【问题标题】:How to call fgets in x86 assembly?如何在 x86 程序集中调用 fgets?
【发布时间】:2010-09-11 05:29:45
【问题描述】:

根据the documentation for fgets(),该函数接受三个参数:

  • char * - 保存输入的字符串
  • int - 一个整数,表示要读取的最大字符数
  • FILE * - 要读取的流的 FILE *

调用函数没有问题。我只是把push这三个参数入栈,调用函数,把ESP加12。

我的问题在于参数 #3。什么应该作为FILE * 传递给标准输入?在 C 语言中,我可以只使用 stdin,但我不知道 x86 汇编中的等价物是什么。


更新:我在 Linux 上使用 NASM。

【问题讨论】:

  • 当我不知道如何在汇编中做某事时,我通常只是用 C 编译它并检查输出。但是,对于这种情况,这几乎没有用:GCC 使用___stdinp@GOTPCREL(%rip),这似乎是非常特定于平台的。也许你可以做一个返回标准输入的 C 函数,并从你的程序集中调用它。
  • @zneak: 是否有从标准输入读取字符输入的替代功能?我试过scanf(),但它有自己的问题。
  • 您可以将read 与文件描述符#0 一起使用。应该做的伎俩。几秒钟前我已经建议它作为答案。
  • @zneak:我一定会试一试的。

标签: linux file-io assembly nasm


【解决方案1】:

stdin 的问题在于它是一个宏,它不仅扩展到特定于平台的东西,而且很可能难以从手工组装中访问。如果您愿意牺牲stdio 并改用POSIX 调用,stdin 与众所周知的文件描述符#0 相同。因此,您可以将0 传递给read 并获得几乎您想要的东西。我很确定这比 stdin C 宏更适合汇编程序。

【讨论】:

  • 这看起来很有希望。所以基本上调用read()传递0作为第一个参数?
  • @zneak:如果可以的话,+500!这非常完美。谢谢!
  • 请注意,这与 fgets 的行尾停止语义不同 - 它可能看起来像,因为当一行通过时它会解除阻塞默认终端模式,但在某些情况下,它可能一次通过多行发送,或者在无缓冲终端模式下,部分行发送。
  • 好吧,我不得不添加一些指令来截断换行符之前的字符串,因为它包含在字符串中。
  • @George Edison 请注意@bdonlan 是对的:read 不是fgets 的 POSIX 克隆,可能需要进行一些额外的处理。
【解决方案2】:

如果程序集是 C/C++ 代码的子例程,大多数运行时环境都提供了一种通过外部引用直接访问标准输入变量的方法。检查 stdio.h 头文件(或者可能包含的任何内容)。通常的嫌疑人似乎是名为 __stdin 的变量或名为 __stdio[] 之类的 FILE * 数组,其中前 3 个元素是 stdin、stdout 和 stderr。

如果 C 被用作其他语言(如汇编)的库,那么您必须自己调用 C 运行时 init。这可能很难识别。如果我不知道怎么做,我会写一个“hello world”类型的 C 程序,然后用调试器单步调试它,看看它是如何设置的 stdin

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

【讨论】:

  • 这是使用libc的纯汇编。
【解决方案3】:

stdin是一个只存在于C语言中的概念。它的定义取决于你的C编译器和库,并且由于宏等原因,可能很难从汇编器中调用。

您可以尝试的一件事是将其视为stdin 是寄存器大小的全局变量。将其加载到寄存器中(使用 C 编译器使用的任何名称修改约定),然后将其推送到堆栈中。如果这不起作用,您需要检查 C 库源代码以了解它是如何工作的。

或者,您可以使用更适合汇编程序使用的较低级别的操作系统调用 - 但是,由于您没有指定您的操作系统,因此很难更具体。

【讨论】:

  • 抱歉,我正在使用libc 使用 Linux。我的汇编器是 NASM。
【解决方案4】:

这是使用 libc 的纯汇编。 ——乔治·爱迪生

那么答案将完全取决于开发系统和操作系统。 Libc 的目的不是支持这种东西。

即使你能弄清楚如何进行这种调用,标准输入指向一个相当复杂的、依赖于操作系统或开发系统的 FILE 数据结构,它由 libc 使用在 main() 之前调用的例程进行初始化跑。所以在纯汇编中,你也必须做所有这些。这就是为什么一个简单的 C 语言“Hello world”程序可以在任何平台上生成相当大的可执行文件的原因。

如果您编写一个简单的 C 程序,从标准输入读取一些信息,然后反汇编整个程序并准确了解它在做什么,那么您将有一个良好的开端。但是这样做不会很快,而且你学到的东西肯定不能从 Windows 上的 Visual Studio 移植到 Linux 上的 gcc。

【讨论】:

  • “所以在纯汇编中,你也必须这样做。”不完全的。只需与libc 链接就足以在您点击main 之前自动构建std 文件指针的结构。关键是要找到宏扩展的内容以及如何使用该结果,这确实取决于平台且复杂。
  • 不完全。不要忘记在我的汇编代码中调用main() 函数的是libc
猜你喜欢
  • 2017-01-18
  • 1970-01-01
  • 2013-05-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多