ghc linker problem with __thread int errno

Goetz Isenmann g.isenmann at science-computing.de
Mon Feb 20 04:21:04 PST 2012


Hi!

Since there seems to be some interest in ghc/haskell on #dragonflybsd,
I would like to write down, what my (uneducated) guess is about the main
problem porting ghc to dfly.

On dfly we have "__thread int errno", "#define errno (*__error())", and
"static __inline int *__error(void) { return (&errno); }"

I believe, that ghc generates correct code for this thread local (tls)
access (uses the C comiler), but the ghc linker/load (rts/linker.c)
cannot handle the resulting relocation types:
#define R_386_TLS_IE    15      /* Absolute address of GOT for -ve static TLS */
#define R_X86_64_GOTTPOFF 22    /* PC relative offset to IE GOT entry */

To get an idea, what the ghc linker should do, I did this:

$ cat >main.c
#include <errno.h>
int main() {
  return errno;
}
$ gcc -c -O main.c
$ gcc -o main main.o
$ objdump -d main.o

main.o:     file format elf32-i386

Disassembly of section .text:

00000000 <main>:
   0:   8d 4c 24 04             lea    0x4(%esp),%ecx
   4:   83 e4 f0                and    $0xfffffff0,%esp
   7:   ff 71 fc                pushl  0xfffffffc(%ecx)
   a:   55                      push   %ebp
   b:   89 e5                   mov    %esp,%ebp
   d:   51                      push   %ecx
   e:   65 a1 00 00 00 00       mov    %gs:0x0,%eax
  14:   8b 15 00 00 00 00       mov    0x0,%edx
  1a:   8b 04 10                mov    (%eax,%edx,1),%eax
  1d:   59                      pop    %ecx
  1e:   c9                      leave  
  1f:   8d 61 fc                lea    0xfffffffc(%ecx),%esp
  22:   c3                      ret    
$ objdump -d main
...
08048548 <main>:
 8048548:       8d 4c 24 04             lea    0x4(%esp),%ecx
 804854c:       83 e4 f0                and    $0xfffffff0,%esp
 804854f:       ff 71 fc                pushl  0xfffffffc(%ecx)
 8048552:       55                      push   %ebp
 8048553:       89 e5                   mov    %esp,%ebp
 8048555:       51                      push   %ecx
 8048556:       65 a1 00 00 00 00       mov    %gs:0x0,%eax
 804855c:       8b 15 6c 96 04 08       mov    0x804966c,%edx
-----------------------------------------------^^^^^^^^^
 8048562:       8b 04 10                mov    (%eax,%edx,1),%eax
 8048565:       59                      pop    %ecx
 8048566:       c9                      leave  
 8048567:       8d 61 fc                lea    0xfffffffc(%ecx),%esp
 804856a:       c3                      ret    
 804856b:       90                      nop    
...
$ objdump -h main

main:     file format elf32-i386

Sections:
Idx Name          Size      VMA       LMA       File off  Algn
...
 17 .got          00000004  0804966c  0804966c  0000066c  2**2
----------------------------^^^^^^^^^^^^^^^^^^
                  CONTENTS, ALLOC, LOAD, DATA
...

The same on x86_64:

$ objdump -d main.o

main.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <main>:
   0:   48 8b 05 00 00 00 00    mov    0x0(%rip),%rax        # 7 <main+0x7>
   7:   64 48 8b 14 25 00 00    mov    %fs:0x0,%rdx
   e:   00 00 
  10:   8b 04 02                mov    (%rdx,%rax,1),%eax
  13:   c3                      retq   
$ objdump -d main
...
  40060c:       48 8b 05 8d 02 20 00    mov    0x20028d(%rip),%rax        # 6008a0 <_DYNAMIC+0x170>
-----------------------------------------------^^^^^^^^
  400613:       64 48 8b 14 25 00 00    mov    %fs:0x0,%rdx
--^^^^^^
  40061a:       00 00 
  40061c:       8b 04 02                mov    (%rdx,%rax,1),%eax
  40061f:       c3                      retq   
...
$ objdump -h main

main:     file format elf64-x86-64

Sections:
Idx Name          Size      VMA               LMA               File off  Algn
...
 18 .got          00000008  00000000006008a0  00000000006008a0  000008a0  2**3
----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
                  CONTENTS, ALLOC, LOAD, DATA
...
$ python2.6 -c 'print hex(0x6008a0 - 0x20028d)'
0x400613


This gives me the idea, that the ghc linker should insert a pointer to
the .got segment on i386 and insert the 32bit offset to the .got
segment on x86_64.

So the next point on my todo list for ghc is, to recompile ghc without
my errno access wrapper, take the .got value from the resulting binary
and recompile ghc again with the linker inserting this value, check
that the .got value hasn't changed, and see what happens.

If this goes well, the next steps would be to (a) find out, how to
calculate the .got value inside the linker, and (b) think about an
experiment, that could show me what has to be done, when there is more
than one tls variable.

Hmm, maybe I should try also from the opposite side: How important is
this "static __inline" on the __error function?
Are there any situations, where one would notice a performance impact?
-- 
Goetz Isenmann
-- 
Vorstand/Board of Management:
Dr. Bernd Finkbeiner, Michael Heinrichs, 
Dr. Roland Niemeier, Dr. Arno Steitz, Dr. Ingrid Zech
Vorsitzender des Aufsichtsrats/
Chairman of the Supervisory Board:
Philippe Miltin
Sitz/Registered Office: Tuebingen
Registergericht/Registration Court: Stuttgart
Registernummer/Commercial Register No.: HRB 382196





More information about the Users mailing list