linux - NASM:两个后续文件写入不起作用

标签 linux assembly x86 nasm system-calls

尝试运行此代码以便我可以创建 bmp 文件 - 我写标题,然后我想将内容写入文件 - 一切都单独工作但不能一起工作。 如果重要的话,我正在使用 hexedit 检查文件。

如果我运行带有标题编写部分的代码,它就可以工作。 如果我运行带有内容编写部分的代码,它就可以工作。 当我同时运行它们时却没有。

有什么想法吗?

代码如下:

section     .text
global      _start                              

_start:                                         

;#######################################################################
;### main ##############################################################
;#######################################################################

    ; open file
    mov     eax,8                               ;system call number - open/create file
    mov     ebx,msg                             ;file name
    mov     ecx,111111111b                      ;file mode
    int     0x80                                ;call kernel

    ; save file descriptor to r8d
    mov     r8d, eax

    ; write headline to file
    mov     eax, 4                              ;write 54 bytes to file
    mov     ebx, r8d                            ;load file desc
    mov     ecx, bmpheadline                    ;load adress of memory to write
    mov     edx, 54                             ;load number of bytes
    int     0x80                                ;call kernel

    ; write content to file
    mov     eax, 4                              ;number of syscall - write
    mov     ebx, r8d                            ;load file desc
    ;add     ebx, 54                             ;add 54 bytes to location of file location
    mov     ecx, empty_space                    ;load adress of buffer
    mov     edx, 40054                          ;load number of bytes
    int     0x80                                ;call kernel

    ; close file
    mov     eax, 6                              ;load syscall number - close
    mov     ebx, r8d                            ;load file desc
    int     0x80                                ;call kernel

    ; exit program
    mov     eax,1                               ;syscall number - exit     
    int     0x80                                ;call kernel

section     .data

    msg     db  'filename.bmp',0x00                 ;name of out file, 0x00 = end of string                        

    bmpheadline db  0x42,0x4D,0xB6,0xDA,0x01,0x00,0x00,0x00,0x00,0x00,0x7A,0x00,0x00,0x00,0x6C,0x00,0x00,0x00,0xC9,0x00,0x00,0x00,0xC9,0x00,0x00,0x00,0x01,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x3C,0xDA,0x01,0x00,0x13,0x0B,0x00,0x00,0x13,0x0B,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x42,0x47,0x52,0x73,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00

section .bss

    empty_space: resb 40054

最佳答案

您的代码有 2 个重大问题。 R8D (R8) 未在 int 0x80 中保留。其次,您原始问题中的 add ebx, 54 是不正确的。您不需要更改文件描述符。


64 位代码首选 SYSCALL

int 0x80 是 Linux 内核中的 IA32 兼容性功能。大多数 64 位 Linux 内核通常会启用此功能,但也可以将其关闭。您不能将 64 位指针与 int 0x80 一起使用。这可以防止使用基于堆栈的地址作为 int 0x80 的参数。出于这些原因,最好对 64 位程序使用 SYSCALL 而不是 int 0x80

有关在 Linux 中使用 SYSCALL 的更多信息,请参阅 Ryan Chapman's Blog .请注意,与 SYSCALL 一起使用的系统调用号与 int 0x80 不同。用于传递参数的寄存器不同,SYSCALL 中唯一不保留的寄存器是 RCXR11RAX(RAX 是返回值)。当前的 64-bit Linux System V ABI 中详细描述了系统调用约定。 .特别是:

  1. User-level applications use as integer registers for passing the sequence %rdi, %rsi, %rdx, %rcx, %r8 and %r9. The kernel interface uses %rdi, %rsi, %rdx, %r10, %r8 and %r9.
  2. A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11.
  3. The number of the syscall has to be passed in register %rax.
  4. System-calls are limited to six arguments, no argument is passed directly on the stack.
  5. Returning from the syscall, register %rax contains the result of the system-call. A value in the range between -4095 and -1 indicates an error, it is -errno.
  6. Only values of class INTEGER or class MEMORY are passed to the kernel

如果您希望您的 64 位代码使用 INT 0x80

INT 0x80 在 64 位代码中有一些怪癖。它遵守保留 RBXRCXRDXRSI 的 32 位调用约定RDIRBP。对于其他 64 位寄存器,适用 64 位 C 调用约定。来自 ABI:

A.2.1 Calling Conventions

... applications that like to call system calls should use the functions from the C library. The interface between the C library and the Linux kernel is the same as for the user-level applications

参见上面链接的 64 位 Linux ABI 中的图 3.4:寄存器用法R12R13R14R15 也将被保留。

这意味着 RAXR8R9R10R11 不会被保留。将您的代码从使用 R8D 更改为保存的寄存器之一。 R12D 例如。


为什么你的代码会失败?

由于 R8D 未在 int 0x80 中保留,因此它可能被 SYS_WRITE 系统调用覆盖。第一个写入有效,第二个无效,因为 R8D 可能被第一个 SYS_WRITE 破坏,并且 R8D 可能成为无效的文件描述符.使用将被保留的寄存器之一应该可以解决这个问题。如果您用完了寄存器,您始终可以在堆栈上分配空间用于临时存储。

关于linux - NASM:两个后续文件写入不起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40915909/

相关文章:

c - 在 C 中返回 char* 的 x86 函数

linux - 什么核心在运行我的进程?

assembly - "iterations"中的 "perf report -b --branch-history"是什么意思(perf record -b -g)

visual-studio-2012 - MASM 从/到立即内存地址移动

assembly - 推送到浮点寄存器而不是堆栈

assembly - x86 汇编代码的语法

assembly - `test` 指令是如何工作的?

linux - 在 CentOS 中合并大量 CSV 文件?

linux - ubuntu服务器默认下载目录在哪里

linux - 从 elf 文件的 DYNAMIC 部分删除条目