https://gcc.gnu.org/bugzilla/show_bug.cgi?id=63318
Andrew Pinski <pinskia at gcc dot gnu.org> changed: What |Removed |Added ---------------------------------------------------------------------------- Status|UNCONFIRMED |RESOLVED Resolution|--- |INVALID --- Comment #5 from Andrew Pinski <pinskia at gcc dot gnu.org> --- This is still invalid. Even though this is not fully correct: #include <unistd.h> int main(void) { const char hello[] = "Hello World!\n"; const size_t hello_size = sizeof(hello); ssize_t ret; asm volatile ( "movl $1, %%eax\n\t" "movl $1, %%edi\n\t" "movq %1, %%rsi\n\t" "movl %2, %%edx\n\t" "syscall" : "=&a"(ret) : "g"(hello), "g"(hello_size) : "%rdi", "%rsi", "%rdx", "%rcx", "%r11" ); return 0; } It works as you mark operand one as being clobbered early (which is kinda correct as you change eax the very first instruction. Really the correct way is to do: #include <unistd.h> static inline syscall_1(long long syscallnum, long long arg0, long long arg1, long long arg2) { register long long syscallnum_ __asm__("eax"); register long long arg0_ __asm__("edi"); register long long arg1_ __asm__("rsi"); register long long arg2_ __asm__("edx"); syscallnum_ = syscallnum; arg0_ = arg0; arg1_ = arg1; arg2_ = arg2; asm volatile ( "syscall" : "+r"(syscallnum_) : "r"(arg0_), "r"(arg1_), "r"(arg2_) : "%rcx", "%r11", "memory" ); return syscallnum_; } int main(void) { const char hello[] = "Hello World!\n"; const size_t hello_size = sizeof(hello); ssize_t ret; ret = syscall_1(/*write*/1, /*fileno*/1, hello, hello_size); return 0; } Note I might have swapped syscallnum and arg0.