C(x86_64,tcc),7个字节
main=6;
受到这个答案的启发。
在线尝试!
这个怎么运作
生成的程序集如下所示。
.globl main
main:
.long 6
请注意,TCC不会在数据段中放置定义的“功能” 。
编译后,_start将照常指向main。当执行结果程序时,它期望main中的代码并找到little-endian(!)32位整数6,该整数被编码为0x06 0x00 0x00 0x00。第一个字节– 0x06 –是无效的操作码,因此程序以SIGILL终止。
C(x86_64,gcc),13个字节
const main=6;
在线尝试!
这个怎么运作
如果没有const修饰符,则生成的程序集将如下所示。
.globl main
.data
main:
.long 6
.section .note.GNU-stack,"",@progbits
GCC的链接器将最后一行视为生成的对象不需要可执行堆栈的提示。由于main已明确放置在数据段中,因此它包含的操作码不可执行,因此程序将终止SIGSEGV(分段错误)。
删除第二行或最后一行将使生成的可执行文件按预期工作。最后一行可以用编译器标志忽略-zexecstack
(在线尝试!),但这花费12个字节。
一个较短的替代方法是使用const修饰符声明main,从而导致以下汇编。
.globl main
.section .rodata
main:
.long 6
.section .note.GNU-stack,"",@progbits
这无需任何编译器标志即可工作。请注意,这main=6;
会在data中写入定义的“函数” ,但是const修饰符使GCC 改为在rodata中写入它,(至少在我的平台上)它可以包含代码。
raise(SIGILL)
?