简体   繁体   English

如何在汇编程序中打开文件并修改它?

[英]How to open a file in assembler and modify it?

I'm starting to learn Assembler and I'm working in Unix.我开始学习汇编程序,我正在 Unix 中工作。 I want to open a file and write 'Hello world' on it.我想打开一个文件并在上面写上“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

But when I compile it, it doesn't do anything.但是当我编译它时,它什么也没做。 What am I doing wrong?我究竟做错了什么? When I open a file where does the file descriptor value return to?当我打开一个文件时,文件描述符值返回到哪里?

This is x86 Linux (x86 is not the only assembly language, and Linux is not the only Unix!)...这是 x86 Linux(x86 不是唯一的汇编语言,Linux 也不是唯一的 Unix!)...

section .data

textoutput db 'Hello world!', 10
lentext equ $ - textoutput
filetoopen db 'hi.txt'

The filename string requires a 0-byte terminator: filetoopen db 'hi.txt', 0文件名字符串需要一个 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 is the O_RDWR flag for the open syscall. 2open系统调用的O_RDWR标志。 If you want the file to be created if it doesn't already exist, you will need the O_CREAT flag as well;如果您希望在文件不存在的情况下创建该文件,则还需要O_CREAT标志; and if you specify O_CREAT , you need a third argument which is the permissions mode for the file.如果您指定O_CREAT ,则需要第三个参数,即文件的权限模式。 If you poke around in the C headers, you'll find that O_CREAT is defined as 0100 - beware of the leading zero: this is an octal constant!如果您查看 C 头文件,您会发现O_CREAT被定义为0100 - 注意前导零:这是一个八进制常量! You can write octal constants in nasm using the o suffix.您可以使用o后缀在nasm编写八进制常量。

So you need something like mov ecx, 0102o to get the right flags and mov edx, 0666o to set the permssions.所以你需要像mov ecx, 0102o这样的东西来获得正确的标志和mov edx, 0666o来设置权限。

int 80h

The return code from a syscall is passed in eax .系统调用的返回码在eax传递。 Here, this will be the file descriptor (if the open succeeded) or a small negative number, which is a negative errno code (eg -1 for EPERM ).在这里,这将是文件描述符(如果打开成功)或一个小的负数,这是一个负的errno代码(例如 -1 表示EPERM )。 Note that the convention for returning error codes from a raw syscall is not quite the same as the C syscall wrappers (which generally return -1 and set errno in the case of an error)...请注意,从原始的系统调用返回错误代码的惯例是不太一样的C系统调用包装(通常返回-1 ,并设置errno出现错误的情况下)...

mov eax, 4
mov ebx, filetoopen   ;I'm not sure what do i have to put here, what is the "file descriptor"?

...so here you need to mov ebx, eax first (to save the open result before eax is overwritten) then mov eax, 4 . ...所以在这里你需要先mov ebx, eax (在eax被覆盖之前保存open结果)然后mov eax, 4 (You might want to think about checking that the result was positive first, and handling the failure to open in some way if it isn't.) (您可能需要考虑首先检查结果是否为正,如果不是,则以某种方式处理无法打开的情况。)

mov ecx, textoutput
mov edx, lentext

Missing int 80h here.这里缺少int 80h

mov eax, 1
mov ebx, 0
int 80h              ; finish without errors

Did you read the Linux Assembly HOWTO ?你读过Linux Assembly HOWTO吗? It covers your question.它涵盖了您的问题。

You can also compile some C code with gcc -S -fverbose-asm -O1 and look at the generated assembly.您还可以使用gcc -S -fverbose-asm -O1编译一些 C 代码并查看生成的程序集。 For example, with foo.c , run gcc -S -Wall -fverbose-asm -O1 foo.c (as a command in some terminal) then look (using some editor -perhaps GNU emacs ) into the generated foo.s assembler file.例如,使用foo.c ,运行gcc -S -Wall -fverbose-asm -O1 foo.c (作为某些终端中的命令)然后查看(使用一些编辑器 - 可能是GNU emacs )进入生成的foo.s汇编程序文件.

At last, I don't think it is worth bothering a lot about assembler.最后,我认为不值得为汇编程序费心。 In 2020, a recent GCC compiler will surely generate better code than what you could write (if you invoke it with optimizations, at least -O2 ).在 2020 年,最近的GCC编译器肯定会生成比您可以编写的代码更好的代码(如果您通过优化调用它,至少-O2 )。 See this draft report for more.有关更多信息,请参阅报告草稿

This is a x64 Linux sample这是一个 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

It depends what assembler you are using and if you expect to be using the C runtime or not.这取决于您使用的汇编程序以及您是否希望使用 C 运行时。 In this case which appears to be the Hello World text example from rosettacode they are using nasm.在这种情况下,这似乎是来自rosettacode的 Hello World 文本示例,他们使用的是 nasm。 Given you have a _start field you are not needing the C runtime so you assemble this to an elf object file and link it into a program:鉴于您有一个 _start 字段,您不需要 C 运行时,因此您将其组装到一个 elf 目标文件并将其链接到一个程序中:

nasm -felf hello.asm
ld hello.o -o hello

Now you can run the hello program.现在您可以运行hello程序。

A slightly more portable example that uses the C runtime to do the work rather than linux syscalls might look like the sample below.使用 C 运行时而不是 linux 系统调用来完成工作的稍微更便携的示例可能类似于下面的示例。 If you link this as described it can use printf to do the printing.如果按照描述链接它,它可以使用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

For information about file descriptors - read the open(2) manual page or look at wikipedia .有关文件描述符的信息 - 阅读open(2)手册页或查看wikipedia It is how posix refers to an open i/o stream.这就是 posix 如何引用开放的 i/o 流。 In your case, stdout.在你的情况下,标准输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM