[lld] question on ELF section formating

I’ve been adding ELF/AArch64 support to lld based off the existing x86_64 code that is already there in lld. I’ve been able to compile and link a simple “Hello World”-type program. However, I’m getting what appears to be a misplacement/name change of the _start atom. When I do the link, the _start section gets named __tls_get_addr. The code inside this section appears to be correct, just the name is wrong. If I output in YAML, it appears to have the correct name.

Since I know this is new code that no one has seen, I was just wondering if anyone might give me a hint as to why this might happen or a good place to start looking. I’m new to the linker and only have been looking into lld for about a week.

The output in YAML for the section in question is:

  • name: _start

scope: global

content: [ 1D, 00, 80, D2, 1E, 00, 80, D2, FD, 03, 00, 91,

E5, 03, 00, AA, E1, 03, 40, F9, E2, 23, 00, 91,

E6, 03, 00, 91, A0, 00, 00, 58, C3, 00, 00, 58,

E4, 00, 00, 58, 00, 00, 00, 94, 00, 00, 00, 94 ]

alignment: 2^3

section-name: .text

references:

  • kind: R_AARCH64_CALL26

offset: 40

target: __plt___libc_start_main

  • kind: R_AARCH64_CALL26

offset: 44

target: __plt_abort

  • kind: in-group

offset: 0

target: L030

  • kind: layout-after

offset: 0

target: ‘$d.010’

The output during objdump of that section is:

00000000004006d0 <__tls_get_addr>:

4006d0: d280001d mov x29, #0x0 // #0

4006d4: d280001e mov x30, #0x0 // #0

4006d8: 910003fd mov x29, sp

4006dc: aa0003e5 mov x5, x0

4006e0: f94003e1 ldr x1, [sp]

4006e4: 910023e2 add x2, sp, #0x8

4006e8: 910003e6 mov x6, sp

4006ec: 580000a0 ldr x0, 400700 <__tls_get_addr+0x30>

4006f0: 580000c3 ldr x3, 400708 <__tls_get_addr+0x38>

4006f4: 580000e4 ldr x4, 400710 <__tls_get_addr+0x40>

4006f8: 97ffffe6 bl 400690 __libc_start_main@plt

4006fc: 97ffffe9 bl 4006a0 abort@plt

400700: 004008a0 .inst 0x004008a0 ; undefined

400704: 00000000 .inst 0x00000000 ; undefined

400708: 00400934 .inst 0x00400934 ; undefined

40070c: 00000000 .inst 0x00000000 ; undefined

400710: 004009ac .inst 0x004009ac ; undefined

400714: 00000000 .inst 0x00000000 ; undefined

Daniel

It could be any of the following issues :-

a) When writing content overlapped ...
b) The way relocations are applied in X86_64 would be different from AARCH64, so could be in the place how relocations are being processed.

Thanks

Shankar Easwaran

Wouldn’t all the relocations already be processed by the time we get to writing a file? Since it appears YAML is correct and the actual executable is not, I thought that the relocations wouldn’t be an issue. But I can go back and check the relocations again.

What do you mean by “writing content overlapped”? Does this refer to a particular process that lld does? I haven’t modified the ELF writing at all (at least I don’t think I have!). I thought that OutputELFWriter.h was doing all (or at least the bulk) of the work. I have an AARch64ExecutbaleWriter.cpp, but it just creates a few got files, it doesn’t actually do any writing that I can tell.

Daniel

So I think I’ve figured out my issue, which maybe isn’t an issue at all. So now I understand that the relocations happen as you’re writing the file (during write() in SectionChunks.h). But I think the issue is not that the section is necessarily wrong, but that both __tls_get_addr and _start are both at the same location. So objdump is simply telling me the first symbol at that address (__tls_get_addr) instead of the _start symbol. It seems like __tls_get_addr should indeed actually be of length 0. So that part of the code I think is actually correct.

I still need to figure out the GOT. The call_weak_fn routine is not properly accessing the Global Offset Table.

Daniel