-
Notifications
You must be signed in to change notification settings - Fork 78
linkerscript: fix ENTRY() last-wins #1642
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,7 +32,12 @@ void EntryCmd::dump(llvm::raw_ostream &Outs) const { | |
| } | ||
|
|
||
| eld::Expected<void> EntryCmd::activate(Module &CurModule) { | ||
| if ((!EntrySymbol.empty()) && (!(CurModule.getConfig().options().hasEntry()))) | ||
| CurModule.getConfig().options().setEntry(EntrySymbol); | ||
| GeneralOptions &Options = CurModule.getConfig().options(); | ||
| if (!EntrySymbol.empty()) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know it was part of the original code, but do you know if there is any valid case where
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Syntactically we can pass ENTRY("") it will result in EntrySymbol.empty(), lld do gives warning in this case but ld.eld and ld.bfd silently ignores it
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is interesting. We should also give warning for it. Can you please raise an issue for this?
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ENTRY("") is treated as having no ENTRY() at all. |
||
| if (Options.hasEntry() && CurModule.getConfig().showLinkerScriptWarnings()) | ||
| CurModule.getConfig().raise(Diag::warn_multiple_entry); | ||
| if (!Options.isEntryFromCmdLine()) | ||
| Options.setEntry(EntrySymbol); | ||
| } | ||
| return eld::Expected<void>(); | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,50 @@ | ||
| #---EntryCmdPrecedence.test-------------- Executable,LS ----------------------# | ||
| #BEGIN_COMMENT | ||
| # Tests GNU ld entry point precedence rules: | ||
| # Case 1: Last ENTRY() in a single script wins over earlier ENTRY() commands. | ||
| # Case 2: Command-line -e always overrides any script ENTRY(). | ||
| # Case 3: Last -e on command line wins over earlier -e. | ||
| # Case 4: -e with a raw address overrides script ENTRY(). | ||
| # Case 5: Across multiple -T scripts, the last ENTRY() activated wins. | ||
| # Case 6: -e overrides script ENTRY() regardless of command-line order | ||
| # (i.e. -e placed before -T still wins). | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please document this as well. |
||
| # | ||
| # Input scripts fix symbol addresses so entry points can be verified with | ||
| # literal address checks (same style as EntryCmd.test): | ||
| # two_entries.t : bar=0x1000, foo=0x2000 | ||
| # script.t : foo=0x1000, bar=0x2000 | ||
| # entry_foo.t : bar=0x1000, foo=0x2000 (SECTIONS; entry_bar.t is ENTRY only) | ||
| #END_COMMENT | ||
| #START_TEST | ||
| RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -ffunction-sections | ||
|
|
||
| # Case 1: ENTRY(bar) then ENTRY(foo) in one script -- foo must win (last wins). | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/two_entries.t -o %t.lastwins.out | ||
| RUN: %readelf -h %t.lastwins.out | %filecheck %s --check-prefix=LASTWINS | ||
| #LASTWINS: Entry point address: 0x2000 | ||
|
|
||
| # Case 2: -e bar overrides the script ENTRY(foo) -- command line always wins. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/two_entries.t -e bar -o %t.cmdline.out | ||
| RUN: %readelf -h %t.cmdline.out | %filecheck %s --check-prefix=CMDLINE | ||
| #CMDLINE: Entry point address: 0x1000 | ||
|
|
||
| # Case 3: -e foo -e bar -- bar must win (last -e wins). | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/script.t -e foo -e bar -o %t.lastcmd.out | ||
| RUN: %readelf -h %t.lastcmd.out | %filecheck %s --check-prefix=LASTCMD | ||
| #LASTCMD: Entry point address: 0x2000 | ||
|
|
||
| # Case 4: -e 0 overrides script ENTRY(foo) -- entry must be 0x0. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/script.t -e 0 -o %t.rawaddr.out | ||
| RUN: %readelf -h %t.rawaddr.out | %filecheck %s --check-prefix=RAWADDR | ||
| #RAWADDR: Entry point address: 0x0 | ||
|
|
||
| # Case 5: Two separate scripts, ENTRY(bar) then ENTRY(foo) -- last script wins. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/entry_bar.t -T %p/Inputs/entry_foo.t -o %t.crossscript.out | ||
| RUN: %readelf -h %t.crossscript.out | %filecheck %s --check-prefix=CROSSSCRIPT | ||
| #CROSSSCRIPT: Entry point address: 0x2000 | ||
|
|
||
| # Case 6: -e bar placed BEFORE -T -- command line still wins over script ENTRY(foo). | ||
| RUN: %link %linkopts %t1.o -e bar -T %p/Inputs/two_entries.t -o %t.eorder.out | ||
| RUN: %readelf -h %t.eorder.out | %filecheck %s --check-prefix=EORDER | ||
| #EORDER: Entry point address: 0x1000 | ||
| #END_TEST | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,53 @@ | ||
| #---EntryCmdWarn.test-------------------- Executable,LS ----------------------# | ||
| #BEGIN_COMMENT | ||
| # Tests that -Wlinker-script emits a warning when multiple entry points are | ||
| # specified, and that the warning is suppressed without -Wlinker-script. | ||
| # | ||
| # Warning cases: | ||
| # Case 1: Two ENTRY() in one script -- warns once with -Wlinker-script. | ||
| # Case 2: -e combined with a single script ENTRY() -- warns with -Wlinker-script. | ||
| # Case 3: Multiple -e on command line -- warns once with -Wlinker-script. | ||
| # Case 4: Cross-script two ENTRY() -- warns with -Wlinker-script. | ||
| # Case 5: Single ENTRY(), no -e -- no warning even with -Wlinker-script. | ||
| # Case 6: Two ENTRY() without -Wlinker-script -- no warning. | ||
| # Case 7: Three ENTRY() in one script -- warns once per overriding ENTRY(). | ||
| #END_COMMENT | ||
| #START_TEST | ||
| RUN: %clang %clangopts -c %p/Inputs/1.c -o %t1.o -ffunction-sections | ||
|
|
||
| # Case 1: Two ENTRY() in one script -- exactly one warning. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/two_entries.t -Wlinker-script -o %t.warn1.out 2>&1 | \ | ||
| RUN: %filecheck %s --check-prefix=WARN1 | ||
| #WARN1-COUNT-1: Warning: multiple entry points specified; the last one takes effect | ||
| #WARN1-NOT: Warning: multiple entry points specified; the last one takes effect | ||
|
|
||
| # Case 2: -e combined with a single script ENTRY() -- warn. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/script.t -e bar -Wlinker-script -o %t.warn2.out 2>&1 | \ | ||
| RUN: %filecheck %s --check-prefix=WARN | ||
| #WARN: Warning: multiple entry points specified; the last one takes effect | ||
|
|
||
| # Case 3: Multiple -e on command line -- exactly one warning. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/script.t -e foo -e bar -Wlinker-script -o %t.warn3.out 2>&1 | \ | ||
| RUN: %filecheck %s --check-prefix=WARN3 | ||
| #WARN3-COUNT-1: Warning: multiple entry points specified; the last one takes effect | ||
| #WARN3-NOT: Warning: multiple entry points specified; the last one takes effect | ||
|
|
||
| # Case 4: Two ENTRY() across two scripts -- warn. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/entry_bar.t -T %p/Inputs/entry_foo.t -Wlinker-script -o %t.warn4.out 2>&1 | \ | ||
| RUN: %filecheck %s --check-prefix=WARN | ||
|
|
||
| # Case 5: Single ENTRY(), no -e -- no warning even with -Wlinker-script. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/script.t -Wlinker-script -o %t.nowarn1.out 2>&1 | \ | ||
| RUN: %filecheck %s --allow-empty --check-prefix=NOWARN | ||
| #NOWARN-NOT: multiple entry points | ||
|
|
||
| # Case 6: Two ENTRY() without -Wlinker-script -- no warning. | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/two_entries.t -o %t.nowarn2.out 2>&1 | \ | ||
| RUN: %filecheck %s --allow-empty --check-prefix=NOWARN | ||
|
|
||
| # Case 7: Three ENTRY() in one script -- one warning per overriding ENTRY() (two total). | ||
| RUN: %link %linkopts %t1.o -T %p/Inputs/three_entries.t -Wlinker-script -o %t.warn7.out 2>&1 | \ | ||
| RUN: %filecheck %s --check-prefix=WARN7 | ||
| #WARN7-COUNT-2: Warning: multiple entry points specified; the last one takes effect | ||
| #WARN7-NOT: Warning: multiple entry points specified; the last one takes effect | ||
| #END_TEST |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| ENTRY(bar) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| ENTRY(foo) | ||
| SECTIONS { | ||
| . = 0x1000; | ||
| .bar : { *(.text.bar) } | ||
| . = 0x2000; | ||
| .foo : { *(.text.foo) } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,4 +2,6 @@ ENTRY(foo) | |
| SECTIONS { | ||
| . = 0x1000; | ||
| .foo : { *(.text.foo) } | ||
| . = 0x2000; | ||
| .bar : { *(.text.bar) } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| ENTRY(bar) | ||
| ENTRY(foo) | ||
| ENTRY(bar) | ||
| SECTIONS { | ||
| . = 0x1000; | ||
| .bar : { *(.text.bar) } | ||
| . = 0x2000; | ||
| .foo : { *(.text.foo) } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| ENTRY(bar) | ||
| ENTRY(foo) | ||
| SECTIONS { | ||
| . = 0x1000; | ||
| .bar : { *(.text.bar) } | ||
| . = 0x2000; | ||
| .foo : { *(.text.foo) } | ||
| } |
Uh oh!
There was an error while loading. Please reload this page.