在NASM中实现cat> fileName命令

时间:2013-04-09 22:36:27

标签: linux assembly x86 nasm i386

我尝试使用系统调用在Ubuntu 11.04中的NASM中实现cat>filename命令。我的程序编译成功并成功运行(似乎是这样)。但每当我尝试触发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 

P.S。通过RageD的建议重新编辑上述代码。然而,我创建的文件不包含来自" inputAndWrite"的任何输入行。分割。我正在寻找你的建议。

1 个答案:

答案 0 :(得分:3)

您的权限主要问题是权限位于octal,您已将其列在decimal中。您正在寻找基数为8的0700,而不是基数10.因此,您可以尝试使用1c0h(十六进制的0700八进制数)。因此,以下代码修复应修复您的权限问题:

;; 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 System Call Table。它非常有助于记住如何设置寄存器等等。

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

.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

修改

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

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

希望这会有所帮助。祝你好运!