为什么一个简单的 C 程序需要系统调用?
Why would a simple C program need syscalls?
与 其他问题相关。我正在尝试 运行 gem5 中的这个简单的 C 程序:
int main() {
int a=1, b=2;
int c=a+b;
return c;
}
它失败了,因为 gem5 没有实现一些系统调用。
我的问题是,为什么像这样的简单程序需要系统调用?这应该 运行 裸机没有问题。有没有办法编译它以避免系统调用?我正在使用 arm-linux-gnueabi-gcc -static -DUNIX 来编译它。
My question is, why would a simple program like this require syscalls?
运行-time loader ld.so
进行系统调用。 C 运行-time 进行系统调用。做 strace <application>
看看。
没有系统调用,程序无法退出。它的工作方式通常是这样的:
// 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()
,终止进程,通常必须是系统调用或通过系统调用实现。
请注意,这适用于 "hosted" C 实现,而不适用于 "freestanding" C 实现,并且高度特定于操作系统。有独立的 C 实现可以 运行 在裸机上,但托管 C 实现通常需要一个操作系统。
你可以在没有标准库和没有 运行time 的情况下进行编译,但是你的入口点不能 return...没有 return 没有 运行 ]时间。
创建裸机程序
通常可以编译支持运行裸机的程序。
使用-ffreestanding
。这使得 GCC 生成的代码不假定标准库可用(并且有其他影响)。
使用-nostdlib
。这将阻止 GCC 与标准库链接。请注意,memcmp
、memset
、memcpy
和 memmove
调用可能无论如何都会生成,因此您可能需要自己提供这些。
此时您可以编写程序,但通常必须使用 _start
而不是 main
:
void _start(void) {
while (1) { }
}
请注意,您不能从 _start
return!想一想…… return 无处可去。当你编译这样的程序时,你会发现它没有使用任何系统调用,也没有加载程序。
$ 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>
您可能想要查看 gcc 的一些参数。其中:
- -独立
- -nostdlib
- -nodefaultlibs
My question is, why would a simple program like this require syscalls?
因为进入main和退出程序是基于系统调用的。
使用 arm-unknown-linux-uclibcgnueabi 编译解决了这个问题。显然 uclibc 实现没有使用 gem5 没有实现的系统调用。
与
int main() {
int a=1, b=2;
int c=a+b;
return c;
}
它失败了,因为 gem5 没有实现一些系统调用。
我的问题是,为什么像这样的简单程序需要系统调用?这应该 运行 裸机没有问题。有没有办法编译它以避免系统调用?我正在使用 arm-linux-gnueabi-gcc -static -DUNIX 来编译它。
My question is, why would a simple program like this require syscalls?
运行-time loader ld.so
进行系统调用。 C 运行-time 进行系统调用。做 strace <application>
看看。
没有系统调用,程序无法退出。它的工作方式通常是这样的:
// 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()
,终止进程,通常必须是系统调用或通过系统调用实现。
请注意,这适用于 "hosted" C 实现,而不适用于 "freestanding" C 实现,并且高度特定于操作系统。有独立的 C 实现可以 运行 在裸机上,但托管 C 实现通常需要一个操作系统。
你可以在没有标准库和没有 运行time 的情况下进行编译,但是你的入口点不能 return...没有 return 没有 运行 ]时间。
创建裸机程序
通常可以编译支持运行裸机的程序。
使用
-ffreestanding
。这使得 GCC 生成的代码不假定标准库可用(并且有其他影响)。使用
-nostdlib
。这将阻止 GCC 与标准库链接。请注意,memcmp
、memset
、memcpy
和memmove
调用可能无论如何都会生成,因此您可能需要自己提供这些。
此时您可以编写程序,但通常必须使用 _start
而不是 main
:
void _start(void) {
while (1) { }
}
请注意,您不能从 _start
return!想一想…… return 无处可去。当你编译这样的程序时,你会发现它没有使用任何系统调用,也没有加载程序。
$ 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>
您可能想要查看 gcc 的一些参数。其中:
- -独立
- -nostdlib
- -nodefaultlibs
My question is, why would a simple program like this require syscalls?
因为进入main和退出程序是基于系统调用的。
使用 arm-unknown-linux-uclibcgnueabi 编译解决了这个问题。显然 uclibc 实现没有使用 gem5 没有实现的系统调用。