nm와 c++filt 활용.

cinsk의 이미지

프로그램 빌드/디버깅 과정에서 쓸모있는 툴 중 nm(1)이 있습니다. nm(1)은 간단히 오브젝트 파일에 들어있는 심볼들을 보여줍니다. 예를 들어 다음과 같은 C 코드(파일 이름 "nm-data.c")를 생각해 봅시다:

static int global_static = 1234;
const int global_const = 5432;
int global;
 
void global_function()
{
  static int local_static = 2;
  int local;
}
 
static void static_function()
{
  extern int extern_int;
  void extern_function(void);
 
  extern_function();
  extern_int = 0;
}

자세히 볼 것도 없이, 아무런 의미가 없는 코드입니다. 위 코드를 "cc -c nm-data.c"로 컴파일해서 nm으로 그 내용을 보면 다음과 같습니다:

cinsk:~$ nm nm-data.o
         U extern_function
         U extern_int
00000004 C global
00000000 R global_const
00000000 T global_function
00000000 d global_static
00000004 d local_static.0
00000008 t static_function
cinsk:~$ _

nm의 출력은 크게 3개의 열로 되어 있습니다. 첫번째 열은 심볼 값을, 두번째 열은 심볼 타입을, 세번째 열은 심볼 이름을 나타냅니다. 심볼 값은 생략 가능하고, 보통 table offset 값이나 virtual address를 나타냅니다. 심볼 타입은 한 글자 알파벳으로 되어 있고, 심볼 이름은 말 그대로 이름을 나타냅니다.

이 글에서는 심볼 타입에 대해서 주로 다룰 것입니다. 먼저 심볼 타입은 A, B, C, D, G, I, N, R, S, T, U, V, W, -, ?가 있으며, 이 중 알파벳은 대소문자가 모두 가능합니다. 사실 다 외워 둘 필요는 없고, 딱 하나만 외워 두면 되는데 그건 바로 'U'입니다. 'U'는 undefined를 뜻하며, 이 오브젝트 파일이 심볼을 참조하고 있지만 정의가 없을 경우에 'U'로 표시합니다.

앞 소스를 보면, 함수 extern_function()을 호출하고 있지만, 이 함수에 대한 정의는 존재하지 않습니다. 또, 전역 변수 extern_int에 0을 대입하고 있지만, 이 변수의 정의도 없습니다. nm은 이러한
심볼들에 대하여 'U' 타입으로 나타냅니다. 'T'는 이 심볼이 text 섹션에 있다는 것, 즉 함수라는 것을 의미하며, 'R'은 read only data section 즉 상수라는 것을 의미하며, 'C'는 common, 초기화되지 않은 데이터라는 것을 나타냅니다. 자세한 것은 man 1 nm 또는 info nm을..

여기까지 알았으면, 경험많은 프로그래머라면 nm이 어떤 경우에 도움을 줄 수 있는지 바로 알 수 있을 것입니다. 바로 이름이 충돌날 때(naming conflict)인데, 예를 들어 다음과 같은 코드(파일 이름: nm-ex.c)를 봅시다:

void f1(void)
{
}
 
int main(void)
{
  fl();
  return 0;
}

정의한 함수는 f1(), 즉 "대문자 에프-숫자 일"입니다. 그리고 호출한 함수는 "대문자 에프-소문자 엘"입니다. 서로 다른 것에 주의 바랍니다. 그러나 이 코드를 작성한 프로그래머는 두 함수 이름이 서로 같다고 착각하고 있다고 가정해 봅시다. 이 경우 컴파일 해 보면, 다음과 같은 에러가 발생합니다:

cinsk:~$ cc nm-ex.c
 
/tmp/ccQQbww3.o: In function `main':
nm-ex.c:(.text+0x16): undefined reference to `fl'
collect2: ld returned 1 exit status
cinsk:~$ _

":shocked: 응? 왜 에러가 나지? 분명 함수 fl()을 정의하고 호출했는데, 왜 fl()이 없다고 하지?"라고 생각할 것입니다. 이 경우 object 파일을 만들고, nm으로 출력해 보면 그 차이를 알 수 있습니다:

cinsk:~$ cc -c nm-ex.c
cinsk:~$ nm nm-ex.o
00000000 T f1
         U fl
00000005 T main
cinsk:~$ _

아하.. :grin: 즉 정의한 함수는 타입이 'T'로 출력된 "f1"이고, 호출한 함수는 정의되지 않은 타입 'U'로 표시된 fl인 것을 알 수 있습니다. 즉 타이핑 실수로 함수 이름을 서로 다르게 만들어 두었기 때문에, 두 심볼로 표시된 것입니다. 만약 올바르게 한 함수 이름으로 코드가 만들어졌다면 'U' 타입 심볼은 만들어지지 않았을 것입니다.

또 다음과 같은 C++ 소스를 봅시다 (파일 이름: nm-ex.cc):

class foo {
public:
  foo();
  ~foo();
 
  void work(void);
  void work(int i);
};
 
foo::foo() {}
foo::~foo() {}
 
void foo::work(void) {}
void foo::work(int i) {}

이것을 컴파일하고 nm으로 출력하면 다음과 같습니다:

cinsk:~$ c++ -c nm-ex.cc
cinsk:~$ nm nm-ex.o
0000001e T _ZN3foo4workEi
00000018 T _ZN3foo4workEv
00000006 T _ZN3fooC1Ev
00000000 T _ZN3fooC2Ev
00000012 T _ZN3fooD1Ev
0000000c T _ZN3fooD2Ev
cinsk:~$ _

C++ name mangling 때문에, 심볼 이름을 알아보기 힘들 것입니다. 이 경우, c++filt(1)라는 툴을 쓰면 쉽게 알아 볼 수 있습니다 :cool: :

cinsk:~$ nm nm-ex.o | c++filt 
0000001e T foo::work(int)
00000018 T foo::work()
00000006 T foo::foo()
00000000 T foo::foo()
00000012 T foo::~foo()
0000000c T foo::~foo()
cinsk:~$ _

nm(1)은 오브젝트 파일 이외에, 실행 파일, 라이브러리 파일에도 모두 동작합니다. 특히 문서나 헤더 파일이 없는 라이브러리가 어떤 함수들을 제공하는 지 훑어볼 때에도 유용합니다.

cinsk:~$ nm libwhat_is_this.a

또, nm은 이러한 목적 이외에도, 나중에 다뤄 볼 objcopy와 함께 object 파일을 직접 조작할 때 자주 쓰입니다. (파일을 처리할 때 ls 명령이 얼마나 자주 쓰이는지 생각해 보면, object 파일을 처리할 때 nm이 얼마나 자주 쓰이는지 쉽게 유추할 수 있습니다.)

Forums: 
kukhyun의 이미지

c++filt 라는것이 있었군요!
만드신 분은 결벽증이 있으신게 아닐까 생각해봅니다.
좋은 글 감사합니다.

pynoos의 이미지

아시겠지만 쓰시지 않은것 같애서
gnu의 binutil에 있는 nm은 -C 옵션을 주면 c++filt한 효과를 보입니다. ;)

lovian의 이미지

제가 유닉스 계열 프로그래밍을 시작한지 오래되지 않아, 난감한 부분이 많았는데,
덕분에 좋은거 하나 배워갑니다.

:)

------------------
한글을 사랑합니다.

-----------------
한글을 사랑합니다.

gonEH의 이미지

감사합니다 :)

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.