计算机执行机器代码,用字节序列编码低级的操作,包括处理数据、管理内存、读写存储设备上的数据,以及利用网络通信。编译器基于编程语言的规则、目标机器的指令集和操作系统遵循的惯例,经过一系列的截断生成机器代码。
在阅读本章的时候一定要复习一遍关于gcc的知识,参考GCC编译链接多文件
特别是以下一些介绍,我认为有必要贴在本章学习总结前面。
选项 -E
gcc -E test.c -o test.i 将test.c预处理输出test.i文件。
选项 -S
gcc -S test.i 将预处理输出文件test.i汇编成test.s文件。
选项 -c
gcc -c test.s 将汇编输出文件test.s编译输出test.o文件。

示例代码mstore.c

long mult2(long,long);
void multstore(long x,long y,long *dest)
{
    long t = mult2(x,y);
    *dest = t;
}

gcc -Og -S mstore.c
编译选项-Og告诉编译器使用会生成符合原始C代码整体结构的机器代码的优化等级。使用较高级别优化产生的代码会严重变形,以至于产生的机器代码和初始源代码之间的关系非常难以理解。
然后会生成mstore.s文件其中包含汇编语言。
示例代码mstore.s

        .file   "mstore.c"
        .text
        .globl  multstore
        .type   multstore, @function
multstore:
.LFB0:
        .cfi_startproc
        pushq   %rbx
        .cfi_def_cfa_offset 16
        .cfi_offset 3, -16
        movq    %rdx, %rbx
        call    mult2
        movq    %rax, (%rbx)
        popq    %rbx
        .cfi_def_cfa_offset 8
        ret
        .cfi_endproc
.LFE0:
        .size   multstore, .-multstore
        .ident  "GCC: (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609"
        .section        .note.GNU-stack,"",@progbits 

关于格式的注解

.file   "mstore.c"
        .text
        .globl  multstore
        .type   multstore, @function

所有以.开头的行都是指导汇编器和链接器工作的伪指令,我们通常都可以忽略这一行。
所以汇编语言主要内容如下

multstore:
        pushq   %rbx
        movq    %rdx, %rbx
        call    mult2
        movq    %rax, (%rbx)
        popq    %rbx
        ret

上面代码中每个缩进去的行都对应一条机器指令,如果pushq指令表示应该将寄存器%rbx的内容压入程序栈中。
使用gcc -Og -c mstore.c生成目标代码文件mstore.o,它是二进制格式的,所以无法直接查看。
要查看机器代码文件的内容有一类称为反汇编器的程序非常有用。这些程序根据机器代码产生一种类似于汇编代码的格式。
在linux中使用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;
}

gcc -Og -o prog main.c mstore.c
objdump -d prog

objdump -d prog显示的代码中与mstore.c反汇编产生的代码存在一点不同是列出的地址不同--连接器将这段代码的地址移动到了一段不同的地址范围中。第二个不同是连接器天上了callq指令调用函数mult2需要使用的地址400613.