툴체인 안에 무엇이 들어있는지 알기 위해, crosstool-NG 툴체인을 살펴보자.
홈 디렉토리의 x-tools를 보면 두 가지 디렉토리가 있는 것을 볼 수 있다.
- aarch64-rpi3-linux-gnu : 라즈베리파이용 툴체인 디렉토리
- arm-unknown-linux-gnueabi : QEMU용 ARM926EJ-S 툴체인 디렉토리
[ 툴체인 사용 ]
라즈베리파이 툴체인을 사용해 보자.
$ cd ~/x-tools/aarch64-rpi3-linux-gnu/bin
~/x-tools/aarch64-rpi3-linux-gnu/bin/에 가면 크로스 컴파일러 aarch64-rpi3-linux-gnu-gcc가 있다.
이 컴파일러를 사용하려면 다음 명령으로 해당 디렉토리를 경로에 넣어야 한다.
$ PATH=~/x-tools/aarch64-rpi3-linux-gnu/bin:$PATH
크로스 컴파일
아래와 같이 c파일을 만든다.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
printf("Hello, world!\n");
return 0;
}
아래 명령어로 컴파일할 수 있다.
$ aarch64-rpi3-linux-gnu-gcc helloworld.c -o helloworld
파일 종류 확인
file 명령어로 파일의 종류를 출력해보면 크로스 컴파일된 걸 확인할 수 있다.
[ 툴체인 구성 ]
툴체인이 어떻게 구성됐는지 알고싶으면 gcc에게 물어보면 된다.
Version 확인
$ aarch64-rpi3-linux-gnu-gcc --version
configure 확인
$ aarch64-rpi3-linux-gnu-gcc -v
Using built-in specs.
COLLECT_GCC=aarch64-rpi3-linux-gnu-gcc
COLLECT_LTO_WRAPPER=/home/ubuntu/x-tools/aarch64-rpi3-linux-gnu/libexec/gcc/aarch64-rpi3-linux-gnu/8.3.0/lto-wrapper
Target: aarch64-rpi3-linux-gnu
Configured with: /home/ubuntu/crosstool-ng/.build/aarch64-rpi3-linux-gnu/src/gcc/configure --build=x86_64-build_pc-linux-gnu --host=x86_64-build_pc-linux-gnu --target=aarch64-rpi3-linux-gnu --prefix=/home/ubuntu/x-tools/aarch64-rpi3-linux-gnu --with-sysroot=/home/ubuntu/x-tools/aarch64-rpi3-linux-gnu/aarch64-rpi3-linux-gnu/sysroot --enable-languages=c,c++ --with-cpu=cortex-a53 --with-pkgversion='crosstool-NG 1.24.0' --enable-__cxa_atexit --disable-libmudflap --disable-libgomp --disable-libssp --disable-libquadmath --disable-libquadmath-support --disable-libsanitizer --disable-libmpx --with-gmp=/home/ubuntu/crosstool-ng/.build/aarch64-rpi3-linux-gnu/buildtools --with-mpfr=/home/ubuntu/crosstool-ng/.build/aarch64-rpi3-linux-gnu/buildtools --with-mpc=/home/ubuntu/crosstool-ng/.build/aarch64-rpi3-linux-gnu/buildtools --with-isl=/home/ubuntu/crosstool-ng/.build/aarch64-rpi3-linux-gnu/buildtools --enable-lto --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --enable-threads=posix --enable-target-optspace --enable-plugin --enable-gold --disable-nls --disable-multilib --with-local-prefix=/home/ubuntu/x-tools/aarch64-rpi3-linux-gnu/aarch64-rpi3-linux-gnu/sysroot --enable-long-long
Thread model: posix
gcc version 8.3.0 (crosstool-NG 1.24.0)
- --with-sysroot=/home/ubuntu/x-tools/aarch64-rpi3-linux-gnu/aarch64-rpi3-linux-gnu/sysroot : sysroot 디렉토리이다.
- --enable-languages=c,c++ : 이를 이용해 C와 C++를 활성화한다.
- --with-cpu=cortex-a53 : ARM Coretext A53 코어용 코드를 만든다.
- --enable-threads=posix : POSIX 스레드를 사용한다.
대부분의 설정은 gcc 커맨드라인에서 바꿀 수 있으며 만약, 다른 CPU용으로 컴파일하고 싶다면 --with-cpu로 configure를 바꿀 수 있다.
$ aarch64-rpi3-linux-gnu-gcc -mcpu=cortex-a75 helloworld.c -o helloworld
아키텍처별로 사용 가능한 옵션 확인 (--target-help)
$ aarch64-rpi3-linux-gnu-gcc --target-help
[ sysroot, 라이브러리, 헤더 파일 ]
툴체인 sysroot는 라이브러리, 헤더 파일, 기타 구성 파일용 서브디렉토리들을 담고 있는 디렉토리이다.
툴체인을 구성할 때, --with-sysroot=로 설정하거나 커맨드라인에서 --sysroot=로 설정할 수 있다.
기본 sysroot 위치
$ aarch64-rpi3-linux-gnu-gcc -print-sysroot
sysroot 서브 디렉토리
$ tree -dL 2
- lib : C 라이브러리용 공유 오브젝트 파일들과 동적 링커/로더인 ld-linux
- usr/lib : C 라이브러리용 정적 라이브러리 아카이브와 추후에 설치되는 기타 라이브러리
- usr/include : 모든 라이브러리의 헤더들
- usr/bin : ldd 명령처럼 타깃에서 실행되는 유틸리티 프로그램들
- /usr/share : 지역화와 국제화를 위해 사용
- sbin : 라이브러리 로드 경로를 최적화하는 데 사용되는 ldconfig 유틸리티를 제공
[ 툴체인 안의 기타 도구들 ]
명령 | 설명 |
addr2line | 실행 파일 안의 디버그 심볼을 읽어서 프로그램 주소를 파일 이름과 행 번호로 변환한다. 시스템 크래시 리포트에 출력된 주소를 해독할 때 유용하다. |
ar | 아카이브 유틸리티는 정적 라이브러리를 만들 때 쓰인다. |
as | GNU 어셈블러 |
c++filt | C++와 자바 심볼을 복원할 때 쓰인다. |
cpp | C 전처리기로, #define, #include 등의 지시자를 확장할 때 쓰인다. 단독으로 사용할 필요는 거의 없다. |
elfedit | ELF 파일의 ELF 헤더를 업데이트할 때 쓰인다. |
g++ | GNU C++ 프론트엔드로, 소스 파일이 C++ 코드를 담고 있다고 가정한다. |
gcc | CNU C 프론트엔드로, 소스파일이 C 코드를 담고 있다고 가정한다. |
gcov | 코드 커버리지 도구 |
gdb | GNU 디버거 |
gprof | 프로그램 프로파일링 도구 |
ld | GNU 링커 |
nm | 오브젝트 파일의 심볼을 나열한다. |
objcopy | 오브젝트 파일을 복사하고 번역할 때 쓰인다. |
objdump | 오브젝트 파일의 정보를 출력할 때 쓰인다. |
ranlib | 정적 라이브러리 안의 인덱스를 만들거나 수정해 링크 단계를 더 빠르게 한다. |
readelf | ELF 오브젝트 형식의 파일에 정보를 출력한다. |
size | 섹션 크기와 전체 크기를 나열한다. |
strings | 파일안의 인쇄 가능 문자열들을 출력한다. |
strip | 오브젝트 파일의 디버그 심볼 테이블을 없애 파일 크기를 줄여준다. 흔히 타깃에 복사할 모든 실행 코드에 적용한다. |
[ C 라이브러리 요소 ]
c 라이브러리는 POSIX API를 구현하는 4개의 주요 부분으로 이루어져 있다.
- libc : printf, open, close, read, write등 잘 알려진 POSIX 함수들이 담고 있다.
- libm : cos, exp, log와 같은 수학 함수들이 있다.
- libpthread : 이름이 pthread_로 시작하는 모든 POSIX 스레드 함수들이 있다.
- librt : 공유 메모리와 비동기 I/O를 포함하는 POSIX 실시간 확장
libc는 언제나 링크가 되지만 나머진s -l 옵션으로 명시적으로 링크해야 한다.
$ aarch64-rpi3-linux-gnu-gcc sin.c -o sin -lm
-l은 라이브러리임을 뜻하며 뒤에있는 m은 libm을 의미한다.
readelf
readelf 명령으로 이 프로그램이나 다른 프로그램이 어떤 라이브러리와 링크되었는지 확인할 수 있다.
$ aarch64-rpi3-linux-gnu-readelf -a helloworld | grep "Shared library"
공유 라이브러리는 런타임 링커가 필요하며 다음 명령으로 알 수 있다.
$ aarch64-rpi3-linux-gnu-readelf -a helloworld | grep "program interpreter"