Hacker News new | ask | show | jobs
by tobinfricke 4843 days ago
whoah - I find that construction astonishing.

My gcc compiles it with only this warning:

  foo.c:2:6: warning: ‘main’ is usually a function [-Wmain]
hah!
4 comments

It won't execute though:

    [23] .got.plt          PROGBITS        0804954c 00054c 000014 04  WA  0   0  4
    [24] .data             PROGBITS        08049560 000560 000010 00  WA  0   0  4  <---
    [25] .bss              NOBITS          08049570 000570 000008 00  WA  0   0  4

    66: 0804840a     0 FUNC    GLOBAL HIDDEN   14 __i686.get_pc_thunk.bx
    67: 08049568     5 OBJECT  GLOBAL DEFAULT   24 main  <---
    68: 08048278     0 FUNC    GLOBAL DEFAULT   12 _init
The main symbol is a relocation in .data, not .text. Which is as you would expect given that declaration. You might be able to get around that by doing something like

    unsigned char code[] = { 0xf0, 0x0f, 0xc7, 0xc8, 0xc3 };

    int main(void)
    {
        ((void (*)())code)();
        return 0;
    }
But these days NX will usually ruin the fun.
Works if you add this line:

char main[] __attribute__((section(".text")));

(You get a warning from the assembler.)

So it does.

I didn't know gcc attributes included that kind of thing. I've really gotta dig though the manual some time.

Historically, we have http://www.ioccc.org/1984/mullender.c use this technique in the Obfuscated C Code Contest in 1984 (hint at http://www.ioccc.org/1984/mullender.hint)
main is probably the only symbol this works with, data is generally put into non-executable sections/pages.
Others will probably be possible, albeit compiler-specific. The IBM xlc compiler / linker chooses to implement C static initializers by simply prefixing them with __sinit_, which tells the linker to automatically glue a call to it into init before calling main. I haven't tried this specific trick in combination with that, but if I had to make a bet it would work exactly the same way.
mainisusuallyafunction.blogspot.com