1
votes

This is the disassembly of syscall() on iPhone.

(gdb) disass syscall
Dump of assembler code for function syscall:
0x3195fafc <syscall+0>: mov     r12, sp
0x3195fb00 <syscall+4>: push    {r4, r5, r6, r8}
0x3195fb04 <syscall+8>: ldm     r12, {r4, r5, r6}
0x3195fb08 <syscall+12>:        mov     r12, #0 ; 0x0
0x3195fb0c <syscall+16>:        svc     0x00000080
0x3195fb10 <syscall+20>:        pop     {r4, r5, r6, r8}
0x3195fb14 <syscall+24>:        bcc     0x3195fb2c <syscall+48>
0x3195fb18 <syscall+28>:        ldr     r12, [pc, #4]   ; 0x3195fb24 <syscall+40>
0x3195fb1c <syscall+32>:        ldr     r12, [pc, r12]
0x3195fb20 <syscall+36>:        b       0x3195fb28 <syscall+44>
0x3195fb24 <syscall+40>:        cfldrdeq        mvd15, [r12], #992
0x3195fb28 <syscall+44>:        bx      r12
0x3195fb2c <syscall+48>:        bx      lr
End of assembler dump.
  1. Can someone please explain what instructions at offsets +28,+32 are doing? At +28, the value of r12 is 0 (set at +12), so looks like r12 is being set to (in C notation) *(pc + 4). At +32, r12 is set to *(pc + r12) - note that this instruction is not compiling - see #3 below. The 'b' at +36 jumps to +44, which returns to the address in r12. So what value was loaded into r12 by +28 & +32?

  2. What does the cfldrdeq instruction at +40 do? I have check the ARM instruction set & searched for it, but not found anything.

  3. I added this code to my C program using asm(). When compiling, the compiler shows these errors. Any idea how to get around this?
    /var/folders/62/3px_xsd56ml5gz18lp8dptjc0000gv/T//ccDThXFx.s:7607:cannot use register index with PC-relative addressing -- ldr r12,[pc,r12]' /var/folders/62/3px_xsd56ml5gz18lp8dptjc0000gv/T//ccDThXFx.s:7609:selected processor does not supportcfldrdeq mvd15,[r12],#992'

1

1 Answers

2
votes

It makes more sense if you know of the small gotcha surrounding reading the PC: most instructions that read PC see a value of address_of_current_instruction+8 (except +4 in thumb mode, and ldm in ARM mode might be either +8 or +12 IIRC).

cfldrdeq mvd15, [r12], #992 is not meant to be an instruction; it's a relative relocation that points to a relocation the DATA section. In the DATA section, there'll be a dynamic relocation that points to the actual address. Typical seudocode looks something like this

  ldr r12,[pc,#small_offset_to_foo]
  ldr r12,[pc,r12]
  bx r12

  ... a short distance away ...

foo:
  int relative_offset_of_bar_from_the_second_ldr
  ... a galaxy far far away ...

bar:
  int pointer_to_the_actual_syscall

I do not know why the disassembly for syscall() places "foo" between ldr r12,[pc,r12] and bx r12, causing the branch over the non-instruction "foo".

It is also worth mentioning that simply pasting the code shown will almost certainly not work: you don't have the relocation that points to the actual implementation of syscall (in a debugger, step past bx r12 and you should get there); you'll just branch to some randomish address.

The error "cannot use register index with PC-relative addressing" is apparently because you're compiling in Thumb mode (the listing is ARM code). As for cfldrdeq, I believe it's just a conditional cfldrd instruction (the "eq" is a condition code), which Google suggests is related to a the Cirrus Logic "Maverick" processor series.