qiangtoucao121 发表于 2011-11-16 17:52

问一个关于编译和链接的问题,谢谢!

本帖最后由 qiangtoucao121 于 2011-11-16 17:54 编辑

这里有一个例子,很简单
#include <stdio.h>

int myadd(int i, int j)
{
   int z = i + j;
   return z;
}

int main()
{
   int i,j;
   i = 1;
   j = 2;
   int m = i + j;
   int n;
   n = myadd(i,j);

   printf("the sum of i + j = %d \n", m);
   printf("the sum of i + j = %d by call myadd.\n", n);
}

我现在执行:
gcc test.c -o test
objdump -d test

观察main函数
00000000004004df <main>:
4004df:       55                      push   %rbp
4004e0:       48 89 e5                mov    %rsp,%rbp
4004e3:       48 83 ec 10             sub    $0x10,%rsp
4004e7:       c7 45 f0 01 00 00 00    movl   $0x1,-0x10(%rbp)
4004ee:       c7 45 f4 02 00 00 00    movl   $0x2,-0xc(%rbp)
4004f5:       8b 45 f4                mov    -0xc(%rbp),%eax
4004f8:       8b 55 f0                mov    -0x10(%rbp),%edx
4004fb:       8d 04 02                lea    (%rdx,%rax,1),%eax
4004fe:       89 45 f8                mov    %eax,-0x8(%rbp)
400501:       8b 55 f4                mov    -0xc(%rbp),%edx
400504:       8b 45 f0                mov    -0x10(%rbp),%eax
400507:       89 d6                   mov    %edx,%esi
400509:       89 c7                   mov    %eax,%edi
40050b:       e8 b4 ff ff ff          callq4004c4 <myadd>
400510:       89 45 fc                mov    %eax,-0x4(%rbp)
400513:       b8 48 06 40 00          mov    $0x400648,%eax
400518:       8b 55 f8                mov    -0x8(%rbp),%edx
40051b:       89 d6                   mov    %edx,%esi
40051d:       48 89 c7                mov    %rax,%rdi
400520:       b8 00 00 00 00          mov    $0x0,%eax
400525:       e8 8e fe ff ff          callq4003b8 <printf@plt>
40052a:       b8 60 06 40 00          mov    $0x400660,%eax
40052f:       8b 55 fc                mov    -0x4(%rbp),%edx
400532:       89 d6                   mov    %edx,%esi
400534:       48 89 c7                mov    %rax,%rdi
400537:       b8 00 00 00 00          mov    $0x0,%eax
40053c:       e8 77 fe ff ff          callq4003b8 <printf@plt>
400541:       c9                      leaveq
400542:       c3                      retq   
400543:       90                      nop
400544:       90                      nop
400545:       90                      nop
400546:       90                      nop
400547:       90                      nop
400548:       90                      nop
400549:       90                      nop
40054a:       90                      nop
40054b:       90                      nop
40054c:       90                      nop
40054d:       90                      nop
40054e:       90                      nop
40054f:       90                      nop

然后,我再执行如下
gcc -c test.c
objdump -d test.o

再观察main函数
000000000000001b <main>:
1b:   55                      push   %rbp
1c:   48 89 e5                mov    %rsp,%rbp
1f:   48 83 ec 10             sub    $0x10,%rsp
23:   c7 45 f0 01 00 00 00    movl   $0x1,-0x10(%rbp)
2a:   c7 45 f4 02 00 00 00    movl   $0x2,-0xc(%rbp)
31:   8b 45 f4                mov    -0xc(%rbp),%eax
34:   8b 55 f0                mov    -0x10(%rbp),%edx
37:   8d 04 02                lea    (%rdx,%rax,1),%eax
3a:   89 45 f8                mov    %eax,-0x8(%rbp)
3d:   8b 55 f4                mov    -0xc(%rbp),%edx
40:   8b 45 f0                mov    -0x10(%rbp),%eax
43:   89 d6                   mov    %edx,%esi
45:   89 c7                   mov    %eax,%edi
47:   e8 00 00 00 00          callq4c <main+0x31>
4c:   89 45 fc                mov    %eax,-0x4(%rbp)
4f:   b8 00 00 00 00          mov    $0x0,%eax
54:   8b 55 f8                mov    -0x8(%rbp),%edx
57:   89 d6                   mov    %edx,%esi
59:   48 89 c7                mov    %rax,%rdi
5c:   b8 00 00 00 00          mov    $0x0,%eax
61:   e8 00 00 00 00          callq66 <main+0x4b>
66:   b8 00 00 00 00          mov    $0x0,%eax
6b:   8b 55 fc                mov    -0x4(%rbp),%edx
6e:   89 d6                   mov    %edx,%esi
70:   48 89 c7                mov    %rax,%rdi
73:   b8 00 00 00 00          mov    $0x0,%eax
78:   e8 00 00 00 00          callq7d <main+0x62>
7d:   c9                      leaveq
7e:   c3                      retq   


如上,主要是红色部分的区别,我的问题是,为什么不链接就无法显示所调用的函数名,而只是主函数名+偏移量,原因是什么?
如果我在反汇编存在的库文件的时候,出现和未链接一样的情况,我用什么办法得到主函数到底调用了哪个函数,请高手指点,万分感谢!

qiangtoucao121 发表于 2011-11-17 09:00

此论坛不给力啊,斑竹大人呢?

