1

I'm compiling some test code for an embedded ARM chip using a test C file.

test.c is as follows:

int main(){
  *(int*)0xFFFFF400 = 7;
}

I compile the file with the following command

arm-none-eabi-gcc -march=armv4 -mtune=arm7tdmi -specs=nosys.specs -Wall -o test test.c

Which compiles without complaint, then I examine the assembly with

arm-none-eabi-objdump -d ./test

Which produces a long output with the following main() section:

00008018 <main>:
    8018:       e3e03000        mvn     r3, #0
    801c:       e3a02007        mov     r2, #7
    8020:       e3a00000        mov     r0, #0
    8024:       e5032bff        str     r2, [r3, #-3071]        ; 0xfffff401
    8028:       e1a0f00e        mov     pc, lr

Why does it say 0xfffff401 instead of 0xfffff400? Why is it subtracting 3071 instead of 3072?

Willis Hershey
  • 1,520
  • 4
  • 22
  • Does this answer your question? [Why this function does point to itself with a offset of 1?](https://stackoverflow.com/questions/65884094/why-this-function-does-point-to-itself-with-a-offset-of-1) – Tagli May 26 '21 at 20:11
  • 1
    Maybe? My instinct says that's a different thing though... This isn't a jump instruction it's a memory store instruction. Also this has nothing to do with thumb instructions, it's clearly a 32-bit ARM instruction that's being executed – Willis Hershey May 26 '21 at 20:13
  • 2
    The `mvn` instruction writes the bitwise inverse of its operand to a register. The bitwise inverse of 0 is all 1 bits, which, in two’s complement, represents −1. Then the address `[r3, #-3071]` is −1 + −3071 = −3072. – Eric Postpischil May 26 '21 at 20:18
  • If it isn't related to thumb mode then maybe you've managed to make the compiler believe this is Linux kernel code or similar. Linux specifically uses a system where MSB set in the address means kernel code. That could explain why, though since this is physical addresses (right?) rather than virtual, it doesn't make any sense. Is there any intricate MMU setup or such? – Lundin May 27 '21 at 09:44
  • No. Eric's answer is clearly the solution – Willis Hershey Jun 01 '21 at 16:29

1 Answers1

2

The mvn instruction writes the bitwise inverse of its operand to a register. The bitwise inverse of 0 is all 1 bits, which, in two’s complement, represents −1. Then the address [r3, #-3071] is −1 + −3071 = −3072.

I do not know why the compiler is choosing to base its addressing off −1 rather than 0.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312