关于C#:为什么在调用strcpy()时在机器代码转储中没有相应的子例程调用?

Why no corresponding subroutine call in machine code dump when calling strcpy()?

我正在研究乔恩·埃里克森(Jon Erickson)的《黑客:剥削的艺术》一书。

在本书的一部分中,他给出了C代码,然后使用gdb遍历了相应的程序集,解释了指令和内存活动。

我正在Mac OS X上工作,所以事情与他在书中介绍的有所不同(他正在使用Linux)。

无论如何,我有这个C程序:

1
2
3
4
5
6
7
8
9
10
11
1 #include <stdio.h>
2 #include <string.h>
3
4 int main()
5 {
6         char str_a[20];
7
8         strcpy(str_a,"Hello, world!\
"
);
9         printf(str_a);
10 }

这是对应的otool对象转储(我刚刚包含main):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
_main:
0000000100000ea0    pushq   %rbp
0000000100000ea1    movq    %rsp,%rbp
0000000100000ea4    subq    $0x30,%rsp
0000000100000ea8    movq    0x00000189(%rip),%rax
0000000100000eaf    movq    (%rax),%rax
0000000100000eb2    movq    %rax,0xf8(%rbp)
0000000100000eb6    leaq    0xd4(%rbp),%rax
0000000100000eba    movq    %rax,%rcx
0000000100000ebd    movq    $0x77202c6f6c6c6548,%rdx
0000000100000ec7    movq    %rdx,(%rcx)
0000000100000eca    movb    $0x00,0x0e(%rcx)
0000000100000ece    movw    $0x0a21,0x0c(%rcx)
0000000100000ed4    movl    $0x646c726f,0x08(%rcx)
0000000100000edb    movq    %rcx,0xe8(%rbp)
0000000100000edf    xorb    %cl,%cl
0000000100000ee1    movq    %rax,%rdi
0000000100000ee4    movb    %cl,%al
0000000100000ee6    callq   0x100000f1e ; symbol stub for: _printf
0000000100000eeb    movl    0xf4(%rbp),%eax
0000000100000eee    movq    0x00000143(%rip),%rcx
0000000100000ef5    movq    (%rcx),%rcx
0000000100000ef8    movq    0xf8(%rbp),%rdx
0000000100000efc    cmpq    %rdx,%rcx
0000000100000eff    movl    %eax,0xd0(%rbp)
0000000100000f02    jne 0x100000f0d
0000000100000f04    movl    0xd0(%rbp),%eax
0000000100000f07    addq    $0x30,%rsp
0000000100000f0b    popq    %rbp
0000000100000f0c    ret
0000000100000f0d    callq   0x100000f12 ; symbol stub for: ___stack_chk_fail

好。您会注意到对printf()的子例程调用:

1
0000000100000ee6    callq   0x100000f1e ; symbol stub for: _printf

但是对strcpy()的调用在哪里?

还有另外两个异常。首先,如果我在gdp中为strcpy()设置了一个断点:

1
break strcpy

该程序将在不停止的情况下进行压缩。似乎strcpy()实际上没有被调用。

其次,当我编译代码时:

1
gcc -g -o char_array2 char_array2.c

我收到警告:

1
2
3
char_array2.c: In function ‘main’:
char_array2.c:9: warning: format not a string literal and no format arguments
char_array2.c:9: warning: format not a string literal and no format arguments

我不确定这是否与缺少的子例程调用有关,但是我认为无论如何我都会将其包含为数据点。

在我看来,似乎编译器已决定不需要strcpy()并优化了代码以使其不使用它。该程序按预期运行,显示" Hello,world!"。到标准输出,但是缺少对strcpy()的调用让我想知道到底发生了什么。

在书中Erickson的示例中,有一个对strcpy()的调用,因此也许他的编译器和我的编译器的工作方式有所不同。我在使用LLVM:

i686-apple-darwin11-llvm-gcc-4.2

任何想法将不胜感激!

在此先感谢您,我希望您觉得这一点很有趣。

汤姆


就在这里:

1
2
3
4
5
0000000100000ebd    movq    $0x77202c6f6c6c6548,%rdx
0000000100000ec7    movq    %rdx,(%rcx)
0000000100000eca    movb    $0x00,0x0e(%rcx)
0000000100000ece    movw    $0x0a21,0x0c(%rcx)
0000000100000ed4    movl    $0x646c726f,0x08(%rcx)