sqfasd 发表于 2011-11-17 12:55

第一点,《程序员的自我修养》第四章4.2节静态链接过程中的符号解析与重定位中,有详细的描述。简单点说,就是链接的时候,需要合并各个目标文件中的段,比如最常见的data、text、bss等,所以在链接前,编译器是不知道调用函数在虚拟内存中的实际位置的,编译器只能暂时把这些函数的地址临时当作0。


第二点,LZ你自己也说了,你反编译的只是一个库,要想得知main函数调用了哪些函数,必须得到包含main的那个目标文件,目标文件里应该包含各种符号表,连接器应该就是根据这些符号表确定被调用函数的最终地址的,这也是我猜的,所以没法提供更详细的信息,你可以去参考下连接器是怎么做的,或者自己分析目标文件的格式。

sqfasd 发表于 2011-11-17 12:58

那个符号表应该就叫做重定位表,那本书的第四章看完,就什么都明白了

qiangtoucao121 发表于 2011-11-17 17:47

回复 4# sqfasd


    谢谢这位兄弟,你说的那本书我以前前段时间看过,未链接的文件比如我上面的test.o和我这个库文件,在它的.text区间是可以看见myadd,等符号的,我不需要知道所调用函数的实际地址,我现在只需要知道函数名而已,这个就是我奇怪的地方。
   我把利用那个库文件生成的.ko文件进行了反汇编,还是只有主函数+偏移地址的形式,无法得到相关的函数名,我现在非常希望得到函数名,问题就在这里

sqfasd 发表于 2011-11-18 00:55

本帖最后由 sqfasd 于 2011-11-18 00:58 编辑

回复 5# qiangtoucao121

这个可能要你自己去分析了,因为objdump不会帮你做,可以试试readelf,这个可以帮你分析目标文件中表和段的信息,找出偏移量对应的函数名就可以了


Relocation section '.rel.text' at offset 0x340 contains 2 entries:
Offset   Info    Type            Sym.ValueSym. Name
0000002100000702 R_386_PC32      00000000   add
0000003c00000802 R_386_PC32      0000000b   func

20:   e8 fc ff ff ff          call   21 <func+0x16>
3b:   e8 fc ff ff ff          call   3c <main+0xf>

看,还是有规律的,用grep或awk处理你需要的信息吧。


又试了下,用objdump -r选项也是可以解析出重定位表的

objdump -r test.o

test.o:   file format elf32-i386

RELOCATION RECORDS FOR [.text]:
OFFSET   TYPE            VALUE
00000021 R_386_PC32      add
0000003c R_386_PC32      func

qiangtoucao121 发表于 2011-11-18 08:53

你的回复很有帮助,我再看看,非常感谢!!

qiangtoucao121 发表于 2011-11-18 09:15

你的可以,我的不行 真是奇怪

qiangtoucao121 发表于 2011-11-18 09:19

下面是readelf的结果
Relocation section '.rela.text' at offset 0x670 contains 5 entries:
Offset          Info         Type         Sym. Value    Sym. Name + Addend
000000000048000900000002 R_X86_64_PC32   0000000000000000 myadd - 4
00000000005000050000000a R_X86_64_32       0000000000000000 .rodata + 0
000000000062000b00000002 R_X86_64_PC32   0000000000000000 printf - 4
00000000006700050000000a R_X86_64_32       0000000000000000 .rodata + 18
000000000079000b00000002 R_X86_64_PC32   0000000000000000 printf - 4

下面是objdump的结果
RELOCATION RECORDS FOR [.text]:
OFFSET         TYPE            VALUE
0000000000000048 R_X86_64_PC32   myadd-0x0000000000000004
0000000000000050 R_X86_64_32       .rodata
0000000000000062 R_X86_64_PC32   printf-0x0000000000000004
0000000000000067 R_X86_64_32       .rodata+0x0000000000000018
0000000000000079 R_X86_64_PC32   printf-0x0000000000000004

而objdump面的结果我上面有说明:
47:   e8 00 00 00 00          callq4c <main+0x31>
61:   e8 00 00 00 00          callq66 <main+0x4b>
78:   e8 00 00 00 00          callq7d <main+0x62>

还是可以的 就是相差1,呵呵 再内核模块上面再试一试,看看有没有问题

qiangtoucao121 发表于 2011-11-18 09:33

简单的问题解决了,复杂的问题又来了,不过估计暂时还没有问题解决
000000000001352a R_X86_64_32S      ifio_2b833.601e4c97925221a121e16eedfa1d5840182.2.3.1.123
0000000000013531 R_X86_64_PC32   ifio_2b833.601e4c97925221a121e16eedfa1d5840182.2.3.1.123-0x0000000000000004
0000000000013538 R_X86_64_PC32   ifio_2b833.601e4c97925221a121e16eedfa1d5840182.2.3.1.123+0x0000000000000004
000000000001353d R_X86_64_PC32   ifio_7653c.c920cb5012983c87a18a599e03ac78cdbe9.2.3.1.123-0x0000000000000004

如上所示,有一些函数,为了在链接的时候能够准确定位,对相同的函数名进行了异化处理,这个现在就不想深入分析了,除非对gcc的命名规则非常熟悉,暂时就不深入了,谢谢这位兄弟的提醒,让我这边很省了不少事情
页: [1]
查看完整版本: 问一个关于编译和链接的问题,谢谢!