Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

How do I call a global C function pointer in NASM without warnings?

Given main.c:

#include <stdio.h>

void (*fn_ptr)(void);

void foo(void);

void bar(void) {
    printf("bar\n");
}

int main(void) {
    fn_ptr = bar;
    foo();
}

and foo.s:

extern fn_ptr

global foo
foo:
    mov rax, fn_ptr
    call [rax]
    ret

we can run and compile it like so:

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

clear &&
nasm foo.s -f elf64 -O0 &&
clang main.c foo.o -z noexecstack &&
./a.out

which successfully prints bar, but also prints a warning:

/usr/bin/ld: foo.o: warning: relocation against `fn_ptr' in read-only section `.text'
/usr/bin/ld: warning: creating DT_TEXTREL in a PIE
bar

I couldn’t find any online examples of calling global function pointers in NASM, and changing it to mov rax, fn_ptr wrt ..plt or call [fn_ptr wrt ..plt] prints this error:

foo.s:7: error: ELF format cannot produce non-PC-relative PLT references

(For anyone wondering what warning the -z noexecstack gets rid of):

/usr/bin/ld: warning: foo.o: missing .note.GNU-stack section implies executable stack
/usr/bin/ld: NOTE: This behaviour is deprecated and will be removed in a future version of the linker

>Solution :

From comments; I can now type answer.

The following assembly instructions don’t work:

    mov rax, fn_ptr wrt ..plt
    call fn_ptr wrt ..plt
    call [fn_ptr wrt ..plt]

But these do:

    mov rax, [rel fn_ptr wrt ..plt]
    call [rel fn_ptr wrt ..plt]

The ELF format error is true. I’m surprised it can’t handle mov rax, fn_ptr wrt ..plt but call [fn_ptr wrt ..plt] definitely cannot work. There’s no such instruction as call qword but only call rel dword and call [rel dword].

The mov instruction that surprises me that it doesn’t work wouldn’t get you out of the problem anyway; that’s asking for an absolute fixup in the text segment to refer to the plt by absolute address. So if it did work that’s still a warning.

What you want to access variables elsewhere is always something with rel so you get a PIC-relative reference to the fixup area. Basic forms:

   lea rax, [rel fn_ptr wrt ..plt]  ; gets the absolute address of the address of fn_ptr
   mov rax, [rel fn_ptr wrt ..plt]  ; gets the absolute address of fn_ptr
   call [rel fn_ptr wrt ..plt]      ; calls fn_ptr

If it’s a variable not a function you will find there’s no memory indirect load or store instruction (that is, you can’t use a value in memory as a pointer) but can only do this via a register so accessing a global variable in another library always takes two instructions.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading