与另外this个问题有关。我正在尝试在gem5中运行这个简单的C程序:
int main() {
int a=1, b=2;
int c=a+b;
return c;
}
它失败了,因为gem5没有实现一些系统调用。
我的问题是,为什么像这样的简单程序需要系统调用?这应该在没有问题的情况下裸机运行。有没有一种方法可以编译该代码以避免系统调用?我正在使用arm-linux-gnueabi-gcc -static -DUNIX进行编译。
答案 0 :(得分:11)
没有系统调用,程序无法退出。它的工作方式通常是这样的:
// Not how it's actually implemented... just a sketch.
void _start() {
char **argv = ...;
int argc = ...;
// ... other initialization code ...
int retcode = main(argc, argv);
exit(retcode);
}
具体细节取决于操作系统,但是exit()
(它终止进程)通常必须是系统调用或通过系统调用实现。
请注意,对于“托管” C实现,而不是“独立” C实现,这是正确的,并且高度依赖于操作系统。有独立的C实现可以在裸机上运行,但是托管C实现通常需要一个操作系统。
您可以在没有标准库且没有运行时的情况下进行编译,但是您的入口点无法返回...没有运行时就无法返回。
通常可以编译能够运行裸机的程序。
使用-ffreestanding
。这使得GCC生成的代码不会假定标准库可用(并具有其他效果)。
使用-nostdlib
。这将阻止GCC与标准库链接。请注意,无论如何都可能生成memcmp
,memset
,memcpy
和memmove
调用,因此您可能必须自己提供这些调用。
此时,您可以编写程序,但是通常必须使用_start
而不是main
:
void _start(void) {
while (1) { }
}
请注意,您无法从_start
返回!考虑一下...无处可寻。当您编译这样的程序时,您会发现它不使用任何系统调用且没有加载程序。
$ gcc -ffreestanding -nostdlib test.c
我们可以验证它没有加载任何库:
$ ldd a.out statically linked $ readelf -d a.out Dynamic section at offset 0xf30 contains 8 entries: Tag Type Name/Value 0x000000006ffffef5 (GNU_HASH) 0x278 0x0000000000000005 (STRTAB) 0x2b0 0x0000000000000006 (SYMTAB) 0x298 0x000000000000000a (STRSZ) 1 (bytes) 0x000000000000000b (SYMENT) 24 (bytes) 0x0000000000000015 (DEBUG) 0x0 0x000000006ffffffb (FLAGS_1) Flags: PIE 0x0000000000000000 (NULL) 0x0
我们还可以看到它不包含任何进行系统调用的代码:
$ objdump -d a.out a.out: file format elf64-x86-64 Disassembly of section .text: 00000000000002c0 <_start>: 2c0: eb fe jmp 2c0 <_start>
答案 1 :(得分:3)
我的问题是,为什么像这样的简单程序需要系统调用?
运行时加载器ld.so
进行系统调用。 C运行时执行系统调用。做strace <application>
看看。
答案 2 :(得分:1)
您可能要检出gcc的一些参数。除其他外:
我的问题是,为什么像这样的简单程序需要系统调用?
因为进入主程序和退出程序是基于syscalls的。
答案 3 :(得分:0)
使用arm-unknown-linux-uclibcgnueabi编译可解决此问题。显然,uclibc实现未使用gem5尚未实现的系统调用。