我正在按照“剥削艺术”一书中的示例来尝试用C语言编写一个程序,而本书附带了自己的Linux LiveCD,我更喜欢使用BT5(32位)。
代码示例非常简单 - (我已经使用了它)
#include <stdio.h>
int main()
{
int i;
for(i=0; i < 10; i++) // Loop 10 times.
{
puts("Hello, world!\n"); // put the string to the output.
}
return 0; // Tell OS the program exited without errors.
}
作者正在使用
gcc file_name.c
编译代码,我使用几乎相同的语法,但使用-o将编译路径保存到我想要的位置。
然后他使用命令 -
objdump -D loop | grep -A20 main。:
检查已编译的二进制文件。
这是他的输出 -
reader@hacking:~/booksrc $ objdump -D a.out | grep -A20 main.:
08048374 <main>:
8048374: 55 push %ebp
8048375: 89 e5 mov %esp,%ebp
8048377: 83 ec 08 sub $0x8,%esp
804837a: 83 e4 f0 and $0xfffffff0,%esp
804837d: b8 00 00 00 00 mov $0x0,%eax
8048382: 29 c4 sub %eax,%esp
8048384: c7 45 fc 00 00 00 00 movl $0x0,0xfffffffc(%ebp)
804838b: 83 7d fc 09 cmpl $0x9,0xfffffffc(%ebp)
804838f: 7e 02 jle 8048393 <main+0x1f>
8048391: eb 13 jmp 80483a6 <main+0x32>
8048393: c7 04 24 84 84 04 08 movl $0x8048484,(%esp)
804839a: e8 01 ff ff ff call 80482a0 <printf@plt>
804839f: 8d 45 fc lea 0xfffffffc(%ebp),%eax
80483a2: ff 00 incl (%eax)
80483a4: eb e5 jmp 804838b <main+0x17>
80483a6: c9 leave
80483a7: c3 ret
80483a8: 90 nop
80483a9: 90 nop
80483aa: 90 nop
reader@hacking:~/booksrc $
这是我对同一程序的输出 -
root @bt:〜#objdump -D loop | grep -A20 main。:
080483e4 <main>:
80483e4: 55 push %ebp
80483e5: 89 e5 mov %esp,%ebp
80483e7: 83 e4 f0 and $0xfffffff0,%esp
80483ea: 83 ec 20 sub $0x20,%esp
80483ed: c7 44 24 1c 00 00 00 movl $0x0,0x1c(%esp)
80483f4: 00
80483f5: eb 11 jmp 8048408 <main+0x24>
80483f7: c7 04 24 e0 84 04 08 movl $0x80484e0,(%esp)
80483fe: e8 15 ff ff ff call 8048318 <puts@plt>
8048403: 83 44 24 1c 01 addl $0x1,0x1c(%esp)
8048408: 83 7c 24 1c 09 cmpl $0x9,0x1c(%esp)
804840d: 7e e8 jle 80483f7 <main+0x13>
804840f: b8 00 00 00 00 mov $0x0,%eax
8048414: c9 leave
8048415: c3 ret
8048416: 90 nop
8048417: 90 nop
8048418: 90 nop
8048419: 90 nop
804841a: 90 nop
root@bt:~#
您是否认为存在差异,因为我没有使用相同的Linux发行版?看起来他的代码在我调用printf()
函数时调用了puts()
函数(就像他在他的例子中所使用的那样)。
答案 0 :(得分:6)
它不一定是操作系统的差异,如果您使用不同版本的GCC来生成不同的机器代码/汇编代码就足够了。
关于puts
/ printf
- 当您在没有格式的情况下调用printf
时,编译器会使用它所决定的更好(在效率,安全性等方面),不需要它,所以他使用更快的puts
。
答案 1 :(得分:1)
即使您使用相同的编译器(gcc),也不要期望在同一天在不同的机器上编译或在不同的日子在同一台机器上进行编译会产生相同的结果。
gcc的不同版本,32位与64位等等,如果您没有自己安装gcc以完全匹配作者安装的gcc,那么您可能会有不同的版本,期望代码会有所不同。
一旦添加优化和其他命令行选项(与代码生成相关,-o不是其中之一),同一台机器在同一天的差异就会大不相同。
我希望这不是本书的重点,我希望它会教会你这些差异,但是当你碰巧看到它们产生时,如何利用一些东西。基本上与书中提到的内容相符,因为它可能与本书试图教授的内容有关。
底线期望相同的代码永远不会构建相同的,一些编译器甚至在文件中加上时间戳,确保没有两个构建永远不会完全匹配。 gcc特别是不断发展,没有两个人以同样的方式构建它,所以即使使用相同的源版本,你也可以看到输出的差异。
答案 2 :(得分:0)
可能是不同版本的编译器。你们正在优化对printf
的调用 - 因为实际上没有格式字符串,所以调用puts
可能会稍快一点。