Re:Hello world in C inline assembly (2020)
by rep_lodsb on Monday June 17, 2024 @03:51AM
(#40703243)
With an older version, it works (as long as there is no optimization at least, with -O2 all the register init code disappears):
$ gcc -v
... gcc version 10.2.1 20210110 (Debian 10.2.1-6)
0000000000001125 <main>:
1125: 55 push %rbp
1126: 48 89 e5 mov %rsp,%rbp
1129: b8 01 00 00 00 mov $0x1,%eax
112e: bf 01 00 00 00 mov $0x1,%edi
1133: 48 8d 35 ca 0e 00 00 lea 0xeca(%rip),%rsi # 2004 <_IO_stdin_used+0x4>
113a: ba 0e 00 00 00 mov $0xe,%edx
113f: 0f 05 syscall
No idea why a newer version produces worse code in this case (though of course, this way of doing inline assembly isn't "correct" anyway, so nasal demons may result)The exact same thing happens with GCC 12 with 32-bit MIPS.
#include <asm/unistd.h>
char msg[] = "hello, world!\n";
int main(void)
{
register int syscall_no asm("v0") = __NR_write;
register int arg1 asm("a0") = 1;
register char *arg2 asm("a1") = msg;
register int arg3 asm("a2") = sizeof(msg) - 1;
asm("syscall");
return 0;
}
root@OpenWrt:~# objdump --disassemble=main
...
00400580 <main>:
400580: 27bdfff8 addiu sp,sp,-8
400584: afbe0004 sw s8,4(sp)
400588: 03a0f025 move s8,sp
40058c: 24020fa4 li v0,4004
400590: 24040001 li a0,1
400594: 3c020041 lui v0,0x41
400598: 24450650 addiu a1,v0,1616
40059c: 2406000e li a2,14
4005a0: 0000000c syscall
. . . . . .
The code biffs rax when it loads the string address, so the system call number is lost, and the code ends up not printing anything. Moving the string assignment to be the very first line in main fixes it.
BTW, Clang 14 with no optimization accepts the code without issue but compiles it without using any of the registers; it just stores the values to memory locations and runs the syscall opcode. With O1 optimization or higher, it optimizes away everything except the syscall opcode.