ARM64 – Memory mapping a file

  arm64, assembly, c++, dynamic-loading, mmap

I am using the mmap system call which maps a file into memory. The function load_asm_code first compiles the generated code and then maps it into memory. The variable buf is a pointer to the mapped area. Now the problem is that before I call the test function (that is mapped into memory) I need to add a 0x40 offset to be at the start address of this function. How can I fix it?

// g++ main.cpp -o main
#include <iostream>
#include <sys/mman.h>
#include <spawn.h>
#include <sys/wait.h>
extern char **environ;

void * load_asm_code(char const*  generated_code){
    /* write generated code to .asm text file */
    char const* file_name = "generated_code.asm"; 
    FILE *assembly = fopen(file_name, "w");
    fprintf ( assembly, "%s", generated_code );
    fclose(assembly);

    /* compile generated_code.asm file */

    char command[128];
    sprintf(command, "as -o generated_code.o %s", file_name); // run this on an ARM based device
    pid_t child_pid;
    char  *argv[] = {(char* )"sh", (char* )"-c", command, NULL};
    posix_spawn ( &child_pid, "/bin/sh", NULL, NULL, argv, environ );
    waitpid ( child_pid, NULL, 0 );

    /* Memory-map the file. */

    size_t size = 2048;
    void *buf = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
    FILE *mcode = fopen ( "generated_code.o", "rb" );
    fread ( buf, size, 1, mcode );
    mprotect ( buf, size, PROT_READ | PROT_EXEC );
    return buf;
}

typedef int64_t (*Func)(void);  // pointer to a function 

void compile() {
    char const*  generated_code = {"test:nmov x0, 5nretn"}; 
    // load into memory
    Func test = (Func) load_asm_code (generated_code);
    // call test function
    int64_t result = test();
    std::cout << result << std::endl; // result = 5
}

int main() {
    compile();
    return 0;
}

generated_code.asm

test:
    mov x0, 5
    ret

As you can see, load_asm_code function returns 0xfffff7ff2000 address that points to illegal instruction:

enter image description here

To fix this, I have to add a 0x40 offset and it is now working as this jumps directly at 0xfffff7ff2040:

    test = test + 0x40; // before I call test function I have to add 0x40, why?

Note: I also tested it on the x86-64 machine( using nasm ) and works as expected.

Source: Windows Questions C++

LEAVE A COMMENT