本文共 1001 字,大约阅读时间需要 3 分钟。
计算机执行机器代码,用字节序列编码低级操作,在本篇文章中,我们会观察机器代码,以及人类可读表示–汇编代码。
为什么要学习机器代码呢?即使编译器承担了生成汇编代码的大部分工作,对于严谨的程序员,能够阅读和理解汇编代码仍是一项很重要的技能,阅读汇编代码,能理解编译器的优化能力,并分析代码中隐含的低效率。
代码示例:
在命令行上使用‘-S
’,就能看到C语言编译器产生的汇编代码 linux> gcc -Og -S mstore.c
汇编文件包含各种声明,包括下面几行:
如果使用‘-c
’选项,GCC就会编译并汇编代码: linux> gcc -Og -c mstore.c
这样产生目标代码文件mstore.o,它是二进制,无法直接查看,机器执行的程序只是一个字节序列,它是对一系列指令的编码
C语言数据类型在x86-64
中的大小,在64位机器,指针长8字节
一个x86-64
的中央处理单元(CPU)包含一组16个存储64位值的通用目的寄存器,这些寄存器存储整数数据和指针。
大多数指令有一个或多个操作数,指示使用的数据源以及放置结果的目的位置。操作数分三种类型,第一种是立即数,表示常数值,$-577、$0x1F;第二种是寄存器,表示某寄存器的内容;第三种是内存引用,根据计算出的地址访问某个内存位置。
寻址模式:
数据传送指令–MOV
,将数据从一个位置复制到另一个位置
使用数据传送指令的代码示例:
函数exchange由三条指令实现:两个数据传送(movq),一条返回函数被调用点的指令(ret)。过程执行时,xp
和y
存储在寄存器%rdi
和%rsi
,指令2从内存读出x
,放到寄存器%rax
,实现x=*xp
,用寄存器%rax
从这个函数返回值。指令3将y
写到寄存器%rdi
中的xp
指向的内存位置,实现*xp=y。
压入和弹出数据–pop/push
0x123
,再写到寄存器%rdx
,然后,寄存器%rsp
值将增加到0x108
,如图,值0x123
仍会保持在0x100
中,直到被覆盖,无论如何,%rsp
指向的地址总是栈顶。 x86-64
的整数和逻辑操作:
x86-64
比较和测试指令:
x86-64
跳转jmp指令:
x86-64
条件传送指令: 启动GDB:
linux> gdb prog
【完】?
转载地址:http://xyhpi.baihongyu.com/