I just saw this here
#include
int main(int argc, char *argv[printf(\"Hello, world!\\n\")]) {}
What this does is print \"Hello
char *argv[printf("Hello, world!\n")])
printf()
returns the number of characters printed.
So
int main(int argc, char *argv[printf("Hello, world!\n")]) {}
is equivalent to
int main(int argc, char *argv[14]) {}
plus a call to printf()
which prints "Hello World"
The code makes use of C99's variable-length array feature, which lets you declare arrays whose size is known only at run-time. printf
returns an integer equal to the number of characters that were actually printed, so the code prints "Hello, world!" first and uses the return value as the size of argv
. The main
function itself does nothing. The actual call to printf
itself probably goes into the startup code generated by the compiler, which in turn calls main
.
Edit: I just checked the disassembly of the code generated by gcc
and it appears that the call to printf
goes inside main
itself, before any other code.
I'm no C expert, but it looks like the command line arguments are declared at the same time as main
.
If I figure out how the compiler parsed it, I'll update this, but at least there needs to be no guesswork as to how it compiled:
objdump --disassemble /tmp/hello (edited):
080483c4 <main>:
80483c4: 55 push %ebp
80483c5: 89 e5 mov %esp,%ebp
80483c7: 83 e4 f0 and $0xfffffff0,%esp
80483ca: 83 ec 10 sub $0x10,%esp
80483cd: b8 a0 84 04 08 mov $0x80484a0,%eax
80483d2: 89 04 24 mov %eax,(%esp)
80483d5: e8 22 ff ff ff call 80482fc <printf@plt>
80483da: c9 leave
80483db: c3 ret
80483dc: 90 nop
80483dd: 90 nop
80483de: 90 nop
80483df: 90 nop
Since Linux executables are based normally at 0x8048000, the address of the argument to printf is at an offset of 0x00004a0 from the start of the binary:
xxd /tmp/hello | grep 00004a0
00004a0: 4865 6c6c 6f2c 2077 6f72 6c64 210a 0000 Hello, world!...
So, the address of the string is pushed, and printf is called with that one arg. Nothing magical at that level, so all the fun stuff was done by gcc.