NASM: 两次后续文件写入无效
NASM: Two subsequent file writes not working
尝试 运行 此代码以便我可以创建 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
你在没有解释的情况下将54添加到文件描述符;我完全不知道你为什么要那样做。
我怀疑您误解了文件描述符,认为您需要将到目前为止写入的数据总量添加到描述符中。事实并非如此。从您 open/create 到您关闭文件句柄,描述符没有改变。验证您的评论是否与您的代码同步是一个非常好的主意。当您编写详细注释时,没有注释的行会立即变得可疑(例如 add
指令。)
您似乎从一开始就有一些问题。例如,您的评论说 "open file" 和 "sys_write" 但您的代码不匹配。您的代码当前所做的是尝试调用 sys_creat
。你所说的文件描述符实际上是权限模式。 ebx
应该包含表示路径的字符串的地址...注释似乎表明它应该是标准输出,但显然不是。 :)
您也没有说明这是针对 64 位还是 32 位 Linux。您的代码似乎混合了两者,使用 r8d
并使用 int 0x80
.
您的代码有 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 . Note that the system call numbers used with SYSCALL are different from int 0x80
. The registers used to pass parameters are different, and the only registers not preserved across a SYSCALL are RCX, R11, and RAX (RAX being the return value). The system calling convention is thoroughly described in the current 64-bit Linux System V ABI。特别是:
- 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.
- A system-call is done via the syscall instruction. The kernel destroys
registers %rcx and %r11.
- The number of the syscall has to be passed in register %rax.
- System-calls are limited to six arguments, no argument is passed directly on
the stack.
- 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.
- Only values of class INTEGER or class MEMORY are passed to the kernel
如果您希望 64 位代码使用 INT 0x80
INT 0x80 在 64 位代码中有一些怪癖。它遵守保留RBX、RCX、RDX、[=41]的32位调用约定=]RSI、RDI 和 RBP。对于其他 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
参见图 3.4:在上面链接的 64 位 Linux ABI 中注册使用。 R12、R13、R14 和 R15 也将被保留。
这表示RAX,R8,R9,R10 和 R11 将不会被保留。将您的代码从使用 R8D 更改为保存的寄存器之一。 R12D 例如。
为什么你的代码会失败?
由于 R8D 未在 int 0x80
中保留,因此它可能被 SYS_WRITE 系统调用覆盖.第一个写的有效,第二个没有,因为 R8D 很可能被第一个 SYS_WRITE 和 R8D 可能成为无效的文件描述符。使用将被保留的寄存器之一应该可以解决这个问题。如果你 运行 超出了寄存器,你总是可以在堆栈上分配 space 用于临时存储。
(代表OP发布解决方案).
这是解决方案的源代码,64 位版本:
section .text
global _start ;must be declared for linker (ld)
_start: ;tell linker entry point
;#######################################################################
;### This program creates empty bmp file - 64 bit version ##############
;#######################################################################
;### main ##############################################################
;#######################################################################
; open file
mov rax,85 ;system call number - open/create file
mov rdi,msg ;file name
;flags
mov rsi,111111111b ;mode
syscall ;call kernel
; save file descriptor
mov r8, rax
; write headline to file
mov rax, 1 ;write to file
mov rdi, r8 ;load file desc
mov rsi, bmpheadline ;load adress of memory to write
mov rdx, 54 ;load number of bytes
syscall ;call kernel
; write content to file
mov rax, 1 ;write to file
mov rdi, r8 ;load file desc
mov rsi, empty_space ;load adress of memory to write
mov rdx, 40000 ;load number of bytes
syscall ;call kernel
; close file
mov rax, 3 ;load syscall number - close
mov rdi, r8 ;load file desc
syscall ;call kernel
; exit program
mov rax,60 ;system call number (sys_exit)
syscall ;call kernel
section .data
msg db 'filename.bmp',0x00 ;name of out file, 0x00 = end of string
len equ $ - msg ;length of our dear 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 40000
生成文件:
all: a.out
a.out: main.o
ld main.o
main.o: main64.asm
nasm -f elf64 main64.asm -o main.o
尝试 运行 此代码以便我可以创建 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
你在没有解释的情况下将54添加到文件描述符;我完全不知道你为什么要那样做。
我怀疑您误解了文件描述符,认为您需要将到目前为止写入的数据总量添加到描述符中。事实并非如此。从您 open/create 到您关闭文件句柄,描述符没有改变。验证您的评论是否与您的代码同步是一个非常好的主意。当您编写详细注释时,没有注释的行会立即变得可疑(例如 add
指令。)
您似乎从一开始就有一些问题。例如,您的评论说 "open file" 和 "sys_write" 但您的代码不匹配。您的代码当前所做的是尝试调用 sys_creat
。你所说的文件描述符实际上是权限模式。 ebx
应该包含表示路径的字符串的地址...注释似乎表明它应该是标准输出,但显然不是。 :)
您也没有说明这是针对 64 位还是 32 位 Linux。您的代码似乎混合了两者,使用 r8d
并使用 int 0x80
.
您的代码有 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 . Note that the system call numbers used with SYSCALL are different from int 0x80
. The registers used to pass parameters are different, and the only registers not preserved across a SYSCALL are RCX, R11, and RAX (RAX being the return value). The system calling convention is thoroughly described in the current 64-bit Linux System V ABI。特别是:
- 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.
- A system-call is done via the syscall instruction. The kernel destroys registers %rcx and %r11.
- The number of the syscall has to be passed in register %rax.
- System-calls are limited to six arguments, no argument is passed directly on the stack.
- 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.
- Only values of class INTEGER or class MEMORY are passed to the kernel
如果您希望 64 位代码使用 INT 0x80
INT 0x80 在 64 位代码中有一些怪癖。它遵守保留RBX、RCX、RDX、[=41]的32位调用约定=]RSI、RDI 和 RBP。对于其他 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
参见图 3.4:在上面链接的 64 位 Linux ABI 中注册使用。 R12、R13、R14 和 R15 也将被保留。
这表示RAX,R8,R9,R10 和 R11 将不会被保留。将您的代码从使用 R8D 更改为保存的寄存器之一。 R12D 例如。
为什么你的代码会失败?
由于 R8D 未在 int 0x80
中保留,因此它可能被 SYS_WRITE 系统调用覆盖.第一个写的有效,第二个没有,因为 R8D 很可能被第一个 SYS_WRITE 和 R8D 可能成为无效的文件描述符。使用将被保留的寄存器之一应该可以解决这个问题。如果你 运行 超出了寄存器,你总是可以在堆栈上分配 space 用于临时存储。
(代表OP发布解决方案).
这是解决方案的源代码,64 位版本:
section .text
global _start ;must be declared for linker (ld)
_start: ;tell linker entry point
;#######################################################################
;### This program creates empty bmp file - 64 bit version ##############
;#######################################################################
;### main ##############################################################
;#######################################################################
; open file
mov rax,85 ;system call number - open/create file
mov rdi,msg ;file name
;flags
mov rsi,111111111b ;mode
syscall ;call kernel
; save file descriptor
mov r8, rax
; write headline to file
mov rax, 1 ;write to file
mov rdi, r8 ;load file desc
mov rsi, bmpheadline ;load adress of memory to write
mov rdx, 54 ;load number of bytes
syscall ;call kernel
; write content to file
mov rax, 1 ;write to file
mov rdi, r8 ;load file desc
mov rsi, empty_space ;load adress of memory to write
mov rdx, 40000 ;load number of bytes
syscall ;call kernel
; close file
mov rax, 3 ;load syscall number - close
mov rdi, r8 ;load file desc
syscall ;call kernel
; exit program
mov rax,60 ;system call number (sys_exit)
syscall ;call kernel
section .data
msg db 'filename.bmp',0x00 ;name of out file, 0x00 = end of string
len equ $ - msg ;length of our dear 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 40000
生成文件:
all: a.out
a.out: main.o
ld main.o
main.o: main64.asm
nasm -f elf64 main64.asm -o main.o