Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
661 views
in Technique[技术] by (71.8m points)

gcc - Static linkage with glibc without calling main

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

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...