【问题标题】:call fgets from assembly code从汇编代码调用 fgets
【发布时间】:2011-03-31 23:41:14
【问题描述】:

我想知道如何从汇编代码中调用 fgets。 我读了这些与这个完全相同的问题:How to call fgets in x86 assembly? 还有这个:How to use c library function fgets in assembly language? 但他们两个都不满意,原因有两个: 1. 我真的很想使用 fgets,因为我希望我的代码可以在 windows 和 linux 上运行(我使用的是 NASM) 2.我查看了 fgets 的反汇编版本,不幸的是它没有提供必要的细节来重现它,命名stdin 在汇编中的表示方式。 这是我使用 gcc -S fgets.c 获得的 C 和汇编代码。

fgets.c

#include <stdio.h>
int main()
{
    char name[15];
    fgets(name, 16, stdin);
    return 0;
}

fgets.s

    .file   "fgets.c"
    .def    ___main;    .scl    2;  .type   32; .endef
    .text
.globl _main
    .def    _main;  .scl    2;  .type   32; .endef
_main:
    pushl   %ebp
    movl    %esp, %ebp
    andl    $-16, %esp
    subl    $32, %esp
    call    ___main
    movl    __imp___iob, %eax
    movl    %eax, 8(%esp)
    movl    $16, 4(%esp)
    leal    17(%esp), %eax
    movl    %eax, (%esp)
    call    _fgets
    movl    $0, %eax
    leave
    ret
    .def    _fgets; .scl    2;  .type   32; .endef

首先,我不擅长阅读 AT&T 语法,因此很容易理解上述汇编源代码。 那么谁能帮我弄清楚:(i)我的局部变量name在哪里?在 ESP+17 中? (ii) 如果__imp___iob 代表stdin,我可以使用它从哪里来?

谢谢

【问题讨论】:

  • 我也不喜欢 AT&T 的语法。使用gcc -S -masm=intel fgets.c 获得更好的反汇编。
  • @Burr:哈哈哈,有点不舒服。谢谢你的提示!!!救了我。

标签: c nasm


【解决方案1】:

是的,名字在 esp+17。初始化它是明智的。 cdecl 调用约定中的参数从右到左传递,堆栈中最右边的最深。 __imp___iob 是从 CRT 导出的,您会在 stdio.h 头文件中找到它。搜索标准输入。 __imp 前缀是 Microsoft 的约定,可以更快地从 DLL 导出。正确地做到这一点显然是编译器的工作。

【讨论】:

  • @Passant:我追踪__imp_iob 回到了一些可能在 DLL (ntdll.dll?) 中定义的数据。正如您刚刚指出的那样,编译器在这里做得很好,但是我如何访问该值并使用它呢?我可以在.text 部分做一些extern __imp_iob,但是,它是否正确?欢迎进一步的建议!
  • 如果编译器生成它很可能是正确的。您必须链接编译器使用的同一个 CRT 库。您似乎在混合工具,因此拨打电话并不容易。这有什么意义?
  • @Khan2011:我假设您使用的是 MinGW。 __imp_iob/mingww/include/stdio.h 中声明,并由链接器在 libmsvcrt.a(msvcrt.dll 的导入库)中解析。您应该能够使用相同的库来链接您的汇编程序。我不确定 C 运行时可能需要什么(如果有的话)特殊初始化。深入了解 MinGW 所做的事情将回答这个问题。
  • @Passant:经过您的解释,很明显我不能依赖 fgets。最好让 C 在汇编中执行“打印”和“扫描”部分以实现可移植性,但调用 fgets 会自动丢弃可移植性部分。所以再追究下去没有意义。 @Burr:感谢您提供详细信息。不再需要调查 CRT 初始化部分 [不可移植]
【解决方案2】:

(i) 我的局部变量 name 在哪里?在 ESP+17 中?

是的-实际上,当您进行调用时,“名称”会衰减为一个指针-您的整个数组都在堆栈上。第一个字节位于 ESP+17,其余字节紧随其后。请注意,代码使用leal 来获取要传递给fgets() 的数组第一个字节的地址

(ii) 如果__imp___iob 代表标准输入,我可以从哪里使用它?

您应该能够使用为您的机器定义的任何stdin。例如,在我的 Mac 上,它最终是 ___stdinp。您可以追踪系统标头中的定义(以stdio.h 开头)。您可能需要一个 .globl 指令来使汇编器不会抱怨,但它应该正确链接。 __imp___iob 看起来是您的正确选择。

这是我在stdio.h 中找到的内容:

#if __DARWIN_UNIX03
#define stdin   __stdinp
#define stdout  __stdoutp
#define stderr  __stderrp
#else /* !__DARWIN_UNIX03 */
#define stdin   (&__sF[0])
#define stdout  (&__sF[1])
#define stderr  (&__sF[2])
#endif /* __DARWIN_UNIX03 */

我的汇编代码中需要额外的_,因为编译器不支持它。

【讨论】:

  • @Norum:感谢您的明确解释!我在stdio.h 中得到了我的stdin,但是如何在我的汇编代码中使用它?我有一些代码编译但是,嘿,不能完成这项工作!我对stackoverflow比较陌生,所以我不确定在哪里发布我的代码。感谢您提供任何新见解!
猜你喜欢
  • 2016-06-01
  • 1970-01-01
  • 2011-09-04
  • 2013-04-16
  • 1970-01-01
  • 1970-01-01
  • 2017-01-19
  • 2016-09-07
  • 2017-02-18
相关资源
最近更新 更多