X86汇编入门-机器码 - 弦外之音

/ 0评 / 0

本文主要讲解 两个重点。

1,汇编代码 对应的 机器码是怎么样的

2,为什么用汇编实现某些功能会比 C语言 性能好。



C语言代码:

int add_two(int a,int b){
    return a+b;
}
int main() {
    int return_num = add_two(1,8);
    return return_num - 3;
}

汇编代码:

        .text
        .globl  main
        .type   main, @function
        .type   add_two, @function
add_two:
        movl    %ebx, %eax
        addl    %ecx, %eax
        ret
main:
        pushl   %ebp
        movl    %esp, %ebp
        /* 两个参数 分别传进去 ebx ,ecx,所以需要先 保存 ebx ,ecx 的旧值进去 堆栈。 */
        pushl   %ebx
        pushl   %ecx
        /* 开始寄存器传参, 参数 1 丢进去 ebx,参数 8 丢进去 ecx */
        movl    $1, %ebx
        movl    $8, %ecx
        call    add_two
        /* 从堆栈恢复 ecx ebx的值 */
        popl    %ecx
        popl    %ebx
        /* 返回值减 3 */
        subl    $3, %eax
        popl    %ebp
        ret

执行以下命令,编译,调试 汇编可执行文件。

gcc -m32 -o main-32 main-32.s
# 运行 gdb
gdb ./main-32
# 显示寄存器窗口
layout regs
# 断点
b *main

汇编代码,是一条 汇编 指令 就对应 一条机器指令,所以从上图看来,main 函数占 12条指令,add_two 函数占 3 条指令,加起来,CPU 运行 汇编程序 只需要 15条指令就可以了。

由于 eip 寄存器指向 0x565561a6 ,所以 mian 函数的 机器码就在 0x565561a6 ~ 0x565561c0 的位置,一共 0x1A 字节大小。

汇编 跟 机器码 表如下:

汇编代码位置占用字节数机器码 (大端序)
pushl %ebp0x565561a6 ~ 0x565561a710x55
addl %ecx, %eax0x565561a7 ~ 0x565561a920xe5 0x89
pushl %ebx0x565561a9 ~ 0x565561aa10x53
pushl %ecx0x565561aa ~ 0x565561ab10x51
movl $1, %ebx0x565561ab ~ 0x565561b050x00 0x00 0x00 0x01 0xbb
movl $8, %ecx0x565561b0 ~ 0x565561b550x00 0x00 0x00 0x08 0xb9
call add_two0x565561b5 ~ 0x565561ba50xff 0xff 0xff 0xe3 0xe8
省略.....0x565561ba ~ 0x565561bf5
popl %ebp0x565561bf ~ 0x565561c010x5d
ret0x565561c0 ~ 0x565561c110xc3
一共27

机器码原来是 小端序的,表格为了方便查看,改成大端序。


现在 再来看看 如果把 之前的 C语言代码 编译成 汇编代码,会有多少条指令。

int add_two(int a,int b){
    return a+b;
}
int main() {
    int return_num = add_two(1,8);
    return return_num - 3;
}

执行以下命令:

gcc -m32 -o main-32-c main-32.c
# 运行 gdb
gdb ./main-32-c
# 显示寄存器窗口
layout regs
# 断点
b *main

从上图可以看出,main 函数 15 条指令,add_two 函数 10 条指令,C语言代码 比 汇编代码多了 10条指令。这还只是 我们的C代码的指令条数,注意 C代码是运行在 /lib32/libc.so 运行时库里面的。所以上面的截图底部还有一些指令 get_pc_thunk.ax 要执行。

这个是因为C语言为了调试方便, 会 利用 GOT 表 等技术来操作汇编变量。

这是为了调试方便,开发效率而牺牲的性能。


扩展知识:

我们在用 notepad++ 来查看一下 之前汇编代码 生成的可执行文件是怎样的。

直接搜索(小端序),下面就是汇编代码对应的部分机器码

55 89 e5 53 51

从上图可以看到,实际的机器码只有 27 字节,其他的应该都是操作系统 加的东西。

之前说过 汇编代码 大多数情况,也是运行在操作系统之上的。


由于笔者的水平有限, 加之编写的同时还要参与开发工作,文中难免会出现一些错误或者不准确的地方,恳请读者批评指正。如果读者有任何宝贵意见,可以加我微信 Loken1。QQ:2338195090。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注