仅使用系统调用将printf置于汇编中?

时间:2016-01-23 13:03:47

标签: c operating-system system-calls object-files

我希望了解程序集级别的printf()语句。但是,大多数汇编程序执行的操作类似于调用外部打印函数,其依赖性由链接器添加的其他目标文件满足。我想知道在打印函数内部的系统调用和非常基本的汇编代码。我想要一个汇编代码,其中唯一的外部调用是系统调用,对于printf。我在考虑类似于已组装的目标文件。我在哪里可以获得类似的东西?

2 个答案:

答案 0 :(得分:5)

我建议先保留C级,然后在Linux上研究一些现有C标准库free software实现的源代码。查看musl-libcGNU libc(a.k.a。glibc)的源代码。您将了解在printf和基本系统调用(在syscalls(2) ...中列出)之间,有几个中间(通常是内部)函数很有用。对printf的示例C程序也使用strace(1)(例如通常的hello-world示例)。

特别是,musl-libc具有非常易读的stdio/printf.c实现,但在到达write(2)系统调用之前,您需要遵循其他几个C函数。请注意,涉及一些buffering。另见setvbuf(3)& fflush(3)。几个答案(例如thisthat)解释了printf和系统调用(直到内核代码)等函数之间的链接。

  

我想要一段汇编代码,其中唯一的外部调用是系统调用,printf

如果你想要的话,你可以从 musl-libc ' stdio/printf.c开始,从musl-libc添加任何其他源文件,直到你没有更多外部未定义的符号,并用gcc -flto -O2和也许-S编译所有符号,您可能会以对象(或汇编)形式完成 musl-libc 的重要部分(因为printf可能会调用malloc和许多其他功能!)......我不确定这是否值得痛苦。

您还可以静态关联libc(例如libc.a)。然后链接器将仅链接printf(以及您正在调用的任何其他函数)所需的静态库成员。

要挑剔,system calls实际上不是外部调用(你的libc write函数实际上是原始系统调用的一个小包装器)。你可以使用SYSENTER机器指令来制作它们(但最好使用vdso(7):更便携,也许更快),你甚至不需要有效的堆栈指针(在x86_64上)来制作它们系统调用。

您甚至无需使用libc即可编写Linux用户级程序; Scheme的bones实现就是这样一个程序(并且你会找到其他程序)。

答案 1 :(得分:3)

函数printf()位于标准C库中,因此它链接到您的程序中而不会复制到它中。动态链接库可以节省内存,因为对于每个使用它的程序,您没有在驻留内​​存中复制完全相同的代码。

考虑一下printf()的作用。解释格式化字符串并生成正确的输出是相当复杂的。 printf()所属的一系列函数也会缓冲输出。你可能真的不想在程序集中重新实现所有这些。标准C库无所不在,可能适合您。

也许你正在寻找write(2),这是系统调用只是字节到文件描述符的无缓冲写入。您必须预先生成要打印的字符串并自行格式化。 (有关打开文件,另请参阅open(2)。)

要反汇编二进制文件,您可以使用objdump

    objdump -d binary

其中binary是一些已编译的二进制文件。这给出了操作码和人类可读的指令。您可能想要重定向到一个文件并在别处阅读。

您可以在系统上反汇编标准C二进制文件,如果需要(强烈不推荐),请尝试解释它。问题是,要理解它太复杂了。像printf()这样的东西是用C语言编写的,然后编译和汇编。你不能(在合理的几十年内)从汇编的(非平凡的)程序中恢复高级结构。如果你真的想试试这个,祝你好运。

更容易的事情是查看printf()本身的C源代码。实际工作实际上是在vfprintf()中完成的,该stdio-common/vfprintf.c位于GNU C库source code<string name="Calories">Calories: %s</string> 中。