为什么调用strcpy()时机器代码转储中没有相应的子程序调用?

Tom*_*ace 2 c macos assembly gdb

我正在阅读Jon Erickson撰写的"黑客:剥削艺术"一书.

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

我在Mac OS X中工作,所以事情与他在书中提出的有点不同(他使用的是Linux).

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

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!\n");
9         printf(str_a);
10 }
Run Code Online (Sandbox Code Playgroud)

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

_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
Run Code Online (Sandbox Code Playgroud)

好.你会注意到printf()的子程序调用:

0000000100000ee6    callq   0x100000f1e ; symbol stub for: _printf
Run Code Online (Sandbox Code Playgroud)

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

还有两个异常现象.首先,如果我在gdp中为strcpy()设置断点:

break strcpy
Run Code Online (Sandbox Code Playgroud)

该程序无需停止即可完成执行.似乎strcpy()实际上没有被调用.

第二,当我编译代码时:

gcc -g -o char_array2 char_array2.c
Run Code Online (Sandbox Code Playgroud)

我收到警告:

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
Run Code Online (Sandbox Code Playgroud)

我不确定这是否与丢失的子程序调用有关,但我认为无论如何我都会将其作为数据点包含在内.

在我看来,好像编译器已经决定strcpy()不是必需的,并且已经优化了代码以便在没有它的情况下工作.该程序按预期工作,打印'Hello,world!' 到标准输出,但这个缺少对strcpy()的调用让我想知道究竟发生了什么.

在埃里克森的书中例子还有就是对于strcpy()调用所以可能存在自己怎么编译器和我的编译器正在不同.我在LLVM上:

i686的 - 苹果darwin11-LLVM-GCC-4.2

任何想法都会感激不尽!

在此先感谢,我希望你发现这个有趣.

汤姆

R..*_*R.. 9

就在这里:

0000000100000ebd    movq    $0x77202c6f6c6c6548,%rdx
0000000100000ec7    movq    %rdx,(%rcx)
0000000100000eca    movb    $0x00,0x0e(%rcx)
0000000100000ece    movw    $0x0a21,0x0c(%rcx)
0000000100000ed4    movl    $0x646c726f,0x08(%rcx)
Run Code Online (Sandbox Code Playgroud)

  • 也许为了更好地阐述,**C不是高级汇编程序**.AC编译器的工作是确保编译程序的可观察行为符合语言标准指定的行为.调用函数时,有很多地方没有`call`指令,例如:(1)它在同一个转换单元中定义并且可以内联,(2)它的行为由标准和编译器指定可以直接实现内联行为. (2认同)