如何在x86汇编中调用fgets函数?

4
根据fgets()的文档,该函数有三个参数:
  • char * - 存储输入内容的字符串
  • int - 表示要读取的最大字符数的整数
  • FILE * - 要从中读取流的FILE *
我没有调用函数的问题。我只需将三个参数推入堆栈中,调用函数,并将ESP增加12。
我的问题是第3个参数。在标准输入中应传入什么作为FILE *?在C中,我可以使用stdin,但我不知道x86汇编中的等效物是什么。
更新:我正在Linux上使用NASM。

当我不知道如何在汇编中完成某些操作时,通常会将其编译为C并检查输出。然而,对于这种情况来说,这种方法已经相当无用了:GCC使用___stdinp@GOTPCREL(%rip),这似乎是极度特定于平台的。也许你可以编写一个返回stdin的C函数,并从汇编中调用它。 - zneak
@zneak:有没有从标准输入读取字符输入的替代函数?我尝试了 scanf(),但它有自己的问题。 - Nathan Osman
2
你可以使用文件描述符#0和read命令。应该能解决问题。我几秒钟之前已经建议过这个答案了。 - zneak
@zneak:我一定会试一试。 - Nathan Osman
4个回答

5
stdin 的问题在于它是一个宏,会展开成一些特定于平台的东西,而且很可能很难手动从汇编中访问。如果你愿意牺牲 stdio 并使用 POSIX 调用,stdin 就和众所周知的文件描述符 #0 一样了。因此,你可以将 0 传递给 read 函数,几乎可以得到你想要的结果。我相信这比 stdin C 宏更容易在汇编中使用。

这看起来很有前途。所以基本上调用read()并将0作为第一个参数传递? - Nathan Osman
请注意,这个函数不会像 fgets 一样在行末停止 - 它可能看起来像是这样,因为在默认终端模式下,当一行输入时它会解除阻塞,但在某些情况下,它可能会一次发送多行或在无缓冲终端模式下发送部分行。 - bdonlan
好的,我必须添加几条指令来截断换行符前的字符串,因为它包含在字符串中。 - Nathan Osman
请注意,@bdonlan是正确的:read不是fgets的POSIX克隆版本,可能需要进行一些额外的处理。 - zneak

1

如果汇编是C/C++代码的子程序,大多数运行时环境都提供了通过外部引用直接访问stdin变量的方法。请检查stdio.h头文件(或者它包含的任何内容)。通常的变量名似乎是__stdin或者命名为__stdio[]的FILE*数组,其中前3个元素分别是标准输入、标准输出和标准错误。

如果C被用作某些其他语言的库(例如汇编语言),那么您就必须自己调用C运行时初始化。这可能很难识别。如果我不知道如何做,我会编写一个类似于“hello world”的C程序,并使用调试器逐步执行以查看它如何设置stdin

另一种完全不同的方法是调用fopen()获取要读取的文件的FILE *。


这是纯汇编,利用了 libc 库。 - Nathan Osman

0

stdin 是一个仅存在于 C 语言中的概念。它的定义取决于你所使用的 C 编译器和库,由于宏等原因,从汇编语言中调用它可能会非常困难。

你可以尝试将其视为寄存器大小的全局变量。将其加载到寄存器中(使用你的 C 编译器所使用的任何名称重整约定),然后将其推入堆栈。如果这种方法不起作用,你需要检查 C 库源代码以了解它是如何处理的。

或者,你可以使用更低级别的操作系统调用,这些调用可能更适合汇编语言的使用 - 但是,由于你没有指定操作系统,很难给出更具体的建议。


抱歉,我正在使用“libc”在Linux上工作。我的汇编器是NASM。 - Nathan Osman

0
这是纯汇编,利用libc。- George Edison
那么答案将完全取决于开发系统和操作系统。Libc并不旨在支持这种类型的事情。
即使您能够弄清楚如何进行此类调用,stdin也指向一个相当复杂的、依赖于操作系统或开发系统的FILE数据结构,该结构由libc使用在main()运行之前调用的例程进行初始化。因此,在纯汇编中,您也必须做所有这些工作。这就是为什么简单的C语言“Hello world”程序在任何平台上都会生成相当大的可执行文件的原因。
如果您编写一个简单的C程序从stdin读取一些信息,然后对整个程序进行反汇编并了解它正在做什么,那么您将有一个良好的开始。但是这样做不会很快,并且您学到的东西肯定无法从Windows上的Visual Studio移植到Linux上的gcc。

所以在纯汇编中,你也必须做所有这些事情。不完全是这样的。只需与libc链接即可在进入main之前自动构建std文件指针的结构。重点主要是找到宏展开的结果以及如何使用该结果,这确实取决于平台并且很复杂。 - zneak
不完全正确。别忘了是libc在我的汇编代码中调用main()函数。 - Nathan Osman

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接