如何生成乾淨可閱讀的彙編代碼


如何生成乾淨可閱讀的彙編代碼


新版 gcc 默認開啟了幾個選項,導致學習彙編語言,尤其是對剛入門的同學,感覺很難。

以如下代碼為例:

 1$ cat demo.c
2#include <stdio.h>
3
4int main(void)
5{
6 int i;
7 char buffer[64];
8
9 i = 1;
10 buffer[0] = 'a';
11
12 return 0;
13}
/<stdio.h>

下面這條指令可以生成比較乾淨簡潔的代碼:

1$ gcc -fno-stack-protector -fomit-frame-pointer -fno-asynchronous-unwind-tables -S demo.c

結果如下:

 1$ cat demo.s
2 .file "demo.c"
3 .text
4 .globl main
5 .type main, @function
6main:
7 movl $1, -4(%rsp)
8 movb $97, -80(%rsp)
9 movl $0, %eax
10 ret
11 .size main, .-main
12 .ident "GCC: (Ubuntu 8.3.0-16ubuntu3~16.04) 8.3.0"

13 .section .note.GNU-stack,"",@progbits

加個 -m32 參數就可以生成 32 位的:

 1$ gcc -fno-stack-protector -fomit-frame-pointer -fno-asynchronous-unwind-tables -m32 -S demo.c
2$ cat demo.s
3 .file "demo.c"
4 .text
5 .globl main
6 .type main, @function
7main:
8 subl $80, %esp
9 movl $1, 76(%esp)
10 movb $97, 12(%esp)
11 movl $0, %eax
12 addl $80, %esp
13 ret
14 .size main, .-main
15 .ident "GCC: (Ubuntu 8.3.0-16ubuntu3~16.04) 8.3.0"
16 .section .note.GNU-stack,"",@progbits

稍微做個解釋:

  • -fno-stack-protector:去掉 stack 保護,stack protector 用於檢查 stack 是否被踩
  • -fomit-frame-pointer:不用 fp 寄存器 rbp/ebp,直接用 stack 寄存器 rsp/esp 就好了
  • -fno-asynchronous-unwind-tables:消除 .eh_frame section

.eh_frame 是 DWARF-based unwinding 用來實現 backtrace(),__attribute__((__cleanup__(f))), __buildtin_return_address(n),pthread_cleanup_push 等,具體請參考 “assembly - Why GCC compiled C program needs .eh_frame…”(https://stackoverflow.com/questions/26300819/why-gcc-compiled-c-program-needs-eh-frame-section)。現在無論是否用到這些功能,gcc 都加了 .eh_frame,所以不用的時候直接刪除掉也無妨。

另外,Stack Protector 不是看上去的那麼強大,從原理上看,如果剛好跳過了預設了值的位置去踩的話,Stack Protector 其實是檢測不出來的,當然,有總比沒有好。

下面這種是可以檢測出來的:

 1$ cat demo.c
2#include <stdio.h>
3
4int main(void)
5{
6 char buffer[2];
7 int i;
8
9 i = 1;
10 buffer[0] = 'a';
11
12 buffer[3] = 'b';
13
14 printf("hello.world");
15
16 return 0;
17}
/<stdio.h>

編譯和運行,確保可以生成 coredump:

1$ gcc -o demo demo.c
2$ ulimit -c unlimited
3$ ./demo
4*** stack smashing detected ***: ./demo terminated
5hello.worldAborted (core dumped)

用 gdb 分析 coredump:

 1$ gdb demo core
2[New LWP 89783]
3Core was generated by `./demo'.
4Program terminated with signal SIGABRT, Aborted.
5#0 0x00007f76507fc428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
654 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
7(gdb) bt
8#0 0x00007f76507fc428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
9#1 0x00007f76507fe02a in __GI_abort () at abort.c:89
10#2 0x00007f765083e7ea in __libc_message (do_abort=do_abort@entry=1,
11 fmt=fmt@entry=0x7f765095649f "*** %s ***: %s terminated\\n") at ../sysdeps/posix/libc_fatal.c:175
12#3 0x00007f76508e015c in __GI___fortify_fail (msg=<optimized>, msg@entry=0x7f7650956481 "stack smashing detected")
13 at fortify_fail.c:37
14#4 0x00007f76508e0100 in __stack_chk_fail () at stack_chk_fail.c:28

15#5 0x00000000004005c0 in main ()
16(gdb)
/<optimized>

可以粗略定位到有 Stack Overflow 的函數,但不能定位到具體哪一行踩了數據。

本文的例子彙整在 Linux Lab: examples/c/hello(https://gitee.com/tinylab/linux-lab/tree/master/examples/c/hello)。


分享到:


相關文章: