深入理解计算机系统 笔记(二)
来源:互联网 发布:instagram类似社交软件 编辑:程序博客网 时间:2024/05/17 08:50
第三章 程序的机器级表示
gcc c语言编译器 -> 汇编
汇编代码是机器代码的文本表示
平坦寻址模式
Intel IA32 和 x86-64
3.2 程序编码
一个c程序,有2个文件p1.c和p2.c
unix$ gcc -o1 -o p p1.c p2.c
gcc gcc c编译器,也可以用cc启动
-o1 编译器使用第一级优化,级别越高编译时间越长
- 步骤:
- 1.编译器插入所有#include命令指定的文件,并扩展#define声明的宏
- 2.编译器产生2个源代码的汇编代码,p1.s和p2.s
- 3.汇编器将汇编代码转为二进制目标代码,p1.o和p2.o
- 4.连接器将2个目标代码文件和库函数的代码合并,生成可执行代码p
3.2.1 机器级代码
指令集体系结构(ISA):定义了处理器状态、指令的格式、指令对状态的影响
机器级程序使用的存储器地址是虚拟地址,操作系统将虚拟地址转化为物理地址
3.2.2 代码示例
int accum = 0;int sum(int x, int y){ int t = x + y; accum += t; return t;}
gcc运行编译器,产生一个汇编文件code.s
unix$ gcc -o1 -S code.c -o code.s
产生一个二进制文件,无法直接查看
unix$ gcc -o1 -c code.c -o code.o
反汇编器:
unix$ objdump -d code.o
macos下可以用tool代替:
macos$ otool -tV code.o
生成实际可执行的代码需要一组目标代码运行连接器,这一组目标代码必须包含main函数
int main(){ return sum(1, 3);}
unix$ gcc -o1 code.o main.c -o prog
进行反汇编
macos$ otool -tV prog
下面给出MacOS和Linux下,system.s:
MacOS:
Linux:
3.3 数据格式
movb(传送字节)、movw(传送字)、movl(传送双字)
3.4 访问信息
IA32cpu包含一组8个存储32位的寄存器,8个寄存器一%e开头。大多数情况下,前6个寄存器可以看为通用寄存器,后2个寄存器保存着指向程序堆栈中重要位置的指针。
3.4.1 操作数指示符
指令包含一个或多个操作数,源操作数:立即数、寄存器、存储器,目的操作数:寄存器、存储器。‘$’后一个用标准c表示法表示的整数表示立即数,如$-577或$0x1F。%eax 表示32位寄存器,%ax 表示16位寄存器,%ah或%al 表示8位寄存器。
寻址方式:
练习题3.1
答案:0x100、0xAB、0x108、0xFF、0xAB、0x11、0x13、0xFF、0x11
3.4.2 数据传送指令
MOV S, D
PS:源操作数和目的操作数不能同为存储器。
// Assume initially that %dh = 0xCD, %eax = 98765432movb %dh, %al %eax = 987654CDmovsbl %dh, %eax %eax = FFFFFFCDmovzbl %dh, %eax %eax = 000000CD
pushl和popl:
堆栈指针%esp保存栈顶元素的地址。
练习题3.2
答案:
1 movl %eax, (%esp)2 movw (%eax), %dx3 movb $0xFF, %bl4 movb (%esp, %edx, 4), %dh5 pushl $0xFF6 movw %dx, (%eax)7 popl %edi
练习题3.3
答案:
1 movb $0xF, (%bl) -> 源操作数是4位,目的操作数不知道大小2 movl %ax, (%esp) -> 源操作数是1字,move是双字3 movw (%eax), 4(%esp) -> 源操作数是1字,目的操作数是双字4 movb %ah, %sh -> 没有%sh的寄存器5 movl %eax, $0x123 -> 目的操作数是立即数6 movl %eax, %dx -> 源操作数是双字,目的操作数是1字7 movb %si, 8(%ebp) -> %si是1个字的大小,用movb不合理
3.4.3 数据传送示例
过程体:由c代码产生的汇编代码,有一部分作为程序入口为运行栈分配空间和在过程返回前回收栈空间的代码,除此之外的代码称为过程体。
练习题3.4
答案:
1 movsbl %al, (%eax)2 movsbl %al, (%eax)3 movzbl %al, (%eax)4 movb %al, (%eax)5 movb %al, (%eax)6 movl %al, (%eax)
练习题3.5
答案:
void decode1(int *xp, int *yp, int *zp){ int tempx = *xp; int tempy = *yp; int tempz = *zp; *yp = tempx; *zp = tempy; *xp = tempz;}
3.5 算数和逻辑操作
加载有效地址、一元操作、二元操作、移位
3.5.1 加载有效地址
加载有效地址指令leal是movl的变形,目的操作数必须是寄存器。
练习题3.6
答案:
x+6、x+y、x+4y、9x+7、4x+10、x+2y+9
3.5.2 一元操作和二元操作
练习题3.7
答案:
3.5.3 移位操作
练习题3.8
答案:
sall $2, %eax
sarl %ecx, %eax
3.5.4 讨论
汇编代码和C语言代码的顺序不同。
练习题3.9
答案:
x ^ y
t1 >> 3
~t2
t3 - z
练习题3.10
答案:
A. 将寄存器%edx置0
B. movl $0, %edx
C. 汇编和反汇编这段代码,xor的版本只需要2个字节,而movl的版本需要5个字节
3.5.5 特殊的算术操作
练习题3.11
答案:
1 movl 8(%ebp), %eax2 movl %edx, %edx3 divl 12(%ebp)4 movl %eax, 4(%esp)5 movl %edx, (%esp)
练习题3.12
答案:
A. 大小为64位的整型数据,应为long
B.
1 %eax = x2 %ecx = y的高32位3 %ecx = x * y的高32位4 %edx:%eax = y的低32位 * x5 %edx = %ecx + %edx // 即将低32位乘法的进位和高32位成法结果相加6 %ecx = dest7 (%ecx) = 积的低32位8 (%ecx + 4) = 积的高32位
3.6 控制
利用jump指令,可以控制一组机器代码的执行顺序。
3.6.1 条件码
条件码寄存器:
CF:进位标示。无符号操作数是否溢出。
ZF:零标志。最近的操作得到的结果为0。
SF:符号标志。最近的操作得到的结果为负数。
OF:溢出标志。有符号操作数是否溢出。
CMP和TEST指令仅会改变条件码寄存器,不更改其他寄存器。
3.6.2访问条件码
条件码不能直接读取,1)根据条件码的某个组合,将一个字节设置为0或1;2)条件跳转到别的部分;3)有条件的传送数据。
练习3.13
答案:
A. int <
B. short >=
C. unsigned char <
D. long !=
练习题3.14
答案:
A. long !=
B. short/unsigned short ==
C. char >
D. unsigned short >
3.6.3 跳转指令及其编码
间接跳转是使用寄存器%eax中的值作为跳转目标。
练习题3.15
答案:
A. je指令的目标为0x8048291+0x05,即0x8048296
804828f: 74 05 je 80482968048291: e8 1e 00 00 00 call 80482b4
B. jb指令的目标为0x8048359-25(-25的补码为e7),即0x8048340
8048357: 72 e7 jb 80483408048359: c6 05 10 a0 04 08 01 movb $0x1, 0x804a010
C. je指令的目标为0x8048391,则mov指令的地址为0x8048391-0x12,即0x804837f。又因为74、12占2字节,则je指令的地址为0x804837f-2,即0x804837d
804837d: 74 12 je 8048391804837f: b8 00 00 00 mov $0x0, %eax
D. 以相反的顺序读取这些字节,则偏移量为0xffffffe0(-32),则0x80482c4-32,即0x80482a4
80482bf: e9 e0 ff ff ff jmp 80482a480482c4: 90 nop
E.
3.6.4 翻译条件分支
C语言中if-else的模版:
if (test-expr) then-statementelse else-statement
汇编通常会使用下面的形式:
t = test-expr if (!t) goto false then-statement goto donefalse: else-statementdone:
练习题3.16
答案:
A.
void cond(int a, int *p){ if (p == 0) goto done; if (a <= 0) goto done; *p += a;done: return;}
B. 第一个条件分支是&&表达式实现的一部分。如果对p为非空的测试失败,代码会跳过对a>0的测试。
练习题3.17
答案:
A.
int absdiff(int x, int y){ int result; if (x < y) goto true; result = x - y; goto done;true: result = y - x;done: return result;}
B.
int absdiff(int x, int y){ int result; if (x < y) goto true; if (x >= y) goto false;true: result = y - x; goto done;false: result = x - y; goto done;done: return result;}
练习题3.18
答案:
int test(int x, int y){ int val = x ^ y; if (x < -3) { if (y < x) val = x * y; else val = x + y; } else if (x > 2) val = x - y; return val;}
3.6.5 循环
- do-while循环
通用形势:
do body-statement while (test-expr)
可以翻译成
loop: body-statement t = test-expr if (t) goto loop
练习题3.19
答案:
A. 14
#include <iostream>#define NUM_SIZE 100int main(void){ using namespace std; int num[NUM_SIZE]; num[0] = 1; for (int i = 1;; i++) { num[i] = num[i - 1] * i; cout << i << ":" << num[i] << endl; if (num[i] < num[i - 1]) break; }return 0;}
B. 20
#include <iostream>#define NUM_SIZE 100int main(void){ using namespace std; long long int num[NUM_SIZE]; num[0] = 1; for (int i = 1;; i++) { num[i] = num[i - 1] * i; cout << i << ":" << num[i] << endl; if (num[i] < num[i - 1]) break; } return 0;}
- 深入理解计算机系统 笔记(二)
- 《深入理解计算机系统》(二)
- 深入理解计算机系统(笔记):计算机系统漫游
- 深入理解计算机系统学习笔记(二)之程序优化
- 《深入理解计算机系统》读后笔记二
- 《深入理解计算机系统》阅读笔记二
- 深入理解计算机系统笔记
- 《深入理解计算机系统》笔记
- 深入理解计算机系统笔记
- 深入理解计算机系统笔记
- 【笔记】深入理解计算机系统
- 深入理解计算机系统笔记
- 深入理解计算机系统笔记
- 《深入理解计算机系统》笔记
- 深入理解计算机系统--笔记
- 深入理解计算机系统-笔记
- 深入理解计算机系统之链接(二)
- 深入理解计算机系统(第一章学习笔记)
- EasyUI学习第三篇:Form表单
- hdu 3657 Game【最大权独立点集------最大流最小割Dinic】
- Android 中 ListView 的 下拉刷新 和 上拉加载 的 重点及学习(一)
- NYOJ 499.迷宫(深搜)
- c++关于线性表的基本操作
- 深入理解计算机系统 笔记(二)
- 100天土鸡饲养计划(32)
- UVA 11210 暴力枚举 + 递归(hdu 4431)
- Leetcode 2 Add Two Numbers
- 在Ubuntu中安装Circos
- 智慧医疗解决方案
- vs2033安装遇到an unhandled exception has been caught by the vsw exception filter
- Linux下使用git命令及github项目
- 笔记--ThinkPHP的URL模式