目录
第3章 程序的机器级表示
数据格式
操作数指示符
练习题
数据传送指令
习题3.4
访问信息
压入和弹出栈数据
算数和逻辑操作
移位操作
讨论
特殊的算数操作
问题
操作数的三种类型:
在ATT格式的汇编代码中,立即数的书写方式是‘$’后面跟一个用标准C表示法表示的整数,如:$-577或$0x1F
用符号ra来表示任意寄存器a,用引用R[ra]来表示它的值,这是将寄存器集合看成一个数组R,用寄存器标识符作为索引。
内存引用会根据计算出来的地址(通常称为有效地址)访问某个内存位置。因为将内存看成一个很大的字节数组,我们用符号Mb[Addr]表示对存储在内存中从地址Addr开始的b个字节值的引用。为了简便,通常省去下标b。
假设下面的值存放在指明的内存地址和寄存器中:
填写下表,给出所示操作数的值:
解:
MOV类:movb、movw、movl、movq,分别对应操作的数据大小为:1、2、4、8字节。
此题转载自:https://blog.csdn.net/anlian523/article/details/83997464
有以下的c语言程序:
src_t *sp;
dest_t *dp;
*dp = (dest_t) *sp;
假设转换成汇编语言后, sp 的值存在寄存 %rdi, dp 的值存在 %rsi。而第一个指令都是将sp的值先导入到 %rax寄存器的相应字节中的。
注意第一条指令就得选择好是零拓展还是符合拓展(当从小的到大的时,关心的是源操作数的有无符号),当从大到小时,就不需要选择了,毕竟直接截断就好了。
第一条指令,也得先拓展到目标类型的大小。
第二条指令,只需要关心目的类型的大小以此来决定后缀。
总结:从小到大或一样大,两条指令的寄存器名字相同(这里指不带括号的,因为带括号的叫内存引用),但除了上表第4行,原因不明。猜想原因可能是:“常规的movq指令只能以表示为32补码数字的立即数作为操作数,然后把这个值符号拓展得到64位的值,放到目的位置”。
疑问???第2行为什么加括号?
movl %edx,%eax
两行可以合并成一行吗?
movl 8(%ebp),%eax
栈向下增长,这样一来,栈顶元素的地址是所有栈中元素地址中最低的。
栈指针%rsp保存着栈顶元素的地址。
大多数操作都分成了指令类,这些指令类有各种带不同大小操作数的变种,只有leaq没有其他大小变种
指令类A DD的四条加法指令:addb(字节加法)、addw(字加法)、addl(双子加法)、addq(四字加法)
leaq指令可以简洁地描述普通的算数操作。leaq指令使用如下:(3rd P129)
long scale(long x,long y,long z)
{
long t=x+4*y+12*z;
return t;
}
对应的3条leaq指令如下:
long scale(long x,long y,long z)
x in %rdi, y in %rsi, z in %rdx
scale:
leaq (%rdi,%rsi,4),%rax x+4*y
leaq (%rdx,%rdx,2),%rdx z+2*z=3*z
leaq (%rax,%rdx,4),%rax (x+4*y)+4*(3*z)=x+4*y+12*z
ret
疑问???高位会被忽略是什么意思?导致的结果就是w-1吗?
疑问???第5行没看懂
练习题3.11 常常可以看到以下形式的汇编代码行:
xorq %rdx,%rdx
但是在产生这段汇编代码的C代码中,并没有出现EXCLUSIVE-OR操作。
疑问???C这里的字节解释没看懂xorq的版本为什么只需要3个字节,而movq的需要7个字节又是为什么,不应该是8个字节吗?
Intel把16字节的数称为八字(oct word)。
下面的C函数说明x86-64如何实现除法,它计算了两个64位有符号数的商和余数:
void remdiv(long x,long y,long *qp,long *rp)
{
long q=x/y;
long r=x%y;
*qp=q;
*rp=r;
}
该函数编译得到如下汇编代码:
void remdiv(long x,long y,long *qp,long *rp)
x in %rdi, y in %rsi, qp in %rdx, rp in %rcx
1 remdiv:
2 movq %rdx,%r8 copy qp
3 movq %rdi,%rax Move x to lower 8 bytes of dividend(被除数)
4 cqto Sign-extend to upper 8 bytes of dividend
5 idivq %rsi Divide by y
6 movq %rax,(%r8) Store quotient at qp
7 movq %rdx,(%rcx) Store remainder at rp
8 ret
上述代码中,必须首先把参数qp保存到另一个寄存器中(第2行),因为除法操作需要使用参数寄存器%rdx。接下来,第3~4行准备“被除数”,复制并符号扩展x。除法之后,寄存器%rax中的商被保存在qp(第6行),而寄存器%rdx中的余数被保存在rp(第7行)中。
练习题3.12 3th P135
考虑如下函数,它计算两个无符号64位数的商和余数:
void uremdiv(unsigned long x,unsigned long y,unsigned long *qp,unsigned long *rp)
{
unsigned long q=x/y;
unsigned long r=x%y;
*qp=q;
*rp=r;
}
修改有符号数除法的汇编代码来实现这个函数。
汇编代码的第4行按照答案解释和书上示例替换为cqto,隐式将符号位(由于是无符号符号位是0)扩展到%rdx的所有位为0。
疑问???汇编代码的第4行的指令为什么不是movq $0,%rdx,为什么用双字的32位指令movl(对应的寄存器为%edx)?
除了整数寄存器,CPU还维护着一组单个位的条件码(condition code)寄存器,它们描述了最近的算术或逻辑操作的属性。
最常用的条件码有:
CF:进位标志。最近的操作使最高位产生了进位。可用来检查无符号操作的溢出。
ZF:零标志。最近的操作得出的结果为0。
SF:符号标志。最近的操作得出的结果为负数。
OF:溢出标志。最近的操作数导致一个补码溢出——正溢出或负溢出。
1、为什么需要3个字节,其他的只需要2个 PPT P25
2、练习题3.2 完全不懂 3thP124
3、练习题3.4的unsigned char到long的转换不太懂原因 3rd P126
4、3.5.1加载有效地址疑问???long t = x+4*y+12*z;编译时,该算数运算一定是需要3条leaq指令实现吗? 3rd P129
5、3.5.4讨论的汇编代码第5行没看懂(往上翻有截图)
6、习题3.11C问的字节解释没看懂