Home > other >  Same ARM7 assembly code for two unsigned integers program and two signed integers program
Same ARM7 assembly code for two unsigned integers program and two signed integers program

Time:03-07

I used the same code for two programs minu and mins which both have to find the smallest integer of the two inputs. minu takes in two 8 bit unsigned integers wheras mins takes in two 16 bit signed integers.

program 1 (minu):

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

program 2 (mins)

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

ARM7 machine code: program 1:

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

program2:

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

CodePudding user response:

That will happen to work if your caller follows the standard calling convention and passes args zero-extended or sign-extended to 32-bit according to their signedness. Unlike uint32_t, all uint8_t values can be represented as non-negative signed int (32-bit), so signed comparison like BGE will give the correct result.

i.e. using a function that treats them both as 32-bit signed int works; that's the point of this calling convention rule, because ARM doesn't have a cmp instruction that could compare only the low 8 or 16 bits of input registers.

That's not what compilers do, though, they use cmp / movlo r0, r1 vs. movlt r0, r1 for unsigned LOwer vs. signed LEss-than. (MOV if the predicate is true, otherwise it runs as a NOP).

See it on the Godbolt compiler explorer.

CodePudding user response:

You have used signed comparison operations, and on 32-bit registers.

This is ok, if the caller used the proper load instructions to fetch and convert the 8-bit/16-bit data from memory into registers that are being compared (or else otherwise managed the conversion from 8-bit/16-bit to 32-bit).

For the unsigned 8-bit code you would need to use LDRB and for signed 16-bit, LDRSH.

In the unsigned case, using LDRB will convert 8-bit unsigned data loaded from memory to 32-bit by zero extension — the top 24 bits of the register get zero, and the lower order 8 bits the value from memory.  This final value in the register after LDRB is always going to be >= 0 whether interpreted as signed or unsigned in 32-bits, since the sign bit in the registers will be zeros.  It is up to you whether to consider the 32-bit value signed or unsigned, because we know that it will always be positive (non-negative) so in a sense it doesn't matter.  The C language would say it is int which is a signed data type, because it gravitates toward int and int can easily hold any value from a signed byte and/or an unsigned byte.

In the signed case, using LDRSH will convert 16-bit signed data loaded from memory to 32-bit signed value in the register.  It does this by propagating the sign bit from bit 15 of the 16-bit memory halfword into all the bits of the upper half of the register.  It is important in this case to consider the 32-bit register with the signed data type, since we may have negative or positive values.


When you have 32-bit values in memory, they can neither be sign extended nor zero extended to fit in a 32-bit register, as all the bits are already specified from memory.  As a result, for unsigned you would have to use unsigned >= conditions — meaning the branch instruction would have to change to BHS (branch higher or same), whereas for signed you would have to use signed >= conditions (BGE).1

Because your code is said to use smaller data types (smaller than 32-bits: 8-bit unsigned, and 16-bit signed) you can get away with using signed comparison for both types — provided the values are properly and accordingly extended to 32-bits into the registers.

If the values were loaded from memory into registers with an incorrect sign/zero extension, you would have to fix that with other instructions before using the comparison operations.  On x86, however, you can compare just the lower 8-bits or just the lower 16-bits of the registers with each other due to its partial register feature.  On the x86 processor using smaller size compares, the above comments about the full 32-bit value made above1 would also apply.

  • Related