cassemblyclanginline-assemblyarm64

Can you somehow grab a value from a register and put it into a C variable in C with the asm keyword for arm64 macOS assembly?


Can you somehow grab a value from a register and put it into a C variable in C with the asm keyword for arm64 macOS assembly?

I have seen code from other stack overflows that have already answered this question for another CPU's assembly so I was wondering if I could somehow do that on arm64 macOS Assembly


Solution

  • Here's an example in WSL/Linux:

    #include <inttypes.h>
    #include <stdio.h>
    
    void test(uint64_t u64)
    {
        uint64_t reg;
    
        // Read the first argument into a local variable. 
        // Constraints make sure we get the correct value even if the compiler moves registers around.
        asm volatile("" : "=r"(reg) : "D"(u64));
    
        (void)printf("reg: 0x%" PRIX64 "\n", reg);
        (void)printf("u64: 0x%" PRIX64 "\n", u64);
    }
    
    int main(void)
    {
        test(0xDEADBEEFCAFEBABELL);
        return 0;
    }
    
    $ gcc main.c -o main; ./main
    reg: 0xDEADBEEFCAFEBABE
    u64: 0xDEADBEEFCAFEBABE
    

    This may work for you. I was able to test with QEMU:

    #include <inttypes.h>
    #include <stdio.h>
    
    void test(uint64_t u64)
    {
        uint64_t reg;
    
        // Read the first argument into a local variable. 
        // Constraints make sure we get the correct value even if the compiler moves registers around.
        asm volatile("mov %0, %1" : "=r"(reg) : "r"(u64));
    
        (void)printf("reg: 0x%" PRIX64 "\n", reg);
        (void)printf("u64: 0x%" PRIX64 "\n", u64);
    }
    
    int main(void)
    {
        test(0xDEADBEEFCAFEBABELL);
        return 0;
    }
    
    $ aarch64-linux-gnu-gcc -static main.c -o main.arm64; qemu-aarch64 ./main.arm64;
    reg: 0xDEADBEEFCAFEBABE
    u64: 0xDEADBEEFCAFEBABE
    

    I can create a text dump of the disassembly, for your system, like this:

    $ aarch64-linux-gnu-gcc -S -O0 main.c -o main.s; aarch64-linux-gnu-objdump -d main.arm64 > disassembly.txt;
    

    Let's look at the disassembly text dump for asm volatile("" : "=r"(reg) : "r"(u64));:

    4007bc: f9400fe0  ldr x0, [sp, #24]
    4007c0: aa0003e0  mov x0, x0
    4007c4: f90017e0  str x0, [sp, #40]
    
    1. ldr x0, [sp, #24] loads value in u64 from the stack into register x0
    2. mov x0, x0 acts like a no-op
    3. str x0, [sp, #40] stores value from register x0 into reg on the stack

    Note: The compiler decides which registers to use for each variable, so there's no way to know exactly which physical register holds a value like u64.