assembly 如何只设置ARM汇编的溢出标志?

juzqafwq  于 12个月前  发布在  其他
关注(0)|答案(4)|浏览(158)

我一直在我的树莓派学习ARM汇编与标志周围乱.我已经想出的方法只设置零标志,只有负,只有进位标志.然而,我想不出一种方法来设置只有溢出标志.这是可能的吗?任何帮助将不胜感激!
挑战是不要写信给CPSR(因为我不允许出于各种原因,否则这将是最好的解决方案,因为它是最好的解决方案)
编辑:只设置溢出标志,所有其他标志为零/清零。只使用算术或移位。NZCV = 0001
编辑2:为了进一步澄清,我认为需要多个指令来实现这一点。

qgzx9mmu

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

字符串

mhd8tkvw

mhd8tkvw2#

我是一个组装新手,在实验和研究过程中,我发现了以下设置单个标志的方法。请注意,我使用的是基于ARM 7 TDMI-S的32位RISC微控制器架构。有所谓的MRSMSR指令。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

字符串

5cnsuln7

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的工作方式,其他处理器/核心将这样做。
因此,为了能够做到这一点,你需要一个处理器,它将进位定义为减法的借位(在加法结束时将进位反转)。
你在写这篇文章的时候编辑了你的问题,移位操作如何修改有符号溢出?需要加或减(需要使用加法器)。

brvekthn

brvekthn4#

我认为,在ARM上,不考虑寄存器输入,通过写入所有四个标志的单个算术指令,没有办法得到V=1 C=0的正结果(Z=0 N=0)。因此,@domen的答案使用移位来清除C和其他标志,而不修改V,这可能是我们所能做的最好的,而不是直接设置CPSR的msr
一般情况下,算术运算在问题中是允许的,但是mul leaves V unmodifiedmls/mla/smull和朋友不设置标志。像lsl这样的移位也不会改变V,就像and这样的位指令。溢出INT_MIN/-1sdiv不会留下任何痕迹:sdiv根本不会设置标志。
加法和减法设置了所有四个标志,但是减法将C设置为非借位输出,如果您将其视为实际的二进制减法的话。(x - y的ARM减法设置进位标志,就像从带进位的加法x + ~y设置进位为1一样。)

  • 我们需要结果为非零,以便零是明确的
  • 我们需要结果是非负的,所以Negative是明确的,因此我们需要结果是正的。
  • 我们需要进位清零,所以我们不能加上negative + negative => positive;它们的符号位会进位到C中。而positive+positive溢出到负数会设置N。
    所以我们不能用加法

减法可以用positive-negative => negative符号溢出,这是我们不想要的。
或者用negative-positive => positive。但是负数是无符号的-比正数高,所以这些减法不会产生借位。因此它们确实设置了C。(当设置了C并且清除了Z时,bhi分支。)

所以减法的溢出条件都不能避免设置C。(至少在不考虑adc/sbc的情况下,不确定这些是否有帮助。

这里有一种相当紧凑和有效的方法:从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

sbc/adc的借位/进位输入?没有,没有帮助

0 - (1<<31) - 10x7fffffff,类似于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 + 1adc没有帮助,那就是INT_MIN + 1没有带符号的溢出并且是负的。任何涉及加法的带符号溢出都有进位或负的结果,即使是adc
因此,adcsbc或仅限ARM模式的rsc在这里都没有帮助。

相关问题