先写一个C语言代码文件mstore.c内容如下:
#include <stdio.h>
long mult2(long, long);
void multstore(long x, long y, long *dest) {
long t = mult2(x, y);
*dest = t;
}
在命令行使用“-S”选项,就能看到C语言编译器产生的汇编代码:
PS E:\VS Code\VS Code C\chapter 3> gcc -S mstore.c
这会使GCC运行编译器,产生一个汇编文件mstore.s,但是不做其他进一步的工作。(通常情况下,它还会继续调用汇编器产生目标代码文件)。
.file "mstore.c"
.text
.globl multstore
.def multstore; .scl 2; .type 32; .endef
.seh_proc multstore
multstore:
pushq %rbx
.seh_pushreg %rbx
subq $32, %rsp
.seh_stackalloc 32
.seh_endprologue
movq %r8, %rbx
call mult2
movl %eax, (%rbx)
addq $32, %rsp
popq %rbx
ret
.seh_endproc
.ident "GCC: (x86_64-posix-seh-rev0, Built by MinGW-W64 project) 8.1.0"
.def mult2; .scl 2; .type 32; .endef
如果继续使用“-C”命令行选项,GCC会编译并汇编该代码:
PS E:\VS Code\VS Code C\chapter 3> gcc -c mstore.c
这就会产生目标代码文件mstore.o,它是二进制格式的,所以无法直接查看。
要查看机器代码文件的内容,有一种称为反编译器(disassembler)的程序非常有用。这些程序根据机器代码产生一种类似于汇编的格式。带“-d”命令行标志的程序OBJDUMP(object dump)可以充当这个角色:
PS E:\VS Code\VS Code C\chapter 3> objdump -d mstore.o
结果如下:
生成实际可执行的代码需要对一组目标代码文件运行链接器,而这一组目标代码文件中必须含有一个main函数。假设在文件main.c中有下面这样的函数:
#include <stdio.h>
void multstore(long, long, long *);
int main() {
long d;
multstore(2, 3, &d);
printf("2 * 3 --> %ld\n", d);
return 0;
}
long mult2(long a, long b) {
long s = a * b;
return s;
}
然后,用如下方法生成可执行文件prog:
PS E:\VS Code\VS Code C\chapter 3> gcc -o prog main.c mstore.c
如:
文件prog不仅包含了两个过程的代码,还包含了用来启动和终止程序的代码,以及用来与操作系统交互的代码。我们也可以反汇编prog文件:
PS E:\VS Code\VS Code C\chapter 3> objdump -d prog.exe
此时可以运行生成的prog文件:
发现两个C文件的程序运行结果符合预期。
在生成的mstore.s文件中:
所有‘.
’开头的行都是指导汇编器和链接器工作的伪指令,我们通常可以忽略这些行。若我们去掉这些,带解释的汇编代码如下:
注以下为Linux环境下的mstore.s文件
multstore:
pushq %rbx
subq $32, %rsp
movq %r8, %rbx
call mult2
movl %eax, (%rbx)
addq $32, %rsp
popq %rbx
ret