Libc Linking Issue

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
Post Reply
User avatar
0fb1d8
Member
Member
Posts: 27
Joined: Mon Nov 03, 2014 2:20 pm
Location: Seoul, South Korea
Contact:

Libc Linking Issue

Post by 0fb1d8 »

Hi,
Thanks to [sortie], I successfully built an os-specific toolchain consisting of binutils, gcc, and a few other dependencies. The toolchain works well, except that there is one issue - libc is not linking properly. More specifically, it corrupts the final output binary by creating an extra leading '.init' section in the wrong place, as Dr. Richard M. Stallman stated, without asking (ayy'hskeeng). My operating system, Arcrascent, has the process space in the range 0x80000000 ~ 0xc0000000, however binutils automatically defaults this to 0x08048000. Obviously, because this is out of bounds, my kernel is not happy with the binaries produced by the toolchain. Silencing this warning by my kernel simply results in a page fault. So after a few hours of researching on google & stackoverflow, I found a way to change the entry point of binaries produced by ld. The "-N -exxxx -Ttext=yyyy -Tdata=zzzz" parameters, if provided to ld, sets the entry point to 'xxxx', the .text segment to 'yyyy', and the .data segment to 'zzzz'. I properly offsetted .text and .data (0x1000) to prevent any overlaps between the two segments. So the binary built successfully, but my kernel still complained that the binary's PT_LOAD header 0 was out of bounds. So I decided to look into the ELF executable produced by ld with readelf -a.

btw, these are the commands i ran to compile & link my test program.

Code: Select all

i386-arcrascent-gcc -c -oplz.o plz.c
i386-arcrascent-ld -N -oplz plz.o /home/joonyoung/arcrascent/usr/bin/../lib/gcc/i386-arcrascent/4.9.2/../../../../i386-arcrascent/lib/crt0.o /home/joonyoung/arcrascent/usr/bin/../lib/gcc/i386-arcrascent/4.9.2/crtbegin.o /home/joonyoung/arcrascent/usr/bin/../lib/gcc/i386-arcrascent/4.9.2/crtend.o -L/home/joonyoung/arcrascent/usr/bin/../lib/gcc/i386-arcrascent/4.9.2 -L/home/joonyoung/arcrascent/usr/bin/../lib/gcc -L/home/joonyoung/arcrascent/usr/bin/../lib/gcc/i386-arcrascent/4.9.2/../../../../i386-arcrascent/lib -L/home/joonyoung/arcrascent/usr/lib -lc -lg -lm -lnosys -lgcc -e0x80000000 -Ttext=0x80000000 -Tdata=0x80001000 --check-sections
The massive junk when executing ld is there because when I link using 'gcc', gcc automatically links against the standard libraries and CRT object files automatically, but when I call ld manually, it failed to locate the libraries/object files.
Anyhow, this is the output given by "readelf -a plz".

Code: Select all

ELF Header:
  Magic:   7f 45 4c 46 01 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF32
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Intel 80386
  Version:                           0x1
  Entry point address:               0x80000000
  Start of program headers:          52 (bytes into file)
  Start of section headers:          5452 (bytes into file)
  Flags:                             0x0
  Size of this header:               52 (bytes)
  Size of program headers:           32 (bytes)
  Number of program headers:         2
  Size of section headers:           40 (bytes)
  Number of section headers:         13
  Section header string table index: 12

Section Headers:
  [Nr] Name              Type            Addr     Off    Size   ES Flg Lk Inf Al
  [ 0]                   NULL            00000000 000000 000000 00      0   0  0
  [ 1] .text             PROGBITS        80000000 000080 0002ea 00 WAX  0   0  4
  [ 2] .data             PROGBITS        80001000 001080 000464 00  WA  0   0 32
  [ 3] .init             PROGBITS        08048074 000074 00000a 00  AX  0   0  1
  [ 4] .fini             PROGBITS        800002ea 00036a 000005 00  AX  0   0  1
  [ 5] .rodata           PROGBITS        800002f0 000370 000006 00   A  0   0  4
  [ 6] .eh_frame         PROGBITS        800002f8 000378 000104 00   A  0   0  4
  [ 7] .ctors            PROGBITS        800003fc 00047c 000008 00  WA  0   0  4
  [ 8] .dtors            PROGBITS        80000404 000484 000008 00  WA  0   0  4
  [ 9] .jcr              PROGBITS        8000040c 00048c 000004 00  WA  0   0  4
  [10] .bss              NOBITS          80001464 0014e4 000024 00  WA  0   0  4
  [11] .comment          PROGBITS        00000000 0014e4 000011 01  MS  0   0  1
  [12] .shstrtab         STRTAB          00000000 0014f5 000056 00      0   0  1
Key to Flags:
  W (write), A (alloc), X (execute), M (merge), S (strings)
  I (info), L (link order), G (group), T (TLS), E (exclude), x (unknown)
  O (extra OS processing required) o (OS specific), p (processor specific)

There are no section groups in this file.

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x000074 0x08048074 0x08048074 0x0000a 0x0000a R E 0x1
  LOAD           0x000080 0x80000000 0x80000000 0x01464 0x01488 RWE 0x20

 Section to Segment mapping:
  Segment Sections...
   00     .init 
   01     .text .data .fini .rodata .eh_frame .ctors .dtors .jcr .bss 

There is no dynamic section in this file.

There are no relocations in this file.

The decoding of unwind sections for machine type Intel 80386 is not currently supported.

No version information found in this file.
After reading the output above, I realized that the issue was in the '.init' section -- and that section contained the function '_start()', the program entry point defined in libc's crt0.o. I believe that the command args I provided to ld didn't fully update the address of the program.

Does anybody know how to fix this?

Thanks.
Joonyoung Lee
Student at 한성과학고등학교(Hansung Science High School) & Ambitious OSDever
Arcrascent OS | Source <-- My OSDev Project
“One of my most productive days was throwing away 1000 lines of code.” - Ken Thompson
User avatar
sortie
Member
Member
Posts: 931
Joined: Wed Mar 21, 2012 3:01 pm
Libera.chat IRC: sortie

Re: Libc Linking Issue

Post by sortie »

Read the OS Specific Tutorial more carefully, in particular [edit] ld/emulparams/elf_i386_myos.sh. What you want to change is TEXT_START_ADDR. You definitely can modify binutils so the generated linker scripts put everything in the right places. You should not have to do the kind of hacks you describe here. It's late, I haven't read your post that carefully, but this sort of thing should be the solution.

Why are you referring to Stallman? That's odd and confusing.

.init is an important part of your program and such. You do want it.

Having user-space in the upper half might violate some assumptions in bad software like JIT engines. You might encounter unexpected compatibility issues with such poor software. It's poor software, make no mistake, but you should be aware of that you might need to fight such battles. I got to fight them anyway because my 64-bit mmap actually returns 64-bit mmap addresses and I refuse to have a MAP_32BIT flag. But worth thinking about in the long term.
User avatar
0fb1d8
Member
Member
Posts: 27
Joined: Mon Nov 03, 2014 2:20 pm
Location: Seoul, South Korea
Contact:

Re: Libc Linking Issue

Post by 0fb1d8 »

Thanks you so much, sortie! After adding "TEXT_START_ADDR=0x80000000" and rebuilding binutils, the toolchain now successfully produces a valid ELF binary for Arcrascent! readelf -a plz successfully reads in all the symbols and all the sections are placed in the right place.

Thank you so much again for your support!
Joonyoung Lee
Student at 한성과학고등학교(Hansung Science High School) & Ambitious OSDever
Arcrascent OS | Source <-- My OSDev Project
“One of my most productive days was throwing away 1000 lines of code.” - Ken Thompson
Post Reply