answers-traps.txt added
This commit is contained in:
67
answers-traps.txt
Normal file
67
answers-traps.txt
Normal file
@ -0,0 +1,67 @@
|
||||
问题 1: 哪些寄存器包含函数的参数?例如,在 main 对 printf 的调用中,哪个寄存器包含 13?
|
||||
|
||||
在 RISC-V 调用约定中,函数参数通常通过寄存器 a0 到 a7 传递。
|
||||
|
||||
对于函数 g(int x) 和 f(int x) ,它们的参数 x 都通过寄存器 a0 传递。
|
||||
在 main 对 printf 的调用中, printf("y=%d\n", 13) 语句中,数字 13 将包含在寄存器 a1 中。 printf 的第一个参数(格式字符串的地址)将包含在寄存器 a0 中。
|
||||
|
||||
问题 2: 在 main 的汇编代码中,对函数 f 的调用在哪里?对 g 的调用在哪里?(提示:编译器可以内联函数。)
|
||||
|
||||
由于编译器优化, f 和 g 函数在 main 函数中被内联了。这意味着它们的实际代码直接插入到 main 函数的调用点,而不是通过 jal 或 jalr 指令进行函数调用。
|
||||
|
||||
我们可以通过观察 main 函数的汇编代码来验证这一点。在 main 函数中,你会看到对 f 和 g 的操作直接在 main 的代码流中执行,而没有显式的 jal 或 jalr 到 <f> 或 <g> 的地址。
|
||||
|
||||
问题 3: 函数 printf 位于哪个地址?
|
||||
|
||||
printf 函数不在 call.asm 文件提供的汇编代码中。 call.asm 似乎只包含用户定义的函数和一些与内存分配相关的代码。 printf 是一个标准库函数,它的地址会在程序链接时确定,并且通常在运行时动态加载。因此,我们无法从 call.asm 的反汇编代码中直接找到 printf 的地址。
|
||||
|
||||
问题 4: 在 main 中 jalr 到 printf 之后的寄存器 ra 中有什么值?
|
||||
|
||||
在 main 函数中 jalr 到 printf 之后,寄存器 ra (返回地址寄存器) 将包含紧跟在 jalr 指令之后的指令的地址。这个地址是 printf 函数执行完毕后应该返回到的 main 函数中的位置。
|
||||
|
||||
问题 5: 运行以下代码。无符号 int i = 0x00646c72; printf(“H%x Wo%s”, 57616, (字符 ) &i); 输出是什么?
|
||||
|
||||
i = 0x00646c72
|
||||
printf("H%x Wo%s", 57616, (char ) &i)
|
||||
|
||||
输出: H0e110 Wo rld
|
||||
|
||||
解释:
|
||||
|
||||
"H" 和 "Wo" 是直接打印的字符串。
|
||||
%x 对应 57616 。 57616 的十六进制是 0xE110 。
|
||||
%s 对应 (char ) &i 。由于 RISC-V 是 little-endian,内存中 i 的字节顺序是 72 6C 64 00 。
|
||||
0x72 是字符 'r'
|
||||
0x6C 是字符 'l'
|
||||
0x64 是字符 'd'
|
||||
0x00 是字符串终止符
|
||||
因此, %s 会打印 "rld"。
|
||||
|
||||
问题 6: 如果 RISC-V 是 big-endian,您会将 i 设置为什么 i 才能产生相同的输出?是否需要将 57616 更改为其他值?
|
||||
|
||||
如果 RISC-V 是 big-endian:
|
||||
为了使 %s 打印 "rld",我们需要将 i 设置为 0x726c6400 。在 big-endian 系统中,高位字节存储在低内存地址,所以 0x72 会在最低地址,然后是 0x6c , 0x64 ,最后是 0x00 。
|
||||
|
||||
是否需要将 57616 更改为其他值?
|
||||
不需要。 57616 是一个整数值,无论系统是 little-endian 还是 big-endian,它的数值表示是不变的。 %x 格式说明符只是将其打印为十六进制。字节序只影响多字节数据类型(如 int )在内存中的存储方式,而不影响其数值。
|
||||
|
||||
问题 7: 在下面的代码中, 'y=' 后面会打印什么?(注意:答案不是具体值。为什么会这样?
|
||||
|
||||
c
|
||||
printf("x=%d y=%d", 3);
|
||||
|
||||
|
||||
输出: y= 后面会打印一个不确定的值(垃圾值)。
|
||||
|
||||
为什么会这样:
|
||||
|
||||
printf 是一个变参函数,它根据格式字符串中的格式说明符来确定需要从栈中取出多少个参数。
|
||||
|
||||
格式字符串是 "x=%d y=%d" 。
|
||||
这意味着 printf 期望有两个 %d 对应的整数参数。
|
||||
但是,在实际调用中,只提供了一个参数 3 。
|
||||
|
||||
因此:
|
||||
|
||||
1. printf 会从栈中读取第一个整数参数来填充 x=%d ,这个值就是 3 。
|
||||
2. 然后, printf 会尝试读取第二个整数参数来填充 y=%d 。由于调用时只提供了 3 这一个参数, printf 会从栈上读取一个任意的、未初始化的内存位置的值,这个值是不可预测的(垃圾值)。
|
||||
Reference in New Issue
Block a user