【问题标题】:Let the gcc compile syscalls in "int 0x80" way?让 gcc 以“int 0x80”方式编译系统调用?
【发布时间】:2013-03-27 08:06:20
【问题描述】:

代码在这里:

void main()
{
    _exit(0);
}

通过拆卸主要部分:

 80483d4:   55                      push   %ebp
 80483d5:   89 e5                   mov    %esp,%ebp
 80483d7:   83 e4 f0                and    $0xfffffff0,%esp
 80483da:   83 ec 10                sub    $0x10,%esp
 80483dd:   c7 04 24 00 00 00 00    movl   $0x0,(%esp)
 80483e4:   e8 17 ff ff ff          call   8048300 <_exit@plt>

据我所知,进行系统调用的方法是使用“int 0x80”,但我只能在这里找到“call 8048300 exit@plt”,那么如何更改 gcc 以使其在“int 0x80”中编译系统调用方式(我需要我的程序以这种方式调用系统调用)?

【问题讨论】:

  • 你为什么要问?你想达到什么目的??
  • void main() 在 C 的托管实现上是虚假的,相对于您的整体问题而言,这是一个小问题。只是吹毛求疵。
  • @BasileStarynkevitch 因为我想扫描我的程序的汇编代码以查找对系统调用的调用发生的位置,因此使用“int $0x80”时更容易检测。
  • @RandyHoward 感谢您的建议。
  • @Coaku 如果您想查看您的程序通过int 0x80 对内核进行的确切系统调用,请使用名为strace 的(binutils?)工具。它向您显示具有给定参数和返回值的确切系统调用,甚至在出现问题时为您解释 errno。对于库调用,您可以使用ltrace

标签: c linux gcc assembly system-calls


【解决方案1】:

您应该使用gcc -Wall(也可能使用-g 标志)进行编译。

这会给你更多警告,并且会指出一些简单的错误,比如缺少合适的#include

exit(3) 函数是一个库函数(使atexit 成为可能)。相应的系统调用是_exit(2),但在最近的Linux 上exit 调用exit_group(2)。所以你的例子错过了#include &lt;stdlib.h&gt;

当前的 Linux 实现通常不使用int 0x80,而是通过VDSO 或至少使用SYSENTERSYSCALL 机器指令。 YMMV。

作为Jeremy answered,您可以使用asm; (您可以为您正在使用的所有系统调用定义自己的标头,并让这些系统调用成为static inline 函数,执行一些asm)请注意,对于其他系统调用,您希望捕获它们的失败和errno 错误代码。

你为什么要问?.... libc(及其启动例程crt0.o ...)正在执行复杂的技巧来调用main...

另见this answer

【讨论】:

  • 谢谢,但使用-Wall-g 仍然不是“int $0x80”方式。因为我想扫描我的程序的汇编代码以查找对系统调用的调用发生的位置。
  • +1 用于提及 VDSO。 @Coaku:请阅读此答案中的链接,它们将帮助您了解为什么您在反汇编中看不到 int $0x80syscall
  • _exit(2) 是一个包装函数。在我的 Debian 操作系统中,_exit() 调用 exit_group() = 系统调用 n。 231. 汇编代码不使用“int 0x80”,而是使用“syscall”指令。
【解决方案2】:

对于 32 位

asm( "int $0x80" :: "a" (1), "b" (0) );

对于 64 位

asm( "syscall" :: "a" (60), "D" (0) );

如果你已经声明了你的 exit 函数并带有属性 noreturn,你可能还需要这个。

__builtin_unreachable();

【讨论】:

  • 谢谢,但是如何使用__builtin_unreachable();
  • exit() 和 _exit() 都使用“noreturn”属性声明
  • attribute ((noreturn)) 启用某些优化。 GCC 对 asm() 调用的内容一无所知,所以在这里你已经通知它调用不会返回。只需将其放在 asm 调用之后即可。
  • 您通常不会在 GCC 汇编器输出中看到“int $0x80”,因为所有 Linux 系统调用都包含在小型库调用中。这些库函数(read()、_exit()、close() 等)通常(至少)选择正确的调用(可能是 32 位或 64 位版本),执行调用,然后处理任何错误并设置 errno。库调用当然是可移植且易于使用的。上面 _exit() 的 asm 版本之所以简单,只是因为它们不返回,因此没有错误处理。还有“系统调用”clobbers r11 和 rcx,出于同样的原因,我们也忽略了它们。
【解决方案3】:

系统调用由 glibc 包装,它应该使用底层内核使用的任何内容。不久前,Linux 放弃了 int 0x80 机制以提高性能...

为什么要以过时的方式进行系统调用?

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-12-11
    • 2015-06-09
    • 1970-01-01
    • 2016-03-27
    • 1970-01-01
    • 2012-12-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多