"lui a4,%hi(0x0001ff00)" 的意外行为

Unexpected behaviour of "lui a4,%hi(0x0001ff00)"

我在使用 %hi() 汇编函数时遇到问题。 这个问题特定于 RISC-V GNU 汇编程序。编译此程序:

lui     a4,%hi(0x0001ff00)     # Does not give what I expect
lui     a4,0x1f                #
.word   0x0001f737             #

riscv32-unknown-elf-as  -o strange_lui.o strange_lui.s
riscv32-unknown-elf-objdump -D strange_lui.o 

给予

strange_lui.o:     file format elf32-littleriscv
Disassembly of section .text:
00000000 <.text>:
0:  00020737            lui a4,0x20
4:  0001f737            lui a4,0x1f
8:  0001f737            lui a4,0x1f

我原以为这三行应该编译成相同的代码。那我在这里错过了什么?我正在使用:

riscv32-unknown-elf-as  -v
GNU assembler version 2.31.1 (riscv32-unknown-elf) using BFD version (GNU Binutils) 2.31.1

%hi(...) 函数比看起来更聪明。它不只是 return 给定参数的前 20 位。

%hi 预计将在 lui 指令中使用,该指令将很快跟上另一条指令,如 add %lo(...),它将通过提供完成寄存器的 32 位加载低 12 位。

在执行add指令期间,这些低12位将被符号扩展以产生一个32位值,然后将其添加到寄存器的原始内容中。当低 12 位的最高位为 0 时,此符号扩展步骤对寄存器现有的最高 20 位没有影响。但是,当低 12 位的最高位为“1”时,符号扩展具有从寄存器高 20 位的现有值中减一的效果。

在这种情况下,%hi(0x0001ff00) 函数发现低 12 位的最左边位是“1”。因此,它预计将由以下 add %lo(0x0001ff00) 执行的减法,并将 0x00020 写入寄存器的前 20 位。 0x00020 将通过预期的符号扩展 add.

转换为您想要的 0001f

如果您希望您的程序为所有三个语句生成相同的指令,请给 %hi 一个参数,其低 12 位在最左边的位置为 0。 lui %hi(0x0001f700) 之类的东西就可以了。

总而言之,如果与“%lo()”返回的带符号值一起使用,“%hi()”宏将采用带符号的 int 值。

我什至不认为 "lui" 指令是假定的,这可能是任何其他取立即值的指令。这是您在示例中使用的内容,但还有许多其他使用立即数参数的 RV 指令

所以应该有另一种形式,如“%hu()”,与“%lu()”一起使用,不假设低位部分的符号扩展,甚至不假设“%lu( )”将被使用