ld의 동작

ubuntu hardy나 몇몇 배포판 환경에서 간단한 test.c 를 만들어서 다음과 같이 컴파일을 하면 잘 됩니다.

gcc test.c -o test

gcc가 알아서 컴파일과 링킹을 해 주고, default library와 crt 코드를 링크 해 주죠. 그런데 다음과 같이 gcc와 하면 안되더군요.

gcc -c test.c -o test.o
ld -o test test.o

내 기억으로는 예전에는 이게 잘 동작 했었고 링커가 다른 옵션이 없으면 시스템의 default library를 알아서 링크 해 줬던 것 같은데 제대로 안되는군요.

결국 다음과 같이 해 줍니다.

gcc -c test.c -o test.o
ld -o test /usr/lib/crt1.o /usr/lib/crti.o test.o /usr/lib/crtn.o -lc

수동으로 crt 코드와 libc를 링크시켜 줍니다. 여기까지 해서 동작을 잘 해야 하는데, 컴파일/링킹 워닝이나 에러가 안나지만 프로그램이 동작하지 않습니다.

$ readelf -l test
...
INTERP 0x000114 0x08048114 0x08048114 0x00013 0x00013 R 0x1
[Requesting program interpreter: /usr/lib/libc.so.1]
...

dynamic linker를 시스템 기본값인 /usr/lib/libc.so.1로 지정하는데, 문제는 시스템에는 해당 파일이 없습니다--; 마찬가지 방법으로 /bin/ls의 INTERP 섹션을 읽어보니까 INTERP는 /lib/ld-linux.so.2로 되어 있네요. 위에서 /usr/lib/libc.so.1 은 없고 /usr/lib/libc.so는 있는데, 이 파일의 내용은 다음과 같습니다.

$ cat /usr/lib/libc.so
/* GNU ld script
Use the shared library, but some functions are only in
the static library, so try that secondarily. */
OUTPUT_FORMAT(elf32-i386)
GROUP ( /lib/libc.so.6 /usr/lib/libc_nonshared.a AS_NEEDED ( /lib/ld-linux.so.2 ) )

즉, 아마도 시스템 기본값은 /usr/lib/libc.so.1이 아니라 /usr/lib/libc.so가 되어야 하는데 무언가 잘못되어 있었네요. 아니면 저 파일의 내용대로 직접 /lib/ld-linux.so.2를 지정해도 됩니다. 이 파일은 링크의 특성상 libc.so.1을 libc.so로 링크해서 사용하면 안됩니다.

결국 문제를 해결하기 위해 링크는 다음과 같이 되어야 합니다.

gcc -c test.c -o test.o
ld -o test /usr/lib/crt1.o /usr/lib/crti.o test.o /usr/lib/crtn.o -lc --dynamic-linker /lib/ld-linux.so.2



분명히 예전에는 시스템이 알아서 해줬던 것 같은데 무언가 이상하군요. ubuntu hardy랑 debian etch 두 곳에서 테스트 했는데 동작은 같습니다. debian에서는 존재하지 않는 /usr/lib/ld.so.1에 대해서 링크하려고 하는군요. 그리고.. 이상한 것 중 하나는 libc.so는 이름으로 봐서 libc의 shared library 이름이지 dynamic linker의 이름은 아니죠. dynamic linker는 ld-elf.so라던가.. ld-linux.so라던가 하는 이름을 가지는게 보통입니다.