Reputation: 33659
I have created a simple hello world using NASM which calls printf
and _exit
from libc but does not use main
.
extern printf
extern _exit
section .data
hello: db 'Hello world!',10
section .text
global _start
_start:
xor eax, eax
mov edi, hello
call printf
mov rax, 0
jmp _exit
I create the object file like this
nasm -felf64 hello.asm
Then I can link it using dynamic linkage with glibc like this
ld hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -melf_x86_64
This runs correctly with no errors. But now I want to do it statically. I do
ln -s `gcc -print-file-name=libc.a`
ln -s `gcc -print-file-name=libgcc_eh.a`
ld hello.o -static libc.a libgcc_eh.a libc.a -melf_x86_64
This links but when I run the code I get a segmentation fault. Using gdb
I see it gives
Program received signal SIGSEGV, Segmentation fault.
0x0000000000401004 in vfprintf ()
If I write a simple hello world in C and compile with static in runs fine so apparently it's possible to link statically to glibc on my system. How can I use static linkage with glibc with my assembly code?
If I link to an alternative to glibc such as musl-libc it works fine
ld hello.o -static /usr/local/musl/lib/libc.a -melf_x86_64
I'm using Ubuntu 14.04, eglibc 2.19, and GCC 4.9.1
Upvotes: 4
Views: 1362
Reputation: 6989
Glibc have a huge initialization sequence, because it is done with strong intention to work in multithreading systems. Also GLIBC properly handles some GNU extensions like constructor attributes. On startup, it caching a lot inside TLS, including locale information, it initializes synchronization objects and so on.
Exact problem with your vprintf is uninitialized locale access.
When you are linking to it dynamically, all this work is done on loading and everything works.
Statically linked glibc requires __libc_init_first
to be called to initialize all it need. Before this call you need __dl_tls_setup
to properly setup TLS and after this call you will need __libc_csu_init
to properly call all global constructors.
All this stuff is highly version-dependent and practically undocumented. Strictly saying, there is no safe way to link statically to glibc, skipping or modifying its normal _start
sequence.
On the other hand, embedded-oriented libraries like musl or newlib are not so restrictive about initialization and multithreading and locales.
Upvotes: 9