CSAPP 习题3.4

发布于 2020-07-23  716 次阅读


题目

假设变量sp和dp被声明为类型

src_t *sp;
dest_t *dp;
这里src_t和dest_t是用typedef声明的数据类型。我们想使用适当的数据传送指令来实现下面的操作
*dp = (dest_t) *sp;

假设sp和dp的值分别存储在寄存器%rdi和%rsi中。对于表中的每个表项,给出实现指令数据传送的两条指令。其中第一条指令应该从内存中读数,做适当的转换,并设置寄存器%rax的适当部分。然后,第二条指令要把%rax的适当部分写到内存。在这两种情况中,寄存器的部分可以使%rax、%eax、%ax或%al,两者可以互不相同。
记住,当执行强制类型转换既涉及大小变化又涉及C语言中符号变化时,操作应先改变大小。

src_t dest_t 指令
long long movq (%rdi),%rax
movq %rax,(%rsi)
char int  
char unsigned  
unsigned char long  
int char  
unsigned unsigned char  
char short  

解答

这个题目本身不难,但是有一点很绕,什么时候用符号扩展传送指令,什么时候用零扩展传送指令

首先,根据左右两个的最大长度来判断是%rax、%eax、%ax还是%al。如:char是一字节,int是双字,所以用%eax;char是一字节,short是一字,所以用%ax。

我们一行一行解答

1. char -> int

首先char是有符号类型,int也是有符号类型,所以可以肯定需要符号扩展传送指令,由于char是1字节,而int是是双字,所以结果应该为
movsbl (%rdi),%eax
movq %eax,(%rsi)

2. char -> unsigned

由于char是有符号类型,unsigned是无符号类型,那么一个有符号一个无符号,我怎么选择扩展指令呢,这是题目的那句,记住,当执行强制类型转换既涉及大小变化又涉及C语言中符号变化时,操作应先改变大小。,所以我们应该先改变大小,改变有符号数的大小还是应该用movqs指令,所以结果与上面相同,
movsbl (%rdi),%eax
movq %eax,(%rsi)

3. unsigned char -> long

现在又来了,第一个是无符号数,第二个是有符号数,第一个是一字节,第二个是4字,根据上面的原则应该先改变大小,
movzbq (%rdi),%eax
movq %rax,(%rsi),
等等为什么答案不对,为什么答案是
movzbl(%rdi),%eax
movq %rax,(%rsi)
课本P123页给出,movl指令以寄存器作为目的时,它会把该寄存器的高位4字节设置为0。大意是把32位扩展到64位。

4. int -> char

这个基本上就没有什么要讲的了,int有符号,char有符号,也不需要扩展,
movl (%rdi),%eax
movq %al,(%rsi)

5. unsigned -> unsigned char

这个答案也很简单,
movl (%rdi),%eax
movq %al,(%rsi)

6. char -> short

这个也不难了,char是有符号一个字节,short是有符号的一个字,所以答案是
movsbw (%rdi),%ax
movw %ax,(%rsi)