只有系统调用才能在程序集中获得printf?

问题描述:

我期待了解程序集级别的printf()语句。然而,大部分汇编程序都会执行一些操作,例如调用外部打印函数,这些函数的依赖性由链接器添加的其他对象文件满足。我想知道打印函数内部的系统调用和非常基本的汇编代码。对于printf,我需要一个汇编代码,其中唯一的外部调用是系统调用。我在想像一个de组装的对象文件。我在哪里可以得到类似的东西?只有系统调用才能在程序集中获得printf?

+1

在大多数情况下,printf()代码通过putchar()调用操作系统write()。 –

+0

但是,我怎么可能反汇编我的Linux上的东西,看看它是怎么做到的????所以putchar()只是一个write()?? – user2277550

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

特别是,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 b因为printf可能会呼叫malloc和许多其他功能!)...我不知道这是值得的痛苦。

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


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

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

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

想想printf()的功能。解释格式化的字符串并生成正确的输出相当复杂。 printf()所属的一系列函数也缓冲输出。你可能并不是真的想在汇编中重新实现所有这些。标准的C库是无所不在的,并且可能为您提供。

也许你正在寻找write(2),这是系统调用只缓冲写入文件描述符的字节。您必须生成预先打印的字符串并自行设置格式。 (也open(2)打开文件见。)

拆解二进制文件,你可以使用objdump

objdump -d binary 

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

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

更简单的做法是查看printf()本身的C源代码。真正的工作实际上是在vfprintf()中完成的,它位于GNU C库source codestdio-common/vfprintf.c中。

+0

我不想重新实现它,我知道它为什么这样做。我只想看看它是如何实现的...... – user2277550

+1

*“在标准的C库中,所以它被链接到你的程序中,而不是复制到它”*不一定是真的。许多较旧的系统将整个运行时间库链接到生成可执行文件。可共享的动态链接库是一个相对较新的创新。由于OP没有指定任何特定的环境,因此假定现代高效的环境是不准确的。 – wallyk