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