在 CentOS 系统上,“查看汇编代码”通常有几种不同的场景和需求。下面我为你详细梳理几种最常用的方法,包括从源码生成汇编、反汇编已有的二进制文件,以及在调试器中查看运行时汇编。
CentOS 最小化安装可能缺少一些开发工具,建议先安装 gcc、gdb 和 binutils:
# CentOS 7 及以前使用 yum
sudo yum install -y gcc gdb binutils
# CentOS 8 / Stream 使用 dnf
sudo dnf install -y gcc gdb binutils
如果你有源代码,并且想看编译器是如何把它翻译成汇编的,最简单的方法是使用 gcc/g++ 的 -S(大写 S)参数。
编写一个简单的 C 文件(如 test.c):
#include <stdio.h>
int main() {
int a = 10;
int b = 20;
int c = a + b;
printf("%d\n", c);
return 0;
}
生成汇编文件:
gcc -S test.c -o test.s
这会在当前目录生成 test.s 文件,里面就是对应的汇编代码(默认是 AT&T 语法)。
常用的辅助参数:
-O2(查看优化后的汇编)mov eax, 1 而不是 mov $1, %eax):gcc -S -O2 -masm=intel test.c -o test.s
grep,或者直接在生成的 .s 文件中找)。objdump)如果你只有一个已经编译好的可执行文件或 .so 库文件,想“逆向”查看它的汇编指令,可以使用 objdump 命令。
先编译生成二进制(加上 -g 保留调试信息方便对照源码):
gcc -g -o test test.c
反汇编可执行代码段:
objdump -d ./test
-d 表示反汇编所有包含机器指令的段(如 .text)。
将源代码与汇编混合显示(非常实用):
objdump -S -d ./test | less
(按 q 退出 less 浏览)
使用 Intel 语法反汇编(推荐):
objdump -M intel -d ./test
只查看某一个函数(如 main):
objdump -M intel -d ./test | grep -A 20 "<main>:"
如果你想在程序运行的过程中(比如在某处断下来时)查看当时的汇编指令和寄存器状态,可以使用 gdb。
用调试信息编译:
gcc -g -o test test.c
启动 GDB:
gdb ./test
在 GDB 内部查看汇编的常用命令:
(gdb) set disassembly-flavor intel
main):(gdb) disassemble main
或者简写:disas main(gdb) break main # 在 main 函数打断点
(gdb) run # 运行程序
(gdb) disassemble # 反汇编当前所在函数
(gdb) x/10i $pc
(gdb) layout asm # 只显示汇编
(gdb) layout split # 上面显示源码,下面显示汇编
(按 Ctrl + X 再按 A 可以退出 TUI 布局)在 CentOS(及绝大多数 Linux 发行版)中,默认生成或反汇编出来的汇编是 AT&T 语法,它的特点是指令带有后缀(如 movl、addq),并且源操作数和目标操作数是相反的:
movl $10, %eax # 把 10 放进 eax(源在前,目的在后,立即数加 $)
而 Intel 语法(Windows 常用的风格,多数开发者觉得更易读)是这样的:
mov eax, 10 # 把 10 放进 eax(目的在前,源在后)
如果你刚接触汇编,强烈建议在 gcc 或 gdb 中加上 Intel 语法参数,降低阅读难度。
| 需求 | 推荐命令 |
|---|---|
| 想看自己写的 C 代码生成啥汇编 | gcc -S -masm=intel test.c |
| 想看编译好的程序/库里有啥汇编 | objdump -M intel -d ./program |
| 想调试并单步执行汇编指令 | gdb ./program -> set disassembly-flavor intel -> disas main |
如果你有更具体的场景(比如查看 Linux 内核模块汇编、或者查看某个具体系统调用的实现),可以告诉我,我可以提供更针对性的命令。