Skip to content

Wrong resolution for R_X86_64_DTPOFF32 w/o the relaxation #882

Description

@marxin

While working on #864, I noticed we emit the wrong output when the aforementioned relaxation is suppressed:

diff --git a/libwild/src/x86_64.rs b/libwild/src/x86_64.rs
index 349b8959..55ccf7e8 100644
--- a/libwild/src/x86_64.rs
+++ b/libwild/src/x86_64.rs
@@ -287,12 +287,14 @@ impl crate::arch::Relaxation for Relaxation {
                 if section_bytes.get(offset - 3..offset)? == [0x48, 0x8d, 0x3d] {
                     match section_bytes.get(offset + 4..offset + 6) {
                         // PC-relative direct call
+                        /*
                         Some(&[0xe8, _]) => {
                             return create(
                                 RelaxationKind::TlsLdToLocalExec,
                                 object::elf::R_X86_64_NONE,
                             );
                         }
+                        */
                         // TODO: Make a test for this. Also, the description of TlsLdToLocalExec64
                         // possibly doesn't match what we're actually checking here.
                         Some(&[0x48, 0xb8]) => {
❯ cat t.c
_Thread_local long foo = 42;
int main() {
	__builtin_printf("%ld\n", foo);
	return 0;
}
❯ gcc t.c -ftls-model=local-dynamic -fPIC -B ~/Programming/wild --save-temps && ./a.out 
WARNING: wild: --plugin /usr/lib64/gcc/x86_64-suse-linux/14/liblto_plugin.so is not yet supported
0
❯ objdump -dr a-t.o

a-t.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:	55                   	push   %rbp
   1:	48 89 e5             	mov    %rsp,%rbp
   4:	48 8d 3d 00 00 00 00 	lea    0x0(%rip),%rdi        # b <main+0xb>
			7: R_X86_64_TLSLD	foo-0x4
   b:	e8 00 00 00 00       	call   10 <main+0x10>
			c: R_X86_64_PLT32	__tls_get_addr-0x4
  10:	48 05 00 00 00 00    	add    $0x0,%rax
			12: R_X86_64_DTPOFF32	foo
  16:	48 8b 00             	mov    (%rax),%rax
  19:	48 89 c6             	mov    %rax,%rsi
...

Seems to me we emit a negative offset (as on x86_64 the $tp points to the end of TLS segment), for the TLS variable ($0xfffffffffffffff8):

0000000000402120 <main>:
  402120:	55                   	push   %rbp
  402121:	48 89 e5             	mov    %rsp,%rbp
  402124:	48 8d 3d 75 12 00 00 	lea    0x1275(%rip),%rdi        # 4033a0 <_GLOBAL_OFFSET_TABLE_>
  40212b:	e8 e0 fe ff ff       	call   402010 <__tls_get_addr@plt>
  402130:	48 05 f8 ff ff ff    	add    $0xfffffffffffffff8,%rax
  402136:	48 8b 00             	mov    (%rax),%rax

Which is the situation we special case here:
https://github.com/davidlattimore/wild/blob/d392e9d87ffc74536b11133aed501f1a60268d3b/libwild/src/elf_writer.rs#L2020-L2027

If I change the logic (relative to layout.tls_start_address()), then it works:

0000000000402120 <main>:
  402120:	55                   	push   %rbp
  402121:	48 89 e5             	mov    %rsp,%rbp
  402124:	48 8d 3d 75 12 00 00 	lea    0x1275(%rip),%rdi        # 4033a0 <_GLOBAL_OFFSET_TABLE_>
  40212b:	e8 e0 fe ff ff       	call   402010 <__tls_get_addr@plt>
  402130:	48 05 00 00 00 00    	add    $0x0,%rax
...
❯ ./a.out 
42

Metadata

Metadata

Labels

No labels
No labels

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions