我想在Ubuntu上使用GNU C编译器编译这段C代码,而不链接任何标准库,只执行以下代码。
static void exit(long long code)
{asm inline
("movq $60,%%raxn"
"movq %[code],%%rdin"
"syscall"
:
:[code]"rm"(code)
:"rax"
,"rdi");}
static void write(long long fd,char *msg,long long len)
{asm inline
("movq $0x1,%%raxn"
"movq %[fd],%%rdin"
"movq %[msg],%%rsin"
"movq %[len],%%rdxn"
"syscall"
:
:[fd]"rm"(fd)
,[msg]"rm"(msg)
,[len]"rm"(len)
:"rax"
,"rdi"
,"rsi"
,"rdx");}
#define PRINT(msg) write(1,msg,sizeof(msg))
void _start()
{PRINT("Hello World.n");
exit(0);}
我用cc example.c -ffreestanding -nostartfiles -O3 -o example
编译。
当我调用输出文件时,我看到了很多使用strace
的额外系统调用,这些调用本不应该存在:
- brk
- arch_prctl
- 访问
- mmap
- arch_prctl
- mpprotect
然后我像这样编译:cc example.c -c -O3 -o example.o; ld example.o -o example
,它没有执行额外的系统调用。它甚至使文件大小变小了一些。
其objdump -d
完全相同。在objdump -D
中,与第二种情况相比,我在第一种情况下发现了一些额外的符号(_DYNAMIC、__GNU_EH_FRAME_HDR、.inep(,但在代码中仍然没有任何额外系统调用的迹象。
你知道为什么我用cc example.c -ffreestanding -nostartfiles -O3 -o example
而不是用cc example.c -c -O3 -o example.o; ld example.o -o example
得到额外的系统调用吗?
我发现了发生的事情。
如果我用cc example.c -ffreestanding -nostartfiles -O3 -o example
编译代码,编译器会生成一个动态链接的可执行文件。动态链接的可执行文件有一个.interp
部分。这就是我在objdump -D
中看到的。
动态链接的可执行文件通过程序解释器和动态链接器执行。我看到的其他系统调用来自动态链接器。我仍然不知道为什么可执行文件想要动态链接一个不链接任何库并且想要独立的程序中的任何内容。
如果您不希望动态链接器进行额外的系统调用,那么您应该为gcc提供额外的-static
选项。如果没有发生动态链接,编译器不会自动执行此操作。