0

I am not able to figure out what does different imm value after svc mean. e.g.

svc.n #c6
svc.n #ac

Can anyone please help?

Nee
  • 159
  • 10
  • What is the origin of this data? Is it assembler source? If so, for which assembler? Is it disassembler source? Then what is the target platform? `SVC` (supervisor call) and also `SWI` (software interrupt) have a 'function' number. Which just 'free' space in the opcode to place a value, as per @cooperised. – artless noise May 03 '23 at 19:20

1 Answers1

1

The immediate does nothing at all. It's just encoded into the instruction, so if you want it you can get it.

So, if you only have a single SVC handler, the immediate is arbitrary. If you have multiple handlers and need to invoke the right one, you need to find the instruction that generated the SVC IRQ and dismantle it to find the immediate.

For example, on ARMv7m:

SVC_Handler
    ; Link register contains the 'exit handler mode' code
    ; Bit 2 tells whether the MSP or PSP was in use
    TST     lr, #4
    MRSEQ   r0, MSP
    MRSNE   r0, PSP
    ; r0 now contains the SP that was in use
    ; Return address is on the stack: load it into r1
    LDR     r1, [r0, #24]
    ; Use the return address to find the SVC instruction
    ; SVC instruction contains an 8-bit code
    LDRB    r1, [r1, #-2]
    ; Immediate from the SVC instruction is now in r1 to do whatever with

You could then use the immediate to index into a jump table, for example.

cooperised
  • 2,404
  • 1
  • 15
  • 18
  • As your example shows, this requires fetching from the instruction stream and decoding the value. Newer methods (post 1998) put the value in a register (typically R7). `svc #fnc` is called 'oabi' in Linux kernels. You also typically need to pass parameters and naturally this is r0-r3. Also, the kernel needs to save any registers. Because of this (already need to save and use registers), it is almost free to pass the function number in R7. So, your answer is technically correct (+1), but it is not recommended to use this structure if you are making a modern OS. – artless noise May 03 '23 at 11:16
  • I accept your point that there are other ways to do this and that those ways are often preferred, but your argument doesn't make sense entirely. The `SVC` instruction didn't even *exist* in 1998, and has existed in this form (with the unused immediate) since its inception, which suggests that the designers of the instruction intended it to be used in this way. – cooperised May 03 '23 at 13:46
  • .. and the implication of '1990s' is that the CPUs did not have the extensive cache structures, nor SMP that exist in present day. So, your example code could work for a Cortex-M system today, but it is not good advice for ARM systems with a cache, like many Cortex-A systems... and even for a Cortex-M, register passing is probably better. – artless noise May 03 '23 at 16:20
  • Indeed, most Cortex-M3 upwards have cache, and separate instruction and data caches of course. I don't see the logic of `SVC` being backwards compatible with `SWI` though, they have different mnemonics precisely because they are *not* compatible in operation. (And incidentally googling `SWI` is not necessary, I am sufficiently old that much of my early ARM assembly language experience was in the 90's!) – cooperised May 03 '23 at 20:50
  • This [page from arm](https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/svc) explicitly state that `SVC` is the same as `SWI`. Why do you think they are different? They are the same binary code. It is just toolchain/assembler that accepts two ascii texts for the same machine opcode. This https://godbolt.org/z/93rrecqfd example creates the same opcodes `ef000002` and `ef00002a` in arm32 mode. The only difference is #2 and #42 (or 0x2a). – artless noise May 04 '23 at 00:20