I want to use a naked function in my C++ program using g++. Unfortunately g++, unlike VC++, does not support naked functions and the only way to manage this is to write your
Here's an example of a trick to achieve the "naked function" effect.
#include <stdio.h>
extern "C" int naked_func ();
static void
dummy ()
{
__asm__ __volatile__
(
" .global naked_func\n"
"naked_func:\n"
" movq $3141569, %rax\n"
" ret\n"
);
}
int
main ()
{
printf ("%d\n", naked_func ());
return 0;
}
This is my way to define a function in assembly, this does not need to have a seperate assembler-file nor you need to escape every newline. You can just copy the contents of the assembly files into the string-literal. Note: The raw multiline string literal is a C++11 feature (you also tagged C++). This is useful, if you want to compile everything in a single .c
-/.cpp
-file.
extern"C" int rand_byte(void);
asm (R"(
.globl rand_byte
rand_byte:
call rand
and eax, 255
ret
)");
You can only use a basic assembly-statement without additional parameters at global scope.
When using GCC or Clang and an arm processor, you are able to use [[gnu::naked]]
/__attribute__((naked))
.
[[gnu::naked]]
int rand_byte(void) {
asm volatile (R"(
push {lr}
bl rand
and r0, #255
pop {pc}
)");
};
The first way always allows to define naked functions. This also helps to make more portable code.
extern"C" int _cdecl rand_byte(void);
#if defined __x86__
// NOTE: the names are decorated with a '_' on windows 32-bit
// You can use extern"C" int _cdecl rand_byte() asm("rand_byte");
// to make the asm symbol name always be rand_byte, without an _
asm volatile (R"(
.globl _rand_byte
_rand_byte:
call rand
and eax, 255
ret
)");
#elif defined __x86_64__
asm volatile (R"(
.globl rand_byte
rand_byte:
call rand
and rax, 255 # eax works here, too. x86-32 and -64 could share the same source.
ret
)");
#elif defined __arm__
asm (R"(
.global rand_byte
rand_byte:
push {lr}
bl rand
and r0, #255
pop {pc}
)");
#else
#error There is no code for your platform yet...
#endif
I just want to add one thing to previous post. Imagine you want a function, that accept arguments: (something like
int add(int,int);
prototype)
segment .text
global add
add:
enter 0,0
mov eax,[ebp+8] ; first argument
mov ebx,[ebp+12] ; second argument
add eax,ebx
leave
ret
In C++ file:
extern "C" void foo(); // Stop name mangling games
int main() {
foo();
}
in "naked" asm file, for x86:
# modified from http://asm.sourceforge.net/howto/hello.html
.text # section declaration
.global foo
foo:
# write our string to stdout
movl $len,%edx # third argument: message length
movl $msg,%ecx # second argument: pointer to message to write
movl $1,%ebx # first argument: file handle (stdout)
movl $4,%eax # system call number (sys_write)
int $0x80 # call kernel
# and exit
movl $0,%ebx # first argument: exit code
movl $1,%eax # system call number (sys_exit)
int $0x80 # call kernel
.data # section declaration
msg:
.ascii "Hello, world!\n" # our dear string
len = . - msg # length of our dear string
Compile, assemble and link (with g++ rather than ld because it's much easier to do it that way for C++) and run:
ajw@rapunzel:/tmp > g++ -Wall -Wextra test.cc -c -o test.o
ajw@rapunzel:/tmp > as -o asm.o asm.S
ajw@rapunzel:/tmp > g++ test.o asm.o
ajw@rapunzel:/tmp > ./a.out
Hello, world!
If you want to pass arguments to your function or return anything you need to respect the calling conventions.