C (x86_64), 11, 30, 34, or 34+15 = 49 bytes
main[]="/";
c=6;main(){((void(*)())&c)();}
main(){int c=6;((void(*)())&c)();}
I've submitted a couple of solutions that use library functions to throw SIGILL
via various means, but arguably that's cheating, in that the library function solves the problem. Here's a range of solutions that use no library functions, and make varying assumptions about where the operating system is willing to let you execute non-executable code. (The constants here are chosen for x86_64, but you could change them to get working solutions for most other processors that have illegal instructions.)
06
is the lowest-numbered byte of machine code that does not correspond to a defined instruction on an x86_64 processor. So all we have to do is execute it. (Alternatively, 2F
is also undefined, and corresponds to a single printable ASCII character.) Neither of these are guaranteed to always be undefined, but they aren't defined as of today.
The first program here executes 2F
from the read-only data segment. Most linkers aren't capable of producing a working jump from .text
to .rodata
(or their OS's equivalent) as it's not something that would ever be useful in a correctly segmented program; I haven't found an operating system on which this works yet. You'd also have to allow for the fact that many compilers want the string in question to be a wide string, which would require an additional L
; I'm assuming that any operating system that this works on has a fairly outdated view of things, and thus is building for a pre-C94 standard by default. It's possible that there's nowhere this program works, but it's also possible that there's somewhere this program works, and thus I'm listing it in this collection of more-dubious-to-less-dubious potential answers. (After I posted this answer, Dennis also mentioned the possibility main[]={6}
in chat, which is the same length, and which doesn't run into problems with character width, and even hinted at the potential for main=6
; I can't reasonably claim these answers as mine, as I didn't think of them myself.)
The second program here executes 06
from the read-write data segment. On most operating systems this will cause a segmentation fault, because writable data segments are considered to be a bad design flaw that makes exploits likely. This hasn't always been the case, though, so it probably works on a sufficiently old version of Linux, but I can't easily test it.
The third program executes 06
from the stack. Again, this causes a segmentation fault nowadays, because the stack is normally classified as nonwritable for security reasons. The linker documentation I've seen heavily implies that it used to be legal to execute from the stack (unlike the preceding two cases, doing so is occasionally useful), so although I can't test it, I'm pretty sure there's some version of Linux (and probably other operating systems) on which this works.
Finally, if you give -Wl,-z,execstack
(15 byte penalty) to gcc
(if using GNU ld
as part of the backend), it will explicitly turn off executable stack protection, allowing the third program to work and give an illegal operation signal as expected. I have tested and verified this 49-byte version to work. (Dennis mentions in chat that this option apparently works with main=6
, which would give a score of 6+15. I'm pretty surprised that this works, given that the 6 blatantly isn't on the stack; the link option apparently does more than its name suggests.)
raise(SIGILL)
? \$\endgroup\$Illegal instruction (core dumped)
. \$\endgroup\$