상세 컨텐츠

본문 제목

리눅스에서 사용하는 바이너리 유틸리티

Linux

by chbae 2023. 4. 18. 18:57

본문

728x90
반응형

바이너리 유틸리티는 바이너리를 조작하거나 정보를 위한 프로그램들의 모임을 말하고 이런 유틸리티 들에 대해 소개를 하고자 한다. 이 글 또한, 유닉스 리눅스 프로그래밍 필수 유틸리티 책 7장에 나온 내용을 정리한 것이다.

 

  • addr2line: 바이너리 파일에서 특정 주소가 어떤 파일의 어떤 라인인지 보여줌
  • c++filt: C++/Java 심볼 문자열을 맹글링 되기 전 문자열로 보여줌 gprof: 프로파일 정보 출력
  • nm: ELF 포맷 오브젝트 파일의 심볼을 보여줌
  • objcopy: 오브젝트 파일의 복사 / 변환
  • objdump: 오브젝트 파일을 업프하거나 역어셈할 때 사용
  • ranlib: 정적 라이브러리 내에 인덱스를 생성할 때 사용
  • readelf: ELF 포맷의 오브젝트 파일 정보를 보여줌
  • size: 오브젝트 파일의 사이즈 정보 출력
  • strings: 바이너리에서 출력 가능한 문자열 출력
  • strip: 오브젝트 파일 사이즈 줄임

1. addrline 명령으로 특정 주소가 어떤 파일의 어떤 라인인지 알아보기

실제 메모리에 like 파일이 로딩 되었을 때 0x848384 번지가 어떤 소스 파일의 어떤 라인 부분인지 알아보고자 할 때 사용한다.

$ addrline -fe like 0x848384
main
/home/changhyeok.bae/work/like.c:3

2. c++filt 명령으로 맹글링 되기 전의 C++ / Java 심볼명 보기

맹글링(mangling)은 C++이나 Java와 같은 객체지향 언어에서 함수명을 클래스명과 인자 타입으로 변경하는 것을 말한다.

 

ex) Config::OptionCheck(char*) -> _ZN6Config11OptionCheckEPc

 

위와 같이 하는 이유는 함수 오버라이드나 가상 함수를 사용하기 위함이다.

 $ c++filt _ZN6Config11OptionCheckEPc  
 Config::OptionCheck(char*)

3. gprof로 프로파일 정보 알아보기

컴파일러 옵션에서 -pg 옵션을 넣고 빌드 후 gprof를 사용할 수 있는 방법이 있다.

 

프로파일 정보란 바이너라가 수행될 때 생성되는 정보로, 어떤 함수가 몇번 호출되었고, 수행시간은 어느정도 걸렸는지와 같은 정보를 의미한다. 우선 사용하기 위해 위에서 말한 것 처럼 -pg 옵션을 주고 컴파일일 다시 해야한다. 이렇게 하면 실행 파일이 수행 종료가 될 때 gmon.out 파일이 생성되고 gprof는 이 파일을 이용해 프로파일 정보를 출력한다.

 

참고로 실행 명령은 아래와 같다. -b 옵션을 주기 않으면 아래 결과의 각 필드가 무엇을 의미하는지 자세한 설명도 같이 출력된다.

 $ gprof -b ./like > like.profile

4. nm으로 ELF 포맷의 심볼 테이블 보기

바이너리 심볼을 볼 때 nm 명령을 많이 사용하기도 한다.

 

5. objcopy 사용하기

오브젝트 파일을 다른 오브젝트 파일로 복사할 때 사용한다. 선택적으로 필요한 부분만 복사할 수 있기 때문에 파일의 사이즈를 줄이는 데 주로 사용하고 바이너리 포맷을 바꾸는데도 사용한다.

 

가장 간단한 카피 명령이다.

 $ objcopy like like.new

 

Instruction과 data만 뽑아 like.new 파일을 만든다. ELF header가 안붙는 순수 바이너리 그 자체이다. 주로 bootloader를 만들 때 많이 사용한다. ELF header 정보는 OS에서 필요한 정보이지 CPU 명령인 instruction이 아니다.

 $ objcopy -O like like.new

 

-R 옵션과 -S 옵션은 많이 사용하고, 그 외의 추가적인 옵션에 대해 알고 싶으면 man page를 이용하면 된다.

6. objdump 사용하기

바이너리 정보를 보여주는 명령어이다. 오브젝트 파일의 어셈블리 코드를 볼 때도 유용하고 주로 바이너라 파일의 instruction 어셈블리 코드를 볼 때 사용한다. 역어셈블해서 결과를 보여준다. C코드와 함께 보기 위해서는 바이너리 컴파일시 -g 옵션을 주고 디버깅 정보를 삽입해야한다.

 

 $ objdump -d like

 

이외에도 -S, -a, -x, -t, -T, -r, -R ,-s 옵션이 많이 사용되므로 이 것은 man page를 참고하길 바란다.

7. readelf 명령으로 ELF 파일의 각종 정보 보기

위의 objdump와 결과 값이 일부 겹치는 부분도 있다. ELF 바이너리 포맷에는 디버깅 정보를 포함하는 DWARF2라는 디버깅 정보 포맷을 보는 옵션이 있고 -g 옵션을 통해 바이너리를 빌드하면 들어가게 된다.

8. 오브젝트 파일의 사이즈 줄이기 (strip)

strip 명령은 바이너리 사이즈를 줄일 때 사용하는 유용한 명령이다. objcopy와도 약간 중복되는 기능이 있지만 strip를 사용하는 것이 더 일반적이다. 최종 배포전에 하는 것으로 아래 example가 있다. -R 옵션으로 .note section과 .comment section을 제거하고 -s 옵션으로 모든 실행에 필요 없는 심볼을 제거한다.

 

$ strip -R .note -R .command -s like

9. gcov로 커버리지 정보 알아보기

gcov는 binutils에 포함된 패키지는 아니지만 gprof와 유사해 비교하기 좋고 일반적으로 코드 커버리지를 파악하는데 많이 사용한다.

 

코드 커버리지는 코드에서 어떤 부분이 얼마만큼 수행되는지를 찾는다. gprof와 비교한다면 gprof는 기본적으로 함수 단위 프로파일렁 정보를 제공하지만, 함수 내 어떤 부분이 시간을 많이 소비하는지 알기는 불가능하다.

 

gcov는 베이직 블록 단위 프로파일링을 수행해 함수 내 부분까지도 수행 내역에 대해 알 수 있다.

 

-fprofile-arcs -ftest-coverage 옵션은 소스 내 베이직 블록에 프로파일링 코드를 삽입하라는 명령이다. 이후 프로그램을 실행시키면 test.gcda, test.gcno 파일이 생성되고 gcov test.c 명령을 내리면 test.c.gcov 파일이 생성되어 분석을 하면 된다.

 

 $ gcc -o test test.c -fprofile-arcs -ftest-coverage -g
728x90

관련글 더보기