深入理解计算机系统笔记:第三章:3.1-程序的机器级表示(本章基于Inter IA32和x86-64)

一、第三章:整章阅读的目的和获得好处

1)了解由C编译器生成的x86-64机器代码,说明为不同控制结构(比如条件、循环和开关语句)生成的基本指令模式。
2)了解栈分配、寄存器使用惯例和参数传递过程的实现。
3)了解不同数据结构(如结构、联合和数组)的分配和访问方式
4)了解整数和浮点数算术运算的指令实现
5)通过分析程序在机器级的方法来理解常见的代码安全漏洞(例如缓冲区溢出),以理解程序员、编译器和操作系统可以采取的减轻这些威胁的措施。

二、编译系统过程

  • 结果
    hello.c通过gcc编译编程可执行文件hello

在这里插入图片描述

  • 过程
    hello.c->预处理->hello.i->编译->hello.s->汇编->hello.o 和.h文件链接成可执行文件
    在这里插入图片描述
  • 因特尔器处理器的发展历史
1978年发布了第一款微处理器8086,到如今,发展的大意实图如下所示

在这里插入图片描述

三、涉及到的代码

  • 代码
    • main.c
#include <stdio.h>
void mulstore(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;
}
  • mstore.c
long mult2(long , long )void mulstore(long x, long y ,long *dest)
{
	long t = mult2(x,y);
	* dest = t;
}
  • 编译指令讲解

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

1)-Og是告诉编译器生成符合编译器生成符合原始C代码整体结构的机器代码,实际项目中会使用-O1
或-O2,甚至更高的编译优化选项,但是使用高级别的优化产生的代码会严重变形,导致产生的机器代码与最初的源代码之间的关系难以理解(这里为了方便理解,选择-Og这个优化选项)
2)-o 后面的参数prog表示生成可执行文件的文件名

四、.c文件生成汇编文件及详细说明

4.1 汇编代码及生成

  • 指令

gcc -Og -S mstore.c

  • 作用
    生成mstore.c 对应的汇编文件mstore.s

  • 参数解释
    -S这个编译选项就是告诉编译器GCC产生的文件为汇编文件

  • 汇编指令

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

4.2 汇编代码讲解

1)其中以“.”开头的行都是指导汇编器和链接器工作的伪指令,也就是说可以忽略以"."开够行
2)push %rbq 将寄存器rbx的值压入程序栈进行保存,保存寄存器rbx的内容,在函数返回之前使用了pop指令,恢复寄存器rbx的内容
3)movq %rdx , %rbx
将寄存器rdx的内容复制到寄存器rbx,这条指令结束后,寄存器rbx与寄存器rdx的内容一致,都是dst指针所指向的内存地址
(根据寄存器用法的定义,函数multstore的三个参数分别保存在寄存器rdi,rsi,rdx中)
4)move指令的后缀"q"表示数据的大小
在这里插入图片描述

5)由于早期的机器是16位,后来才扩展到32位和64位,因此intel用字(word)来表示16位的数据类型,所以32位的数据类型称为双字,64位的数据类型称为四字
在这里插入图片描述
movb -》是move byte的缩写,表示传送字节
movw -》是move word的缩写,表示传送字
movl -》表示传送双字(move double word),其中l是long word的缩写
movq -》 表示传送四字
6)call指令对应于C代码中的函数调用,这一行代码比较容易理解,该函数的返回值会保存在寄存器rax中,rax保存了x和y的乘积结果
在这里插入图片描述
7)吓一跳指令movq %rax ,(%rbx)
将寄存器rax的值送到内存中,内存的地址就存放在寄存器rbx中(由于是被调用者寄存器测录)
8)最后一条ret就是函数返回

五、寄存器简单介绍

  • 分类
    64位操作系统有16个寄存器,可简单分类为调用者保存寄存器和被调用者保存寄存器

  • 例子(函数A调用了函数B)
    在这里插入图片描述
    (1)函数A称为调用者,函数B称为被调用者
    (2)由于调用了函数B,寄存器rbx在函数B中被修改了
    (3)逻辑上寄存器rbx的内容在调用函数B的前后应该保持一致,为了实现这个一致,有两个策略:
    策略一:函数A在调用函数B之前,提前保存寄存器rbx的内容,执行函数B之后,再恢复寄存器rbx原来存储的内容,这种策略称为调用者保存
    在这里插入图片描述
    策略二:函数B在使用寄存器rbx之前,先保存寄存器rbx的值,在函数B返回之前,先恢复rbx原来存储的内容,这种策略被称之为被调用者保存
    在这里插入图片描述

  • 寄存器使用策略选择
    不同的寄存器被定义成不同的策略,具体如下所示

Callee saved: (被调用者保存模式)
Caller saved : (调用者保存模式)

在这里插入图片描述

五、C代码如何翻译成机器代码

  • 编译指令

gcc -Og -c mstore.c

  • 指令执行结果
    执行这条命令即可产生mstore.c所对应的机器代码文件mstore.o,由于该文件是二进制的,所以无法直接查看,这里需要借助反汇编工具-objdump,汇编器将汇编代码翻译成二进制的机器代码(.o文件),反汇编器就是将机器代码(.o文件)翻译成汇编代码(.s代码)

  • 反汇编指令

objdump -d mstore.o

  • 汇编代码
root@iZbp1do67v9l7zwkcs2b22Z:~/code/test# objdump -d mstore.o

mstore.o:     file format elf64-x86-64


Disassembly of section .text:

0000000000000000 <mulstore>:
   0:   53                      push   %rbx
   1:   48 89 d3                mov    %rdx,%rbx
   4:   e8 00 00 00 00          callq  9 <mulstore+0x9>
   9:   48 89 03                mov    %rax,(%rbx)
   c:   5b                      pop    %rbx
   d:   c3                      retq   
root@iZbp1do67v9l7zwkcs2b22Z:~/code/test# 
  • 对比汇编得到的汇编代码和编译得到的汇编代码(反汇编代码省略了很多指令后缀的"q",但在call 、ret指令添加了后缀"q")
    在这里插入图片描述
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值