
[英]How can I measure CPU time in C++ on windows and include calls of system()?
[英]How can I make Linux system calls from a C/C++ application, without using assembly, and in a cpu-independent manner? [closed]
我正在寻找一个程序,该程序将需要对进程进行低级工作(例如,使用fork系统调用等)。 该程序将用C ++编写,并且只能在Linux上运行。 理想情况下,这将是整个CPU架构(即86,x86_64和ARM)与只不过是重新编译更便携,但我只真正需要x86_64的支持。
由于每个Linux系统调用都带有多个参数,并在cpu寄存器中返回多个参数(通常只有1个返回值),因此每个系统调用的C函数包装器可能很容易实现。 另外,由于AFAIK(在内核中实现)的系统调用具有相同的参数和返回值,因此,如果不同的程序集级实现,则可以公开相同的C接口。
这样的事情存在吗? 如果是这样,我如何访问它?
它的文档在哪里(可用功能的列表,带有说明的参数以及对功能的确切说明)?
libc已经包含了您要寻找的包装函数。 其中的许多原型位于POSIX指定的#include <unistd.h>
。
C是Unix(和Linux)上的低级系统程序的语言,因此自Unix诞生以来,这就是事实。 (在libc中提供包装函数比教导编译器函数调用和系统调用之间的区别更容易,并且允许在errno
上设置errno
。它还允许LD_PRELOAD
技巧来拦截用户空间中的系统调用。)
系统调用的手册页在第2节中,而库函数的使用手册页在第3节中(库功能可能会也可能不会使用系统调用:math.h cos(3)
,ISO C stdio printf(3)
和fwrite(3)
,与POSIX write(2)
)相比。
execve(2)
是系统调用。
请参阅execl(3)
并且朋友也是libc的一部分,并最终调用execve(2)
。 它们是它们之上的便利包装,用于构造argv数组,执行$PATH
查找以及传递当前进程的环境。 因此,它们被分类为函数,而不是系统调用。
有关概述,请参见syscalls(2)
,以及带有指向其手册页包装器的链接的系统Linux调用的完整列表 。 (我已经链接了Linux手册页,但是对于所有标准系统调用也有POSIX手册页。)
万一您没有链接libc,可以使用MUSL的syscall2
/ syscall3
/ etc等宏(数字为arg计数)在任何平台上内联正确的asm。 您可以使用asm/unistd.h
__NR_write
获取系统电话号码。
但是请注意,原始的Linux系统调用与libc包装器提供的接口可能会有细微的差别。 例如,他们不会检查pthreads取消点,并且brk
/ sbrk
需要libc在用户空间进行簿记。
有关使用MUSL宏的可移植原始sys_write()
内联包装,请参见Android中的SYSCALL_INLINE 。
但是,如果像普通人一样使用libc来实现malloc
和printf
类的功能,则应仅使用其系统调用包装器功能。
syscalls(2)手册页列出了Linux上可用的每个系统调用 (并提供了每个系统调用的链接)。 他们中的大多数人都在libc中拥有C包装器(例如, write(2) , fork(2)等)。 一个典型的系统调用包装管理调用约定 (请参见x86 ABI规格在这里 ),并设置错误号(3)上的失败。 ALP是Linux系统编程的不错的入门书,但是您可能会发现较新的东西(ALP并没有提及最近的系统调用,例如signalfd(2),因为在编写ALP时,这些系统调用不存在)。
Linux上的大多数C标准库实现(例如,您的libc.so
)为系统调用提供POSIX接口。 而且它们通常是免费软件 (例如GNU glibc或musl-libc等)。 因此,如果您关心棘手的实现细节(通常不应该这样做),请研究(或改进)其源代码。
libc没有接口很少的系统调用,因为它们是不常见的,并且在C代码中没有多大意义。 例如, sigreturn(2) , socketcall(2) , gettid(2) (或namedat2(2) ;您将改用renameat
)。 如果确实需要直接使用它们(这是不可能的,并且很可能是程序中的设计错误),则需要编写一些汇编代码(特定于您的系统和指令集体系结构),或者使用syscall(2) 。
一些系统调用随时间演变或出现在后来的内核中,但十年前还没有退出。 系统调用号(由内核了解)可能在一些asm/unistd_64.h
文件中列出(您可能不想包含该文件,请改用sys/syscalls.h
)。 例如,将preadv(2) syscall重定向到__NR_preadv
或__NR_preadv2
但是您的libc应该足够聪明,可以做到最好。
在旧内核中不存在一些新的系统调用。 在这种情况下,最新的libc
可能会“模仿”它们。 但是您大多数时候应该信任您的libc
实现(和您的内核)。 实际上, libc.so
是Linux系统和发行版的基石(并且最好将其用作共享库,并避免由于nsswitch.conf(5)进行静态链接)。 如果您需要详细了解共享库的工作原理,请阅读Drepper的“ 如何编写共享库” 。 如果您想了解有关Userland中系统调用机制的详细信息,请参见Assembler HowTo 。
在几乎所有情况下,您都以某种方式编写可移植的C代码,并且仅使用syscalls(2) (具有C包装程序)和intro(2)中记录的功能 。
实际上,您的类shell程序将使用fork(2) , execve(2) , waitpid(2)等。所有这些都由POSIX指定,并且在libc
可用(并包装)。 您可以研究一些免费软件外壳的源代码以获取启发。
为了在Linux上进行C编程,请将syscalls(2)中列出的具有C包装程序的所有函数视为系统调用(例如,几乎所有函数)。 因此, socket(2)或bind(2)实际上也是系统调用(即使两者都在内部使用socketcall(2) ,您也不会直接调用它们)请注意system(3) -历史记录的命名非常差的函数原因- 不是系统调用。 它在fork(2) , execve(2) , signal(2) , waitpid(2)等之上实现,并需要/bin/sh
...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.