1

我尝试cat>filename使用系统调用在 Ubuntu 11.04 的 NASM 中实现命令。我的程序编译成功并成功运行(似乎如此)。但是,每当我尝试触发cat filename命令时,它都会显示“没有这样的文件或目录”,但我看到该文件位于目录中。如果我尝试通过双击打开文件,它会显示“您没有打开文件所需的权限”。你能帮我找出我的代码中的错误吗?

代码如下:

section .data
   msg:     dd "%d",10,0    
   msg1:    db "cat>",0
   length:  equ $-msg1
section .bss
   a    resb 100
       len1 equ $-a
   b    resd 1
   c    resb 100       
   len2 equ $-c
section .txt
  global main
main:
  mov eax,4   ;;it will print cat>
  mov ebx,1
  mov ecx,msg1
  mov edx,length
  int 80h
start:
  mov eax,3   ;;it will take the file name as input
  mov ebx,0
  mov ecx,a
  mov edx,len1
  int 80h

  mov eax,5   ;;it will create the file by giving owner read/write/exec permission
  mov ebx,a
  mov ecx,0100  
  mov edx,1c0h
  int 80h

  cmp eax,0
  jge inputAndWrite
  jmp errorSegment

inputAndWrite:
  mov [b],eax   

  mov eax,3   ;;take the input lines
  mov ebx,0
  mov ecx,c
  mov edx,len2
  int 80h

  mov edx,eax   ;;write the input lines in the file
  mov eax,4
  mov ebx,[b]
  mov ecx,c
  int 80h   

  jmp done  
errorSegment:   
  jmp done
done:   
  mov eax, 1 
  xor ebx, ebx 
  int 80h 

ps 以上代码是根据RageD的建议重新编辑的。然而,我创建的文件不包含从“inputAndWrite”段给出的任何输入行。我正在寻找你的建议。

4

1 回答 1

3

您的权限的主要问题是权限在octal并且您已将它们列出在decimal. 您正在寻找以07008 为底,而不是 10 为底。因此,您可以尝试使用1c0h0700十六进制的八进制)。因此,以下代码修复应该可以解决您的权限问题:

;; This is file creation
mov eax, 5
mov ebx, a
mov ecx, 01h ; Edited here for completeness - forgot to update this initially (see edit)
mov edx, 1c0h

供您参考,Linux 系统调用的快速指南(可能有些过时,但大部分是正确的)是使用Linux 系统调用表。这对于记住需要如何设置寄存器等非常有帮助。

另一个关键问题是写入文件。我认为你在一些问题上有点困惑。首先,小心你的长度变量。组装是“在线”完成的,也就是说,当您计算 len1 时,您会计算 之间的距离a加上之间的所有内容ato len1。也就是说,您的长度值应如下所示:

.section bss
a resb 100
len1 equ $ - a
b resd 1
c resb 100
len2 equ $ - c

这样做应该确保你有正确的读取(尽管重要的是要注意你在这里输入的缓冲区大小受到限制)。

我发现的另一个关键问题是您如何尝试写入文件。你翻转了系统调用寄存器。

;; Write to file
mov edx, eax ;; Amount of data to write
mov eax, 4 ;; Write syscall
mov ebx, [b] ;; File descriptor to write out to (I think this is where you stored this, I don't remember exactly)
mov ecx, c ;; Buffer to write out

从这里开始,我会再做一些调整。首先,为了很好地结束(没有段错误),我建议简单地使用exit. 除非这是在另一个程序中,ret否则可能并不总是正常工作(特别是如果这是一个独立的 x86 程序)。退出系统调用的代码如下:

;; Exit
mov eax, 1 ;; Exit is syscall 1
xor ebx, ebx ;; This is the return value
int 80h ;; Interrupt

另外,至于清洁度,我假设您正在接受由换行符缓冲的输入。如果是这种情况,我建议去掉文件名后的换行符。最简单的方法是在最后一个字符(将是新行)之后简单地以空终止。因此,在读取文件名的输入后,我将放置一些类似于此的代码:

;; Null-terminate the last character - this assumes it directly follows the read call
;; and so the contents of eax are the amount of bytes read
mov ebx, eax ;; How many bytes read (or offset to current null-terminator)
sub ebx, 1 ;; Offset in array to the last valid character
add ebx, a ;; Add the memory address (i.e. in C this looks like a[OFFSET])
mov BYTE [ebx], 0 ;; Null-terminated

最后,在大型项目中,完成后关闭文件描述符是有礼貌的。由于您将立即退出,因此此处可能没有必要,但这看起来像:

;; Close fd
mov eax, 6 ;; close() is syscall 6
mov ebx, [b] ;; File descriptor to close
int 80h

编辑

对不起,我错过了写作问题。您正在使用 value 打开文件100。您想要的是1O_RDWR读取和写入功能)。此外,您可能需要考虑简单地使用sync系统调用(0x24不带参数的系统调用号)来确保正确刷新缓冲区;但是,在我的测试中,这是不必要的,因为输入数据的换行符在技术上应该这样做,我相信。因此,正确打开文件的更新代码应如下所示:

; Open file
mov eax, 5
mov ebx, a
mov ecx, 01h
mov edx, 1c0h
int 80h

希望这可以帮助。祝你好运!

于 2013-04-10T01:35:12.757 回答