llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.4k stars 11.73k forks source link

linker script assignment loses relative nature of section #39204

Closed nickdesaulniers closed 5 years ago

nickdesaulniers commented 5 years ago
Bugzilla Link 39857
Resolution FIXED
Resolved on Apr 19, 2019 14:25
Version unspecified
OS Linux
CC @rui314,@smithp35

Extended Description

Not sure the best way to reproduce this, but it was reported in another bug and in a mail thread.

llvm/llvm-project#39157 #c11: "It seems like efistubtext = _text; loses the section relative property of _text."

llvm/llvm-project#39157 #c13: 2.) A symbol assignment to symbol defined in a section description in a linker script can lose the section information.

http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20170116/420898.html: "The real problem is that we are not tracking absoluteness correctly."

http://lists.infradead.org/pipermail/linux-arm-kernel/2018-December/616765.html: (since using an intermediate assignment loses the section relative property when using ld.lld)

nickdesaulniers commented 5 years ago

Thanks all!

llvmbot commented 5 years ago

r358652

nickdesaulniers commented 5 years ago

George has also authored: https://reviews.llvm.org/D55550 to help simplify https://reviews.llvm.org/D55423.

llvmbot commented 5 years ago

I investigated the issue, thoughts are below.

So we have: aliastotext = text; SECTIONS { .text 0x1000 : { __text = . ; *(.text) } }

In this script, we have 2 assignment symbols commands (for 'aliastotext' and for 'text') and the problem is that we set the final value of the second symbol too late and first does not get the correct section value.

I experimented with the GNU linkers and the following script:

aliastotext = aliastotext1; aliastotext1 = aliastotext2; aliastotext2 = text;

gold (2.28) does not support it: (gold does set the section index as expected) Num: Value Size Type Bind Vis Ndx Name 6: 0000000000000000 0 NOTYPE GLOBAL DEFAULT ABS aliastotext 7: 0000000000000000 0 NOTYPE GLOBAL DEFAULT ABS aliastotext1 8: 0000000000001000 0 NOTYPE GLOBAL DEFAULT 1 aliasto__text2

Though BFD do: Num: Value Size Type Bind Vis Ndx Name 16: 0000000000001000 0 NOTYPE GLOBAL DEFAULT 1 aliastotext2 17: 0000000000001000 0 NOTYPE GLOBAL DEFAULT 1 aliastotext1 18: 0000000000001000 0 NOTYPE GLOBAL DEFAULT 1 aliasto__text

I think we do not need to support the BFD behavior and it is enough to follow the behavior gold has.

Let see what LLD do now with the linker script symbols of the initial script:

1) First, we declare Defined symbols stubs in declareSymbols https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L246 https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L198

We create stub Defined symbols early because want to make them visible by LTO and to do a symbol versioning.

2) Later during processSectionCommands we call addSymbol: (https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L475) (https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L165)

Just like internal comment says, we do that because want to set symbol values early if we can. This allows us to use symbols as variables in linker scripts. Doing so allows us to write expressions like this:

VAR = 0x1000; ... SECTIONS { ... .bbb : ALIGN(VAR) { *(.bbb) }

So we are able to set 0x1000 value early and set the proper section .bbb alignment in adjustSectionsBeforeSorting: https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L879

3) At the end, we set the final symbol values in the assignSymbol: assignAddresses() (https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L1036) assignOffsets() (https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L764) assignSymbol() (https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L270)

What happens for the sample script above? We do steps 1 and 2 as usual. Since we iterate assignment commands one by one, at the step 2 we assign a nullptr as a section value to aliasto__text (https://github.com/llvm-mirror/lld/blob/master/ELF/LinkerScript.cpp#L176). That happens because we assign aliasto__text before the __text and at the moment of assignment __text does not have a section assigned, what leaves aliasto__text symbol absolute.

Then we are scanning the relocations in scanRelocations<ELFT> and fail with 'cannot refer to absolute symbol' here: https://github.com/llvm-mirror/lld/blob/master/ELF/Relocations.cpp#L408

I experimented with few different approaches and ended up with a next patch finally: https://reviews.llvm.org/D55423

smithp35 commented 5 years ago

To reproduce:

// rtoabs.s .text .globl _start .type _start, %function _start: .globl aliastotext bl text // Ok, text is section relative. bl aliastotext // Should be ok, but isn't. ret

rtoabs.lds

aliastotext = text; SECTIONS { .text 0x1000 : { __text = . ; *(.text) } }

This will link fine without -pie or -shared: bin/ld.lld rtoabs.o -o rtoabs.axf --script=rtoabs.lds

With -pie then we get: ld.lld rtoabs.o -o rtoabs.axf --script=rtoabs.lds --pie ld.lld: error: relocation R_AARCH64_CALL26 cannot refer to absolute symbol: aliasto__text

defined in referenced by rtoabs.o:(.text+0x4)