Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Linux 如何在汇编程序中打开文件并对其进行修改?_Linux_Assembly_X86_Nasm - Fatal编程技术网

Linux 如何在汇编程序中打开文件并对其进行修改?

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

我开始学习汇编程序,我在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            ;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
系统调用,以便在使用stdio
printf
之前将
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