Linux 如何在汇编程序中打开文件并对其进行修改?
我开始学习汇编程序,我在Unix中工作。我想打开一个文件,在上面写上“Hello world”Linux 如何在汇编程序中打开文件并对其进行修改?,linux,assembly,x86,nasm,Linux,Assembly,X86,Nasm,我开始学习汇编程序,我在Unix中工作。我想打开一个文件,在上面写上“Hello world” section .data textoutput db 'Hello world!', 10 lentext equ $ - textoutput filetoopen db 'hi.txt' section .text global _start _start: mov eax, 5 ;open mov ebx, filetoopen mov ecx, 2
section .data
textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
int 80h
mov eax, 4
mov ebx, filetoopen ;I'm not sure what do i have to put here, what is the "file descriptor"?
mov ecx, textoutput
mov edx, lentext
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
但是当我编译它的时候,它什么都不做。我做错了什么?
当我打开一个文件时,文件描述符值返回到哪里?这取决于您正在使用的汇编程序,以及您是否希望使用C运行时。在本例中,这似乎是Hello World文本示例,因为他们正在使用nasm。如果您有一个_start字段,则不需要C运行时,因此可以将其组装到elf对象文件中,并将其链接到程序中:
nasm -felf hello.asm
ld hello.o -o hello
现在您可以运行hello
程序
一个使用C运行时而不是linux系统调用来完成这项工作的可移植性稍高的示例可能类似于下面的示例。如果按说明链接,则可以使用printf
进行打印
;;; helloworld.asm -
;;;
;;; NASM code for Windows using the C runtime library
;;;
;;; For windows - change printf to _printf and then:
;;; nasm -fwin32 helloworld.asm
;;; link -subsystem:console -out:helloworld.exe -nodefaultlib -entry:main
;;; helloworld.obj msvcrt.lib
;;; For gcc (linux, unix etc):
;;; nasm -felf helloworld.asm
;;; gcc -o helloworld helloworld.o
extern printf
section .data
message:
db 'Hello, World', 10, 0
section .text
global main
main:
push dword message ; push function parameters
call printf ; call C library function
add esp, 4 ; clean up the stack
mov eax, 0 ; exit code 0
ret
有关文件描述符的信息,请阅读打开(2)
手册页或查看。posix是如何引用开放i/o流的。在您的例子中,stdout.这是x86Linux(x86不是唯一的汇编语言,Linux也不是唯一的Unix!)
文件名字符串需要一个0字节的终止符:filetoopen db'hi.txt',0
section .text
global _start
_start:
mov eax, 5 ;open
mov ebx, filetoopen
mov ecx, 2 ;read and write mode
2
是open
syscall的O_RDWR
标志。如果您希望在文件不存在的情况下创建该文件,则还需要O_create
标志;如果指定O_create
,则需要第三个参数,即文件的权限模式。如果你仔细查看C标题,你会发现O_create
被定义为0100
-注意前导零:这是一个八进制常数!您可以使用o
后缀在nasm
中写入八进制常数
因此,您需要像movecx,0102o
这样的东西来获得正确的标志,并且movedx,0666o
来设置许可
int 80h
系统调用的返回代码传入eax
。这里,这将是文件描述符(如果打开成功)或一个小的负数,它是一个负数errno
代码(例如-1表示EPERM
)。请注意,从原始系统调用返回错误代码的约定与C系统调用包装器并不完全相同(在发生错误时,C系统调用包装器通常返回-1
并设置errno
)
…因此,这里您需要先mov ebx,eax
(在覆盖eax
之前保存open
结果),然后mov eax,4
。(您可能想先检查结果是否为正,如果不是,则以某种方式处理打开失败。)
此处缺少int 80h
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
你看过报纸了吗?它涵盖了你的问题
您还可以使用gcc-S-fverbose asm-O1
编译一些C代码,并查看生成的程序集。例如,使用foo.c
,运行gcc-S-Wall-fverbose asm-O1 foo.c
(作为某些终端中的命令),然后查看(可能使用一些编辑器)生成的foo.S
汇编文件
最后,我认为不值得为汇编程序操心太多。到2020年,最新的编译器肯定会生成比您所能编写的更好的代码(如果您使用优化,至少是
-O2
)。有关更多信息,请参阅报告。这是一个x64 Linux示例
; Program to open and write to file
; Compile with:
; nasm -f elf64 -o writeToFile64.o writeToFile64.asm
; Link with:
; ld -m elf_x86_64 -o writeToFile64 writeToFile64.o
; Run with:
; ./writeToFile64
;==============================================================================
; Author : Rommel Samanez
;==============================================================================
global _start
%include 'basicFunctions.asm'
section .data
fileName: db "testFile.txt",0
fileFlags: dq 0102o ; create file + read and write mode
fileMode: dq 00600o ; user has read write permission
fileDescriptor: dq 0
section .rodata ; read only data section
msg1: db "Write this message to the test File.",0ah,0
msglen equ $ - msg1
msg2: db "File Descriptor=",0
section .text
_start:
mov rax,2 ; sys_open
mov rdi,fileName ; const char *filename
mov rsi,[fileFlags] ; int flags
mov rdx,[fileMode] ; int mode
syscall
mov [fileDescriptor],rax
mov rsi,msg2
call print
mov rax,[fileDescriptor]
call printnumber
call printnewline
; write a message to the created file
mov rax,1 ; sys_write
mov rdi,[fileDescriptor]
mov rsi,msg1
mov rdx,msglen
syscall
; close file Descriptor
mov rax,3 ; sys_close
mov rdi,[fileDescriptor]
syscall
call exit
回答得好!我只是想提一下,open的标志可以在debian/ubuntu上的
/usr/include/bits/fcntl.h
中找到,请问,我必须如何在linux终端bcs中使用nasm-f elf my_code.asm
ld-m elf_i386 my_code.o-s-o my_code
mycode
不知道为什么要将标志/模式存储在.data
中作为qword整数?您可以使用eq
与msglen
相同的方法在那里定义它们,但要立即组装到mov中。另外,通常您应该使用mode=0666o
并让用户的umask
管理权限,这样他们可以选择644
或664,或者如果他们愿意,也可以选择
600`。也没有理由将文件描述符存储到内存中。您可以将它复制到一个保留调用的寄存器(例如,ebx
),这样它就可以在关闭RAX的函数调用中生存。或者,如果print
函数使用像Irvine32这样的保留RDI的自定义调用约定,则转到edi
。(顺便说一句,int打开(常量字符*路径名,int标志,模式);
返回一个int,在x86-64系统V ABI中只有32位。当您只需要eax
时,在整个64位寄存器中复制是毫无意义的。此外,这个答案显然取决于一些您甚至没有链接到的基本函数.asm
。您需要fopen
/fprintf
来写入文件(或者更简单地说,如果您不需要格式化,fputs
),或者您需要进行open
和dup2
系统调用,以便在使用stdioprintf
之前将stdout
重定向到文件。如果调用约定是特定于平台的,那么编写使用更多可移植API的asm似乎毫无意义(就像x86-64)。32位Windows和Linux调用约定对于大多数事情来说都足够接近,除了Windows在32位代码中使用\u printf
,不是吗?但是您忘记了在调用之前确保16字节堆栈对齐;i386 System V需要这样做。(子esp,8
)
mov ecx, textoutput
mov edx, lentext
mov eax, 1
mov ebx, 0
int 80h ; finish without errors
; Program to open and write to file
; Compile with:
; nasm -f elf64 -o writeToFile64.o writeToFile64.asm
; Link with:
; ld -m elf_x86_64 -o writeToFile64 writeToFile64.o
; Run with:
; ./writeToFile64
;==============================================================================
; Author : Rommel Samanez
;==============================================================================
global _start
%include 'basicFunctions.asm'
section .data
fileName: db "testFile.txt",0
fileFlags: dq 0102o ; create file + read and write mode
fileMode: dq 00600o ; user has read write permission
fileDescriptor: dq 0
section .rodata ; read only data section
msg1: db "Write this message to the test File.",0ah,0
msglen equ $ - msg1
msg2: db "File Descriptor=",0
section .text
_start:
mov rax,2 ; sys_open
mov rdi,fileName ; const char *filename
mov rsi,[fileFlags] ; int flags
mov rdx,[fileMode] ; int mode
syscall
mov [fileDescriptor],rax
mov rsi,msg2
call print
mov rax,[fileDescriptor]
call printnumber
call printnewline
; write a message to the created file
mov rax,1 ; sys_write
mov rdi,[fileDescriptor]
mov rsi,msg1
mov rdx,msglen
syscall
; close file Descriptor
mov rax,3 ; sys_close
mov rdi,[fileDescriptor]
syscall
call exit