3 ms·
As other comments have noted, the asm statement needs to have its input/output registers specified to ensure the compiler doesn't erase the "unused" values. Wo
by jmillikin 2y ago
As other comments have noted, the asm statement needs to have its input/output registers specified to ensure the compiler doesn't erase the "unused" values.
Working example: https://john-millikin.com/unix-syscalls#linux-x86-64-gnu-c https://john-millikin.com/unix-syscalls#linux-x86-64-gnu-c
Adapted to use main():
static const int STDOUT = 1;
static const int SYSCALL_WRITE = 1;
static const char message[] = "Hello, world!\n";
static const int message_len = sizeof(message);
int main() {
register int rax __asm__ ("rax") = SYSCALL_WRITE;
register int rdi __asm__ ("rdi") = STDOUT;
register const char *rsi __asm__ ("rsi") = message;
register int rdx __asm__ ("rdx") = message_len;
__asm__ __volatile__ ("syscall"
: "+r" (rax)
: "r" (rax), "r" (rdi), "r" (rsi), "r" (rdx)
: "rcx", "r11");
return 0;
}
Test with:
$ gcc -o hello hello.c
$ ./hello
Hello, world!
- im3w1l 2y agoOr just int main(void) { asm volatile("syscall" : : "a"(1), "d"(14), "D"(1), "S"("hello world!\n")); return 0; } Though the clobber list is weak spot, I don't know exactly what it should have in this case.
- jart 2y agoYou want: long ax; asm volatile("syscall" : "=a"(ax) : "0"(1), "D"(1), "S"("hello world!\n"), "d"(14)); You can also say: long ax = 1; asm volatile("syscall" : "+a"(ax) : "D"(1), "S"("hello world!\n"), "d"(14)); https://justine.lol/dox/rmsiface.txt https://justine.lol/dox/rmsiface.txt
- jart 2y agoGot some sleep and took a second look. You actually want: long ax = 1; asm volatile("syscall" : "+a"(ax) : "D"(1), "S"("hello world!\n"), "d"(14) : "rcx", "r11"); Sorry folks! Note also this only works on Linux. On BSDs for example, even if you change the magic number, BSDs may clobber all the call-clobbered registers. So with those OSes it's usually simplest to write an assembly stub like this: my_write: mov $4,%eax syscall ret
- JonChesterfield 2y agoI don't suppose you know the syscall clobbered list for aarch64 Linux? Can't find it documented anywhere and not sure how to dig it out of the kernel A sibling comment pointed at https://chromium.googlesource.com/linux-syscall-support/+/refs/tags/v2022.10.12/linux_syscall_support.h https://chromium.googlesource.com/linux-syscall-support/+/re... which suggests none are clobbered outside of the arguments used by a given call which is possible but seems unlikely
- jart 2y agoI think that's accurate. Example code: static privileged int GetPid(void) { int res; #ifdef __x86_64__ asm volatile("syscall" : "=a"(res) : "0"(__NR_linux_getpid) : "rcx", "r11", "memory"); #elif defined(__aarch64__) register long res_x0 asm("x0"); asm volatile("mov\tx8,%1\n\t" "svc\t0" : "=r"(res_x0) : "i"(__NR_linux_getpid) : "x8", "memory"); res = res_x0; #endif return res; } You should be fine.