本章思考题
- 请简述N、Z、C、V这4个条件标志位的作用。
答:如下表所示。条件标志位 描述 N 负数标志(上一次运算结果为负值) Z 零结果标志(上一次运算结果为零) C 进位标志(上一次运算结果发生了无符号数溢出) V 溢出标志(上一次运算结果发生了有符号数溢出) - 下面两条ADD指令能否编译成功?
答:不能编译成功。汇编器会报如下错误,其中第一条语句中立即数超过了范围,第二条语句中左移的位数只能是0或者12。add x0, x1, #4096 add x0, x1, #1, LSL 1
test.S: Assembler messages: test.S: Error: immediate out of range test.S: Error: shift amount must be 0 or 12 at operand 3 -- 'add x0,x1,#1,LSL 1'
- 下面的示例代码中,X0寄存器的值是多少?
答:ADC指令的计算过程是0xffffffffffffffff+2+C,因为0xffffffffffffffff+2的过程中已经触发了无符号数溢出,C=1,所以最终计算X0寄存器的值为2。mov x1, 0xffffffffffffffff mov x2, #2 adc x0, x1, x2
- 下面的示例代码中,SUBS指令对PSTATE寄存器有什么影响?
答:会导致C标志位为1。第二个操作数为X2寄存器的值,对应值为1,按位取反之后为0xFFFFFFFFFFFFFFFE。根据计算公式,计算3+0xFFFFFFFFFFFFFFFE+1,这个过程会发生无符号数溢出,因此4个标志位中的C=1,最终计算结果为2。mov x1, 0x3 mov x2, 0x1 subs x0. x1. x2
- 在下面的示例代码中,X0寄存器的值是多少?
答:X0寄存器的值为2。mov x1, #3 mov x2, #1 sbc x0, x1, x2
- 检查数组array[0, index-1]是否越界,需要判断两个条件:一是输入值是否大于或等于index,二是输入值是否小于0。如下两条指令可实现数组边界检查的功能,其中X0寄存器的值为数组的边界index,X1寄存器的值为输入值input。请解释这两条指令为什么能实现数组越界检查。
答:第一条语句是带N、Z、C、V标志位的减法指令。第二条语句中的HS表示是否发生了无符号数溢出,即判断C标志位是否为1。如果C为1,跳转到OutOfIndex标签处,说明发生了溢出。subs xzr, x1, x0 b.hs OutOfInex
- 在下面的示例代码中,W2和W3的值是多少?
答:W2的值是0xC0000045,W3的值是0x40000045。ldr w1, =0x8000008a asr w2, w1, 1 lsr w3, w1, 1
- 如果想在汇编代码中使某些特定的位翻转,该如何操作?
答:例如,想把0b10100001的第2位和第3位翻转,则可以对该数与0b00000110进行按位异或运算。10100001 ^ 00000110 = 10100111
- 设置某个寄存器A的Bit[7,4]为0x5。下面是C语言的伪代码,用变量val来表示寄存器A的值2,请使用BFI指令来实现。
答:代码如下。val &=~ (0xf << 4) val |= ((u64)0x5 << 4)
BFI指令把X1寄存器中的Bit[3,0]设置为X0寄存器中的Bit[7,4],X0寄存器的值是0x52。mov x0, #0x2 // 寄存器A的初始值为2 mov x1, #0x5 bfi x0, x1, #4, #4 // 往寄存器A的Bit[7,4]字段设置0x5
- 下面的示例代码中,X0和X1寄存器的值分别是多少?
答:X0寄存器的值是0x8,X1寄存器的值是0xFFFFFFFFFFFFFFF8。mov x2, #0x8a ubfx x0, x2, #4, #4 sbfx x1, x2, #4, #4
- 下面是用C语言来读取pmcr_e10寄存器Bit[15:11]的值,请使用汇编代码来实现。
答:使用UBFX指令来实现更简洁。val = read_sysreg(pmcr_e10) val = val >> 11; val &= 0x1f;
mrs x0, pmcr_e10 ubfx x0, x0, #11, #5