Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The executable file produced in the libso listing of chapter 5 does not work. #12

Closed
yeah-boi opened this issue Jul 29, 2017 · 4 comments

Comments

@yeah-boi
Copy link
Contributor

The executable file produced in the libso listing of chapter 5 does not work. The problem is reproduced below:

$ nasm -f elf64 -o main.o main.asm
$ nasm -f elf64 -o libso.o libso.asm
$ ld -shared -o libso.so libso.o --dynamic-linker=/lib64/ld-linux-x86-64.so.2
$ ld -o main main.o -d libso.so

Executing main does not work:

$ LD_LIBRARY_PATH=. ./main
bash: ./main: No such file or directory

The problem seems to be with the last command. If we change it to using gcc instead of ld, the execution works:

gcc -nostdlib -o main main.o libso.so

$ LD_LIBRARY_PATH=. ./main
Shared object 

It should be possible to fix this without using gcc instead of ld, but I don't know how.

@sayon
Copy link
Collaborator

sayon commented Jul 29, 2017

Thank you for this issue! This is indeed an error.

The right sequence should be:

$ nasm -f elf64 -o main.o main.asm
$ nasm -f elf64 -o libso.o libso.asm
$ ld -shared -o libso.so libso.o 
$ ld -o main main.o -d libso.so --dynamic-linker=/lib64/ld-linux-x86-64.so.2

The --dynamic-linker should be provided on the final stage when the executable file is produced, not when creating the shared library itself.

If you compare readelf output on the object file you've created with the new one you will see a difference:

$ # Without dynamic linker
$ ld -o main main.o -d libso.so                                                                                                                                                $ ./main                                                                                                                                                                       bash: no such file or directory: ./main
$ readelf -l main                                                                                                                                                             
Elf file type is EXEC (Executable file)
Entry point 0x400270
There are 5 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000000118 0x0000000000000118  R E    8
  INTERP         0x0000000000000158 0x0000000000400158 0x0000000000400158
                 0x000000000000000f 0x000000000000000f  R      1
      [Requesting program interpreter: /lib/ld64.so.1]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000288 0x0000000000000288  R E    200000
  LOAD           0x0000000000000288 0x0000000000600288 0x0000000000600288
                 0x0000000000000130 0x0000000000000130  RW     200000
  DYNAMIC        0x0000000000000288 0x0000000000600288 0x0000000000600288
                 0x0000000000000110 0x0000000000000110  RW     8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .hash .dynsym .dynstr .rela.plt .plt .text 
   03     .dynamic .got.plt 
   04     .dynamic 


$ # Now with dynamic linker
$ ld -o main main.o -d libso.so --dynamic-linker=/lib64/ld-linux-x86-64.so.2                                                                                                   
$ ./main                                                                                                                                                                       
Shared object                                                                                                                                                                                                     
$ readelf -l main                                                                                                                                                              sayon@antheus

Elf file type is EXEC (Executable file)
Entry point 0x400280
There are 5 program headers, starting at offset 64

Program Headers:
  Type           Offset             VirtAddr           PhysAddr
                 FileSiz            MemSiz              Flags  Align
  PHDR           0x0000000000000040 0x0000000000400040 0x0000000000400040
                 0x0000000000000118 0x0000000000000118  R E    8
  INTERP         0x0000000000000158 0x0000000000400158 0x0000000000400158
                 0x000000000000001c 0x000000000000001c  R      1
      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]
  LOAD           0x0000000000000000 0x0000000000400000 0x0000000000400000
                 0x0000000000000298 0x0000000000000298  R E    200000
  LOAD           0x0000000000000298 0x0000000000600298 0x0000000000600298
                 0x0000000000000130 0x0000000000000130  RW     200000
  DYNAMIC        0x0000000000000298 0x0000000000600298 0x0000000000600298
                 0x0000000000000110 0x0000000000000110  RW     8

 Section to Segment mapping:
  Segment Sections...
   00     
   01     .interp 
   02     .interp .hash .dynsym .dynstr .rela.plt .plt .text 
   03     .dynamic .got.plt 
   04     .dynamic 

Without -dynamic-linker you are going to silently get a "default" dynamic loader, whose path is hardcoded in ld:

      [Requesting program interpreter: /lib/ld64.so.1]

Most of us do not have a dynamic loader stored with such a name in /lib. That is why the explicit -dynamic-linker option is mandatory in order to obtain a working executable. It changes the relevant field in the resulting ELF program header so that it stores a correct path to the dynamic loader:

      [Requesting program interpreter: /lib64/ld-linux-x86-64.so.2]

GCC resolves the loader path for you before calling linker internally.

You will read more on that in Chapter 15 which is entirely dedicated to writing dynamic libraries in C and assembly.

Again thank you and I am going to correct that in my next commit.

@sayon
Copy link
Collaborator

sayon commented Jul 29, 2017

Fixed in #13

@yeah-boi
Copy link
Contributor Author

Thanks for the solusion and explanation.

The same correction needs to be done for the make files also. I'll create a pull request for that.

@yeah-boi
Copy link
Contributor Author

Makefiles fixed in pull request #14.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants