2

I'm working on an iPhone/iPad project, and I want to update the status register during some (not all) arithmetic operations. By default, Xcode uses 'Compile for Thumb' and I don't want to change it.

The following GCC inline assembly code works fine under ARM, but results in a compile error under Thumb: 'instruction not supported in Thumb16 mode - adds r6,r4,r5'. The problem lies in the status register update. (I'm also aware that movcs and strcs will need to be changed).

Does Thumb have an ADD instruction which sets Overflow (V) or Carry (C) in the CPSR? If not, are there Thumb-specific assembly level workarounds to test for overflows and carries?

uint32_t result, a, b;
int no_carry = 1;
...

__asm__
(
  "ldr  r4, %[xa]   ;"  // R4 = a
  "ldr  r5, %[xb]   ;"  // R5 = b
  "adds r6, r4, r5  ;"  // R6 = R4 + R5, set status
  "movcs    r4, #0      ;"  // set overflow (if carry set)
  "strcs    r4, %[xc]   ;"  // store it (if carry set)
  "str  r6, %[xr]   ;"  // result = R6
  : [xr] "=m" (result), [xc] "=m" (no_carry)
  : [xa] "m" (a), [xb] "m" (b)
  : "r4", "r5", "r6"
);

...

EDIT: Registers also need to be moved around to take advantage of the ARM ABI at Application Binary Interface (ABI) for the ARM Architecture.

jww
  • 97,681
  • 90
  • 411
  • 885

3 Answers3

4

Igor suggested ".syntax_unified". However, at least for binutils 2.22, the command is ".sytax unified". The following example compiles fine here:

.align  4
.code   16
.syntax unified

adds r0,r0,r2
adc  r1,r1,r3
Sven
  • 1,364
  • 2
  • 17
  • 19
4

I'm not very familiar with XCode and Apple's toolchain, but I suspect that it might be expecting the assembly in the old, pre-UAL form. The Thumb-16 encoding of ADD always sets flags (for registers R0-R7), however, in the pre-UAL assembly, the S was not added to the mnemonic. (Most arithmetic operations always update flags in Thumb-16, so S was implied.) So, you should try to either add .syntax_unified at the start of the assembly block, or use the simple ADD mnemonic.

However, you have another issue in your code. Thumb-16 does not support conditional instructions, only conditional branches. So you will have to redo your code using a branch, or use ADC/SBC.

Note that all of the above only applies to the original Thumb ISA (aka Thumb-16). Thumb-2 (aka Thumb-32) can do (almost) anything that ARM can, including using high registers and conditional instructions, but it's not available in ARMv6 targets (which is probably the default in XCode).

Igor Skochinsky
  • 24,629
  • 2
  • 72
  • 109
  • "However, you have another issue in your code..." GAS stopped complaining too soon (after ADDS). Thanks - fixed. – jww Jun 20 '11 at 10:51
  • "The Thumb-16 encoding of ADD always sets flags" - this is interesting. According to the following link, ADDS is supported on Thumb16. Perhaps this is a bug in Apple's GAS. See http://infocenter.arm.com/help/topic/com.arm.doc.qrc0006e/QRC0006_UAL16.pdf. – jww Jun 20 '11 at 10:56
  • 1
    All current ARM docs use UAL syntax, with S explicitly specified. Check the ARM Architecture Reference Manual, section Legacy Instruction Mnemonics. – Igor Skochinsky Jun 20 '11 at 11:10
  • 2
    gas has been doing this for a long while, perhaps since thumb was added. the most annoying part is that binutils disassembles it as adds, but wont accept that syntax when assembly. Just verified with codesourcery gas 2.20.51. It is a well known thing. – old_timer Jun 20 '11 at 13:26
0

According to the Thumb-16 Quick Reference Guide, the ADDS instruction should be available. This appears to be a bug in the assembler (as was confirmed by @dwelch).

I found I could work around it by issuing instructions pre-encoded using assembler directives. For example:

__asm__
(
  "ldr  r0, %[xa]   ;"  // R0 = a
  "ldr  r1, %[xb]   ;"  // R1 = b
  "adds r1, r1, r0  ;"  // R1 = a + b
  ...
);

would be realized using:

__asm__
(
  "ldr  r0, %[xa]   ;"  // R0 = a
  "ldr  r1, %[xb]   ;"  // R1 = b
  ".inst.w 0x1809   ;"  // Issue 'adds r1, r1, r0'
  ...
);

If I wanted adds r2, r2, r1, the code should emit .inst.w 0x1852, and so on.

EDIT: Code recently updated due to arm thumb2 ldr.w syntax? on the Binutils mailing list.

jww
  • 97,681
  • 90
  • 411
  • 885