【问题标题】:Write byte to file with x86 assembler使用 x86 汇编程序将字节写入文件
【发布时间】:2016-05-04 13:46:10
【问题描述】:

我想在汇编程序中创建一个从 c 调用的函数,它将一个字节(char)写入文件。下面是函数在 c 中的样子:

void writebyte (FILE *f, char b)
{
    fwrite(&b, 1, 1, f);
}

下面是调用它的代码:

#include <stdio.h>

extern void writebyte(FILE *, char);

int main(void) {
    FILE *f  = fopen("test.txt", "w");    
    writebyte(f, 1);
    fclose(f);
    return 0;
}

到目前为止,我想出了以下汇编代码:

    .global     writebyte  
writebyte:
    pushl   %ebp
    movl    %esp, %ebp  #standard params
    pushl   12(%ebp)    # pushing byte to the stack
    pushl   $1
    pushl   $1
    pushl   8(%ebp)     #file to write
    call    fwrite
    popl    %ebp
    ret

我不断从 gdb 获取信息:

Program terminated with signal SIGSEGV, Segmentation fault.
#0  0xffa9702c in ?? ()

如何在汇编中编写这样的函数?

编辑:我使用的是 Ubuntu 16.04

【问题讨论】:

  • 由于您没有带汇编程序的 std 库,因此代码将依赖于操作系统。
  • 我使用的是 ubuntu 16.04
  • 调用fwrite的第一个参数是指向字节的地址,而不是字节本身;假设您已正确链接程序,您很可能会遇到 seg 错误,因为 fwrite 试图将您的字节用作地址,并访问未映射到虚拟地址空间中的地址的内存。
  • 你也不清理堆栈。

标签: c assembly


【解决方案1】:

根据cdecl 约定,您应该以相反的顺序推送参数。所以f 应该先走,b 应该最后走。在调用fwrite()之后,调用者也应该清理堆栈。

如 cmets 中所述,b 将作为值接收,但我们需要将其作为指针传递给 fwrite()。指针将等于ebp + 12 的值。

这似乎对我有用:

    .global writebyte
writebyte:
    //create new stack frame
    pushl   %ebp
    movl    %esp, %ebp

    //push the four arguments to stack (in reverse order)
    pushl   8(%ebp)
    pushl   $1
    pushl   $1

    //get pointer of "b" argument (%ebp+12) and move it to %eax
    leal    12(%ebp), %eax
    pushl   %eax

    //call fwrite()
    call    fwrite

    //remove arguments from stack and pop %ebp
    leave

    ret

【讨论】:

  • 为什么在调用和函数名中使用下划线?
  • 因为我使用 Windows 编译了这个示例,而 Windows 上的 GCC 要求符号名称以下划线开头,并且实际上在所有 C 函数的前面加上下划线。你可以看到,如果你反汇编一个编译的目标文件。但无论如何,在 Linux 上应该不需要下划线,所以我将编辑帖子以删除它们。
  • 你为什么pusha/popa?你甚至评论这条线,如果他们被破坏,那是我们的呼叫者问题。这样您就可以使用leave 代替add $16, %esp / pop %ebp 作为结尾。 (当然,编译器甚至不会费心制作堆栈帧,而是 gcc is dumb and copies the char into a local,而不是传递其在堆栈上的位置的地址。此外,gcc 使堆栈保持 16B 对齐 fwrite()。这往往没关系,因为 stdio 函数不会将 SSE 向量溢出到堆栈中。)
  • 你说得对,pusha/popa 根本不需要。可能是我写这篇文章的时候没有注意。我将编辑帖子以删除它们。看看 GCC 的行为方式很有趣。
猜你喜欢
  • 1970-01-01
  • 2015-06-15
  • 1970-01-01
  • 2015-06-09
  • 2011-02-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多