我一直在我的树莓派学习ARM汇编与标志周围乱.我已经想出的方法只设置零标志,只有负,只有进位标志.然而,我想不出一种方法来设置只有溢出标志.这是可能的吗?任何帮助将不胜感激!挑战是不要写信给CPSR(因为我不允许出于各种原因,否则这将是最好的解决方案,因为它是最好的解决方案)编辑:只设置溢出标志,所有其他标志为零/清零。只使用算术或移位。NZCV = 0001编辑2:为了进一步澄清,我认为需要多个指令来实现这一点。
qgzx9mmu1#
我看不出一个明显的方法,只有一个指令,但你可以做的组合。例如:
mov r0, #0x80000000 mov r1, #0x00000001 subs r2, r0, r1 ; C and V set mov r3, #0x10 asrs r3, #1 ; C cleared, V not changed
字符串
mhd8tkvw2#
我是一个组装新手,在实验和研究过程中,我发现了以下设置单个标志的方法。请注意,我使用的是基于ARM 7 TDMI-S的32位RISC微控制器架构。有所谓的MRS和MSR指令。MRS用于读取标志,MSR用于写入标志。下面是我如何设置每个标志:
msr cpsr_cxsf, #0x80000000 ; N Flag msr cpsr_cxsf, #0x40000000 ; Z flag msr cpsr_cxsf, #0x20000000 ; C Flag msr cpsr_cxsf, #0x10000000 ; V Flag
5cnsuln73#
abc cr 000 00 001 01 x 010 01 011 10 100 01 101 10 110 10 x 111 11
字符串有符号溢出是指进位输出不等于进位输入。如果第一列是操作数a b的msbits,进位输入到msbit(其他位对于有符号或无符号溢出无关紧要),则右列是进位输出和结果。如果结果为1,则得到N位。因此必须是操作数的msbits为1,进位输入为0
0xxx (carrys) 1xxx (operand a) 1xxx (operand b) 0x80 + 0x80 = 0x00 (zero flag) 0x81 + 0x81 = 0x02 (need some other ones) 100000010 10000001 + 10000001 ============ 00000010
型-127 + -127 = -254你能得到的最大负数是-128,0x80,所以这是一个有符号溢出。但是有外卖,不是吗?所以也许减法会起作用-127-127
100000011 10000001 + 10000000 ============ 00000010
型但是,作为一个减法,它是否将进位反转为借位,在进位位中留下一个0?这不是ARM的工作方式,其他处理器/核心将这样做。因此,为了能够做到这一点,你需要一个处理器,它将进位定义为减法的借位(在加法结束时将进位反转)。你在写这篇文章的时候编辑了你的问题,移位操作如何修改有符号溢出?需要加或减(需要使用加法器)。
brvekthn4#
我认为,在ARM上,不考虑寄存器输入,通过写入所有四个标志的单个算术指令,没有办法得到V=1 C=0的正结果(Z=0 N=0)。因此,@domen的答案使用移位来清除C和其他标志,而不修改V,这可能是我们所能做的最好的,而不是直接设置CPSR的msr。一般情况下,算术运算在问题中是允许的,但是mul leaves V unmodified,mls/mla/smull和朋友不设置标志。像lsl这样的移位也不会改变V,就像and这样的位指令。溢出INT_MIN/-1的sdiv不会留下任何痕迹:sdiv根本不会设置标志。加法和减法设置了所有四个标志,但是减法将C设置为非借位输出,如果您将其视为实际的二进制减法的话。(x - y的ARM减法设置进位标志,就像从带进位的加法x + ~y设置进位为1一样。)
msr
mul
mls
mla
smull
lsl
and
INT_MIN/-1
sdiv
x - y
x + ~y
negative + negative => positive
positive+positive
减法可以用positive-negative => negative符号溢出,这是我们不想要的。或者用negative-positive => positive。但是负数是无符号的-比正数高,所以这些减法不会产生借位。因此它们确实设置了C。(当设置了C并且清除了Z时,bhi分支。)
positive-negative => negative
negative-positive => positive
bhi
所以减法的溢出条件都不能避免设置C。(至少在不考虑adc/sbc的情况下,不确定这些是否有帮助。
adc
sbc
这里有一种相当紧凑和有效的方法:从subs开始,它以我们想要的方式设置除了N之外的标志,然后进行移位,覆盖除了V之外的所有标志。
subs
N
V
.syntax unified movs r0, #0x80 // fits in a Thumb 16-bit mov reg, imm8 (zero-extended) subs r0, r0, r0, lsl #24 // NZCV=1001 from 0x80 - INT_MIN (0x80000000) overflowing to negative result 0x80000080 lsrs r0, #1 // R0 = 0x40000040, NZCV=0001 (checked with QEMU + LLDB)
字符串在Thumb-2机器码中,有两条指令是16位的,我还没有想到一种方法可以让所有3条指令都有16位的Thumb编码,用这个或任何其他策略。
0: 2080 movs r0, #0x80 2: ebb0 6000 subs.w r0, r0, r0, lsl #24 6: 0840 lsrs r0, r0, #0x1
型
0 - (1<<31) - 1是0x7fffffff,类似于0 - INT_MIN - 1。将其作为一个操作来执行就像0 - (INT_MIN + 1)一样,从0中减去一个负数并获得一个正数而不会溢出。使用rscs r0, #0这样的ARM指令来执行此操作会清除C和V标志。0 - 0x7fffffff - 1产生0x80000000 = INT_MIN,所以它甚至不是有符号溢出。从正数中减去也不会,但是从负数中减去会。但是负数是无符号的-比正数高,所以减法不会有借位,所以-3 - 0x7fffffff - 1使得C=0,如果我们从小于-1的负数开始,我们就不需要sbc,所以这没有帮助。0 + 0x80000000 + 1和adc没有帮助,那就是INT_MIN + 1没有带符号的溢出并且是负的。任何涉及加法的带符号溢出都有进位或负的结果,即使是adc。因此,adc、sbc或仅限ARM模式的rsc在这里都没有帮助。
0 - (1<<31) - 1
0x7fffffff
0 - INT_MIN - 1
0 - (INT_MIN + 1)
rscs r0, #0
0 - 0x7fffffff - 1
0x80000000
-3 - 0x7fffffff - 1
-1
0 + 0x80000000 + 1
INT_MIN + 1
rsc
4条答案
按热度按时间qgzx9mmu1#
我看不出一个明显的方法,只有一个指令,但你可以做的组合。例如:
字符串
mhd8tkvw2#
我是一个组装新手,在实验和研究过程中,我发现了以下设置单个标志的方法。请注意,我使用的是基于ARM 7 TDMI-S的32位RISC微控制器架构。有所谓的MRS和MSR指令。MRS用于读取标志,MSR用于写入标志。
下面是我如何设置每个标志:
字符串
5cnsuln73#
字符串
有符号溢出是指进位输出不等于进位输入。如果第一列是操作数a b的msbits,进位输入到msbit(其他位对于有符号或无符号溢出无关紧要),则右列是进位输出和结果。如果结果为1,则得到N位。因此必须是操作数的msbits为1,进位输入为0
型
-127 + -127 = -254你能得到的最大负数是-128,0x80,所以这是一个有符号溢出。
但是有外卖,不是吗?
所以也许减法会起作用-127-127
型
但是,作为一个减法,它是否将进位反转为借位,在进位位中留下一个0?这不是ARM的工作方式,其他处理器/核心将这样做。
因此,为了能够做到这一点,你需要一个处理器,它将进位定义为减法的借位(在加法结束时将进位反转)。
你在写这篇文章的时候编辑了你的问题,移位操作如何修改有符号溢出?需要加或减(需要使用加法器)。
brvekthn4#
我认为,在ARM上,不考虑寄存器输入,通过写入所有四个标志的单个算术指令,没有办法得到V=1 C=0的正结果(Z=0 N=0)。因此,@domen的答案使用移位来清除C和其他标志,而不修改V,这可能是我们所能做的最好的,而不是直接设置CPSR的
msr
。一般情况下,算术运算在问题中是允许的,但是
mul
leaves V unmodified,mls
/mla
/smull
和朋友不设置标志。像lsl
这样的移位也不会改变V,就像and
这样的位指令。溢出INT_MIN/-1
的sdiv
不会留下任何痕迹:sdiv
根本不会设置标志。加法和减法设置了所有四个标志,但是减法将C设置为非借位输出,如果您将其视为实际的二进制减法的话。(
x - y
的ARM减法设置进位标志,就像从带进位的加法x + ~y
设置进位为1一样。)negative + negative => positive
;它们的符号位会进位到C中。而positive+positive
溢出到负数会设置N。所以我们不能用加法
减法可以用
positive-negative => negative
符号溢出,这是我们不想要的。或者用
negative-positive => positive
。但是负数是无符号的-比正数高,所以这些减法不会产生借位。因此它们确实设置了C。(当设置了C并且清除了Z时,bhi
分支。)所以减法的溢出条件都不能避免设置C。(至少在不考虑
adc
/sbc
的情况下,不确定这些是否有帮助。这里有一种相当紧凑和有效的方法:从
subs
开始,它以我们想要的方式设置除了N
之外的标志,然后进行移位,覆盖除了V
之外的所有标志。字符串
在Thumb-2机器码中,有两条指令是16位的,我还没有想到一种方法可以让所有3条指令都有16位的Thumb编码,用这个或任何其他策略。
型
有
sbc
/adc
的借位/进位输入?没有,没有帮助0 - (1<<31) - 1
是0x7fffffff
,类似于0 - INT_MIN - 1
。将其作为一个操作来执行就像0 - (INT_MIN + 1)
一样,从0中减去一个负数并获得一个正数而不会溢出。使用rscs r0, #0
这样的ARM指令来执行此操作会清除C和V标志。0 - 0x7fffffff - 1
产生0x80000000
= INT_MIN,所以它甚至不是有符号溢出。从正数中减去也不会,但是从负数中减去会。但是负数是无符号的-比正数高,所以减法不会有借位,所以-3 - 0x7fffffff - 1
使得C=0,如果我们从小于-1
的负数开始,我们就不需要sbc
,所以这没有帮助。0 + 0x80000000 + 1
和adc
没有帮助,那就是INT_MIN + 1
没有带符号的溢出并且是负的。任何涉及加法的带符号溢出都有进位或负的结果,即使是adc
。因此,
adc
、sbc
或仅限ARM模式的rsc
在这里都没有帮助。