[置顶] 泰晓 RISC-V 实验箱,配套 30+ 讲嵌入式 Linux 系统开发公开课
如何生成干净可阅读的汇编代码
Wu Zhangjin 创作于 2019/09/04
By Falcon of TinyLab.org Aug 01, 2019
新版 gcc 默认开启了几个选项,导致学习汇编语言,尤其是入门的同学,很难。
以如下代码为例:
$ cat demo.c
#include <stdio.h>
int main(void)
{
int i;
char buffer[64];
i = 1;
buffer[0] = 'a';
return 0;
}
下面这条指令可以生成比较干净简洁的代码:
$ gcc -fno-stack-protector -fomit-frame-pointer -fno-asynchronous-unwind-tables -S demo.c
结果如下:
$ cat demo.s
.file "demo.c"
.text
.globl main
.type main, @function
main:
movl $1, -4(%rsp)
movb $97, -80(%rsp)
movl $0, %eax
ret
.size main, .-main
.ident "GCC: (Ubuntu 8.3.0-16ubuntu3~16.04) 8.3.0"
.section .note.GNU-stack,"",@progbits
加个 -m32
参数就可以生成 32 位的:
$ gcc -fno-stack-protector -fomit-frame-pointer -fno-asynchronous-unwind-tables -m32 -S demo.c
$ cat demo.s
.file "demo.c"
.text
.globl main
.type main, @function
main:
subl $80, %esp
movl $1, 76(%esp)
movb $97, 12(%esp)
movl $0, %eax
addl $80, %esp
ret
.size main, .-main
.ident "GCC: (Ubuntu 8.3.0-16ubuntu3~16.04) 8.3.0"
.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…。现在无论是否用到这些功能,gcc 都加了 .eh_frame,所以不用的时候直接删除掉也无妨。
另外,Stack Protector 不是看上去的那么强大,从原理上看,如果刚好跳过了预设了值的位置去踩的话,Stack Protector 其实是检测不出来的,当然,有总比没有好。
下面这种是可以检测出来的:
$ cat demo.c
#include <stdio.h>
int main(void)
{
char buffer[2];
int i;
i = 1;
buffer[0] = 'a';
buffer[3] = 'b';
printf("hello.world");
return 0;
}
编译和运行,确保可以生成 coredump:
$ gcc -o demo demo.c
$ ulimit -c unlimited
$ ./demo
*** stack smashing detected ***: ./demo terminated
hello.worldAborted (core dumped)
用 gdb 分析 coredump:
$ gdb demo core
[New LWP 89783]
Core was generated by `./demo'.
Program terminated with signal SIGABRT, Aborted.
#0 0x00007f76507fc428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
54 ../sysdeps/unix/sysv/linux/raise.c: No such file or directory.
(gdb) bt
#0 0x00007f76507fc428 in __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:54
#1 0x00007f76507fe02a in __GI_abort () at abort.c:89
#2 0x00007f765083e7ea in __libc_message (do_abort=do_abort@entry=1,
fmt=fmt@entry=0x7f765095649f "*** %s ***: %s terminated\n") at ../sysdeps/posix/libc_fatal.c:175
#3 0x00007f76508e015c in __GI___fortify_fail (msg=<optimized out>, msg@entry=0x7f7650956481 "stack smashing detected")
at fortify_fail.c:37
#4 0x00007f76508e0100 in __stack_chk_fail () at stack_chk_fail.c:28
#5 0x00000000004005c0 in main ()
(gdb)
可以粗略定位到有 Stack Overflow 的函数,但不能定位到具体哪一行踩了数据。
本文的例子汇整在 Linux Lab: examples/c/hello。
猜你喜欢:
- 我要投稿:发表原创技术文章,收获福利、挚友与行业影响力
- 知识星球:独家 Linux 实战经验与技巧,订阅「Linux知识星球」
- 视频频道:泰晓学院,B 站,发布各类 Linux 视频课
- 开源小店:欢迎光临泰晓科技自营店,购物支持泰晓原创
- 技术交流:Linux 用户技术交流微信群,联系微信号:tinylab
支付宝打赏 ¥9.68元 | 微信打赏 ¥9.68元 | |
请作者喝杯咖啡吧 |