I am trying to write a function, which prints string to stdout without importing <cstdio> or <iostream>.
For this I am trying to pass 2 parameters (const char* and const unsigned) to the asm(...) section in c++ code. And calling write syscall.
This works fine:
void writeInAsm(const char* str, const unsigned len) {
register const char* arg3 asm("rsi") = str;
register const unsigned arg4 asm("rdx") = len;
asm(
"mov rax, 1 ;" // write syscall
"mov rdi, 1 ;" // file descriptor 1 - stdout
"syscall ;"
);
}
Is it possible to do this without those first two lines in which I assign parameters to registers?
Next lines don't work:
mov rsi, str;
// error: relocation R_X86_64_32S against undefined symbol `str' can not be used when making a PIE object; recompile with -fPIC
// compiled with -fPIC - still got this error
mov rsi, [str];
// error: relocation R_X86_64_32S against undefined symbol `str' can not be used when making a PIE object; recompile with -fPIC
// compiled with -fPIC - still got this error
mov rsi, dword ptr str;
// incorrect register `rsi' used with `l' suffix
mov rsi, dword ptr [str];
// incorrect register `rsi' used with `l' suffix
I am compiling with g++ -masm=intel. I am on x86_64 Intel® Core™ i7-7700HQ CPU @ 2.80GHz × 8, Ubuntu 19.04 5.0.0-36-generic kernel (if it matters).
$ g++ --version
g++ (Ubuntu 8.3.0-6ubuntu1) 8.3.0
Edit: According to Compiler Explorer, the next can be used:
void writeInAsm(const char* str, const unsigned len) {
asm(
"mov rax, 1 ;"
"mov rdi, 1 ;"
"mov rsi, QWORD PTR [rbp-8] ;"
"mov edx, DWORD PTR [rbp-12] ;"
"syscall ;"
);
}
But is it always rbp register and how will it change with larger number of parameters?