尝试运行此代码以便我可以创建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
答案 0 :(得分:2)
您在文件描述符中添加了54而没有说明;我完全不知道你为什么这么做。
我怀疑您误解了文件描述符,并认为您需要将目前为止写入的数据总量添加到描述符中。事实并非如此。描述符不会从打开/创建时间更改为关闭文件句柄的时间。验证您的评论是否与您的代码同步是一个非常好的主意。当您编写详细注释时,没有注释的行会立即被怀疑(例如add
指令。)
您从一开始就遇到了一些问题。例如,您的评论说"打开文件"和" sys_write"但是你的代码并不匹配。您的代码目前正在尝试调用sys_creat
。您调用文件描述符的实际上是权限模式。 ebx
应该包含表示路径的字符串的地址......注释似乎表明它应该是stdout,但它显然不是。 :)
您也不会说明这是针对64位还是32位Linux。您的代码似乎使用r8d
并使用int 0x80
混合了两者。
答案 1 :(得分:2)
您的代码存在两个重大问题。 R8D ( R8 )不会在int 0x80
之间保留。其次,原始问题中的add ebx, 54
不正确。您无需更改文件描述符。
int 0x80
是Linux内核中的IA32兼容性功能。此功能通常在大多数64位Linux内核中打开,但可以关闭。您不能将{64}指针与int 0x80
一起使用。这可以防止使用基于堆栈的地址作为int 0x80
的参数。出于这些原因,您最好将 SYSCALL 用于64位程序而不是int 0x80
。
可以在Ryan Chapman's Blog中找到有关在Linux中使用 SYSCALL 的更多信息。请注意,与 SYSCALL 一起使用的系统调用号与int 0x80
不同。用于传递参数的寄存器是不同的,并且 SYSCALL 中未保留的唯一寄存器是 RCX , R11 和 RAX < / em>( RAX 是返回值)。系统调用约定在当前64-bit Linux System V ABI中有详细描述。特别是:
- 用户级应用程序用作整数寄存器来传递序列 %rdi,%rsi,%rdx,%rcx,%r8和%r9。 内核界面使用%rdi, %rsi,%rdx,%r10,%r8和%r9 。
- 系统调用通过syscall指令完成。 内核破坏了 注册%rcx和%r11 。
- 系统调用的号码必须在寄存器%rax中传递。
- 系统调用仅限于六个参数,不直接传递参数 堆栈。
- 从系统调用返回,寄存器%rax包含结果 系统调用即可。介于-4095和-1之间的值表示错误, 它是-errno。
- 只将类INTEGER或类MEMORY的值传递给内核
醇>
INT 0x80 在64位代码中有一些怪癖。它遵循保留 RBX , RCX , RDX , RSI ,的32位调用约定RDI 和 RBP 。对于其他64位寄存器,适用64位 C 调用约定。来自ABI:
A.2.1呼叫约定
...喜欢调用系统调用的应用程序应该使用C库中的函数。 C库和Linux内核之间的接口与用户级应用程序的接口相同
请参阅上面链接的64位Linux ABI中的图3.4:注册表用法。 R12 , R13 , R14 和 R15 也将被保留。
这意味着 RAX , R8 , R9 , R10 和 R11 不会被保留。将代码从使用 R8D 更改为保存的其中一个寄存器。 R12D 例如。
由于 R8D 未在int 0x80
之间保留,因此 SYS_WRITE 系统调用可能会覆盖 R8D 。第一个写入工作,第二个写入不起作用,因为 R8D 可能被第一个 SYS_WRITE 删除,而 R8D 可能成为无效的文件描述符。使用将保留的其中一个寄存器应该可以解决此问题。如果用完寄存器,您总是可以在堆栈上分配空间以进行临时存储。
答案 2 :(得分:0)
(代表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