linux - 创建/写入文件 x86 Linux

标签 linux assembly x86

我一直在尝试自学一些 32 位 x86 (NASM)。我试图让用户输入文件名,打开/创建文件,然后获取用户的消息并将该消息写入文件。我已经在 GDB 中检查过了,所有的系统调用都正确返回了。程序运行后,文件似乎创建不正确,并且没有写入任何内容。我 ahev 看到了其他一些类似的问题,但我的代码似乎与他们的代码几乎相同,所以我似乎无法弄清楚到底发生了什么。

这是我的菜鸟代码:

global _start
section .data
  fmsg:  db "Enter Filename: ", 0
  .len:  equ $ - fmsg
  umsg:  db "Enter message: ", 0
  .len:  equ $ - umsg
  buff:  times 50 db 0  ;array for user string
  .blen: equ $ - buff
  fname: times 50 db 0 ;array for filename
  .flen: equ $ - fname

  ;modes
  O_RDONLY: db 0        ;read-only
  O_WRONLY: db 1        ;wirte-only
  O_RDWR:   db 2        ;read and write

  ;flags
  O_CREAT:  dw 100o     ;create file if file doesnt exists
  O_TRUNC:  dw 1000o    ;truncate file
  O_APPEND: dw 2000o    ;append to file


section .bss
  fd:   resd 1          ;file descriptor
  bret: resd 1          ;read buffer return value
  fret: resd 1          ;read filename return value
  tmp:  resd 1          ;temp 4 byte variable

section .text
_start:

fprompt:               ;Print prompt
  mov eax, 0x4         ;syscall 4 - write()
  mov ebx, 0x1         ;file desc 1 - stdout
  mov ecx, fmsg        ;print message
  mov edx, fmsg.len    ;length of message
  int 80h              ;syscall interupt

filein:
  mov eax, 0x3          ;syscall 3 - read()
  mov ebx, 0x0          ;file desc 0 - stdin
  mov ecx, fname        ;dst buffer
  mov edx, fname.flen   ;length of buffer
  int 80h               ;syscall interupt
  mov [fret], eax       ;save return value to file return variable
  cmp eax, edx          ;read max bytes or more?
  jb  fileopen          ;jmp is bytes read < max
  mov bl, [ecx+eax-1]   ;grab last byte @ last index before '\0'
  cmp bl, 10            ;does it = '\n' ?
  je  clean1
  inc DWORD [fret]      ;len++

clean1:               ;loop to clear excess input, if any
  mov eax, 0x3        ;syscall 3 - read()
  mov ebx, 0x0        ;file desc 0 - stdin
  mov ecx, tmp        ;temp buffer
  mov edx, 0x1        ;read only 1 byte
  int 80h             ;;syscall interupt
  test eax, eax       ;EOF?
  jz  fileopen        ;Yes, jump to pback
  mov al, [tmp]       ;put character into lower 8 bits of EAX
  cmp al, 10          ;is it = to lf ?
  jne clean1          ;no, jump to begining of loop

fileopen:
  mov eax, 0x05
  mov ebx, fname      ;filename
  or  ecx, O_CREAT    ;if it doesn't exist create the file
  or  ecx, O_TRUNC    ;truncate
  mov edx, O_WRONLY   ;write only
  int 80h             ;syscall interupt
  mov [fd], eax       ;save file descripor

prompt2:
  mov eax, 0x4         ;syscall 4 - write()
  mov ebx, 0x1         ;file desc 1 - stdout
  mov ecx, umsg        ;print message
  mov edx, umsg.len    ;length of message
  int 80h

userin:
  mov eax, 0x3          ;syscall 3 - read()
  mov ebx, 0x0          ;file desc 0 - stdin
  mov ecx, buff         ;dst buffer
  mov edx, buff.blen    ;length of buffer
  int 80h               ;syscall interupt
  mov [bret], eax       ;save return value to buff return variable
  cmp eax, edx          ;read max bytes or more?
  jb  writetofile       ;jmp is bytes read < max
  mov bl, [ecx+eax-1]   ;grab last byte @ last index before '\0'
  cmp bl, 10            ;does it = '\n' ?
  je  clean2
  inc DWORD [bret]      ;len++

