assembly 两个无符号整数程序和两个有符号整数程序的ARM7汇编代码相同

3gtaxfhh  于 2023-01-13  发布在  其他
关注(0)|答案(2)|浏览(146)

我在minu和mins两个程序中使用了相同的代码,这两个程序都必须找到两个输入中最小的整数。minu接受两个8位无符号整数,而mins接受两个16位有符号整数。
程序1(minu):

uint8_t a = 5
uint8_t b = 10
//result should equal 5

程序2(分钟)

int16_t = -10
int16_t = 10
//result should be -10

ARM7机器代码:方案一:

minu:
  CMP R0,R1
  BGE end
  BX LR 
end: 
  MOV R0,R1
  BX LR

方案二:

mins: 
  CMP R0,R1 
  BGE end
  BX LR
end:
  MOV R0,R1
  BX LR
tpxzln5u

tpxzln5u1#

您已经在32位寄存器上使用了有符号比较运算和。
如果调用程序使用正确的加载指令从内存中读取8位/16位数据并将其转换到要比较的寄存器中(或者以其他方式管理从8位/16位到32位的转换),这是可以的。
对于无符号的8位代码,您需要使用LDRB,对于有符号的16位代码,您需要使用LDRSH
在无符号的情况下,使用LDRB将通过零扩展将从内存加载的8位无符号数据转换为32位-寄存器的前24位获得零,低8位获得来自内存的值。无论在32位中解释为有符号还是无符号,LDRB之后寄存器中的最终值总是〉= 0。因为寄存器中的符号位将为零。是否考虑32位值的符号或无符号取决于您,因为我们知道它将始终为正(非负)所以从某种意义上说这并不重要,C语言会说它是int,这是一个有符号的数据类型,因为它倾向于X1 M5 N1 X,并且X1 M6 N1 X可以容易地保存来自有符号字节和/或无符号字节的任何值。
在有符号的情况下,使用LDRSH会将从内存加载的16位有符号数据转换为寄存器中的32位有符号值。其方法是将16位内存半字的位15中的符号位传播到寄存器上半部分的所有位。在这种情况下,考虑具有有符号数据类型的32位寄存器非常重要。因为我们可能有正值或负值。
当内存中有32位值时,它们既不能进行符号扩展,也不能进行零扩展以适应32位寄存器,因为所有位都已经从内存中指定。因此,对于无符号值,您 * 必须使用无符号〉=条件-这意味着分支指令必须更改为BHS(分支更高或相同),而对于有符号的,则 * 必须使用有符号的〉=条件(BGE。1
因为您的代码使用较小的数据类型(小于32位:8位无符号和16位有符号),您可以对这两种类型都使用有符号比较--前提是这些值被正确地相应地扩展到寄存器中的32位。
如果将值从内存加载到带有不正确符号/零扩展名的寄存器中,则必须在使用比较操作之前使用其它指令进行修复。但是,在x86上,由于其部分寄存器功能,您可以仅比较寄存器的低8位或低16位。在使用较小比较大小的x86处理器上,上面关于全32位值的评论也适用。

tkclm6bt

tkclm6bt2#

如果调用者遵循标准的调用约定,并根据args的符号性将其零扩展或符号扩展为32位,那么这种方法就可以正常工作。与uint32_t不同,所有uint8_t值都可以表示为非负符号int(32位),因此像BGE这样的符号比较将给予正确的结果。
即,使用将它们都视为32位有符号int作品的函数;这就是此调用约定规则的要点,因为ARM没有只能比较输入寄存器低8位或低16位的cmp指令。
不过,编译器并不是这样做的,它们使用cmp/movlo r0, r1movlt r0, r1来表示无符号LOwer与有符号LEss-than。(如果 predicate 为真,则为MOV,否则作为NOP运行)。
在Godbolt编译器资源管理器上查看它。

相关问题