2014-10-14 1 views
3

libm에서 printf_exit을 호출하지만 main을 사용하지 않는 NASM을 사용하여 간단한 hello world를 만들었습니다.main 호출하지 않고 glibc와의 정적 연결

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 

나는 그럼 난이 오류없이 제대로 실행이

ld hello.o -dynamic-linker /lib64/ld-linux-x86-64.so.2 -lc -melf_x86_64 

같은 glibc는 동적 링크를 사용하여 연결할 수 있습니다이

nasm -felf64 hello.asm 

같은 오브젝트 파일을 생성합니다. 하지만 지금은 정적으로하고 싶습니다. do 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 

이 링크는 있지만 코드를 실행할 때 세그먼트 오류가 발생합니다. gdb 사용 나는 C에서 간단한 인사 세계를 작성하고 잘 그래서 분명히 내 시스템의 glibc에 정적으로 연결하는 것이 가능 실행에 정적으로 컴파일 할 경우는

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000401004 in vfprintf() 

을 제공 참조하십시오. 내 어셈블리 코드에 glibc와 정적 연결을 어떻게 사용할 수 있습니까?

나는 그것이 잘 작동 등 musl-libc로 glibc가의 대안에 연결하면 우분투 14.04, eglibc 2.19 및 GCC 4.9.1를 사용하고 있습니다

ld hello.o -static /usr/local/musl/lib/libc.a -melf_x86_64 

답변

6

Glibc의 거대한 초기화가 멀티 스레딩 시스템에서 작업하려는 강한 의도로 이루어지기 때문입니다. 또한 GLIBC는 생성자 속성과 같은 GNU 확장을 적절하게 처리합니다. 시작시, 로케일 정보를 포함하여 TLS 내에서 많이 캐싱되며 동기화 객체를 초기화합니다.

vprintf의 정확한 문제는 초기화되지 않은 로캘 액세스입니다.

동적으로 링크 할 때 모든 작업이 로딩되고 모든 것이 작동합니다.

정적으로 링크 된 glibc는 필요한 모든 초기화를 위해 __libc_init_first을 호출해야합니다. 이 호출을하기 전에 TLS를 올바르게 설정하려면 __dl_tls_setup이 필요하며이 호출 후에 모든 글로벌 생성자를 올바르게 호출하려면 __libc_csu_init이 필요합니다.

이 모든 것들은 버전에 따라 크게 다르며 실질적으로 문서화되지 않았습니다. 엄밀히 말하면, 정상적인 _start 시퀀스를 건너 뛰거나 수정하여 정적으로 glibc에 링크하는 안전한 방법은 없습니다.

한편, musl 또는 newlib와 같은 임베디드 지향 라이브러리는 초기화 및 다중 스레드 및 로케일에 대해 그리 제한적이지 않습니다.

+0

감사합니다. 예상보다 나은 답변입니다. 나는 수건을 던져서 glibc에 정적으로 연결하는 것을 피해야한다고 생각합니다. –

관련 문제