clean2:               ;loop to clear excess input, if any
  mov eax, 0x3        ;syscall 3 - read()
  mov ebx, 0x0        ;file desc 0 - stdin
  mov ecx, tmp        ;temp buffer
  mov edx, 0x1        ;read only 1 byte
  int 80h             ;syscall
  test eax, eax       ;EOF?
  jz  writetofile     ;Yes, jump to pback
  mov al, [tmp]       ;put character into lower 8 bits of EAX
  cmp al, 10          ;is it = to lf ?
  jne clean2          ;no, jump to begining of loop


writetofile:
  mov eax, 0x4         ;syscall 4 - write()
  mov ebx, [fd]        ;file desc 1 - stdout
  mov ecx, buff        ;print message
  mov edx, [bret]      ;length of message
  int 80h              ;syscall interupt

closefile:
  mov eax, 0x6      ;syscall 6 - close()
  mov ebx, [fd]     ;file desc
  int 80h           ;syscall interupt

exit:               ;return 0
  mov eax, 1        ;syscall 1 - exit()
  mov ebx, 0        ;return val
  int 80h           ;syscall interupt

这是我运行后得到的示例: Output

文件“test.txt?”出现并且还显示为可执行文件,即使我只为文件设置了读/写。即使我试图打开它,那里也什么也没有。有什么想法吗?另外正如我所提到的,我是新手,正在自学,所以如果您有任何关于改进该计划其他领域的好建议,请告诉我! :)

最佳答案

我们在以下三行代码中有多个错误(或一个大错误):

or  ecx, O_CREAT    ;if it doesn't exist create the file
or  ecx, O_TRUNC    ;truncate
mov edx, O_WRONLY   ;write only

问题:

寄存器 ecxedx 在这些行之后有什么值?

您对 ecx 寄存器执行了两个 操作,但显然它在那一刻没有被初始化!

这意味着您可以确定代表 O_CREATO_TRUNC 的位(无论这些值是什么意思 - 见下文)已设置,但您不知道哪些值其他位有。

O_WRONLY 位应该在 ecx 中设置,而不是在 edx 中设置。 edx 应该包含所需的文件模式。

不幸的是,有两种不同类型的汇编程序——我不知道 NASM 是哪种类型:

  • 一种类型的汇编程序会将第一条指令解释为:或 ecx, [O_CREAT]
  • 另一种类型会将其解释为:或 ecx, address_of(O_CREAT)

在第一种情况下,指令 mov edx, O_WRONLY 将读取以 O_WRONLY 字节开始的四个字节到 edx 寄存器中,所以 edx 的值为 0x400201 (O_CREAT*0x10000+O_RDWR*0x100+O_WRONLY)。

在第二种情况下,edx 将包含 O_WRONLY 的地址而不是值。

这个值在任何情况下都是错误的。

关于linux - 创建/写入文件 x86 Linux,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45786253/

相关文章:

linux - lpr 命令不适用于 CYGWIN。

linux - rsync 错误 : received SIGINT, SIGTERM 或 SIGHUP(代码 20)位于 rsync.c(544) [sender=3.0.6]

汇编代码未按预期工作

c++ - 是否可以访问物理地址0?

python - 无法将 Django 管理命令添加到我的开发环境中的项目

linux - 此 makefile 语句 : export SRVHOME ` or\` dirname $0 =`readlink -f\` 中的符号\`/../` 是什么意思

assembly - 比较 '+' 符号程序集 x86

c++ - 被调用者如何知道参数是通过寄存器而不是堆栈传递的

c - GDB 调用不在 main 中的函数

linux - 在 x86 nasm 中除法时出现浮点异常