Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't force the use of 64-bit registers in GCC inline assembly

I'm trying to make some things with GCC Inline Assembly, in this case, make a Syscall, but I want to force use of 64bit registers (rax, rdi, rsi, ...) instead of 32bit ones (eax, edi, ...), but I tried a lot of ways, and nothing.

void syscall(uint64_t arg1, uint64_t arg2) {
   // arg1 -> rax        arg2 -> rdi
   __asm__("syscall" : : "a" (arg1), "D" (arg2));
}

When I compile that I get:

mov eax, 60
syscall

I'm in a function, so "edi" is being get from arguments, but like you can see is "eax", I want to use rax.

How can I force 64bit registers instead of 32bit ones?

like image 748
Eduardo José Gómez Hernández Avatar asked Jul 18 '17 18:07

Eduardo José Gómez Hernández


People also ask

What is__ asm__ in C?

The __asm keyword invokes the inline assembler and can appear wherever a C or C++ statement is legal. It cannot appear by itself. It must be followed by an assembly instruction, a group of instructions enclosed in braces, or, at the very least, an empty pair of braces.

What is asm function in C?

The asm statement allows you to include assembly instructions directly within C code. This may help you to maximize performance in time-sensitive code or to access assembly instructions that are not readily available to C programs. Note that extended asm statements must be inside a function.

Why do 64-bit registers start with R?

R just stands for "register". The AMD64 ISA extension added 8 additional general-purpose registers, named R8 through R15 . The 64-bit extended versions of the original 8 registers had an R prefix added to them for symmetry. E stands for "extended" or "enhanced".

Which is a 64bit general-purpose register?

General-purpose registers (64-bit naming conventions)Edit 64-bit x86 adds 8 more general-purpose registers, named R8, R9, R10 and so on up to R15. R8–R15 are the new 64-bit registers. R8D–R15D are the lowermost 32 bits of each register. R8W–R15W are the lowermost 16 bits of each register.


Video Answer


1 Answers

This actually sets the RAX register to 60:

mov eax, 60

Writing to EAX always clears the upper 32-bit half of the 64-bit register. This is not like AH and AL, where writes preserve the rest of the register.

If you absolutely want a move to RAX, you need to use something like this:

static inline __attribute__ ((always_inline)) void
syscall(uint64_t arg1, uint64_t arg2)
{
   __asm__("mov rax, %0; syscall" : : "i" (arg1), "D" (arg2) : "rax");
}

Note that gas will still assemble this as a 32-bit immediate move.

like image 174
Florian Weimer Avatar answered Sep 29 '22 20:09

Florian Weimer