我尝试使用系统调用在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"的任何输入行。分割。我正在寻找你的建议。
答案 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
加上a
到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
修改强>
抱歉,我错过了写作问题。您正在使用值100
打开文件。对于1
(读写功能),您想要的是O_RDWR
。此外,您可能需要考虑简单地使用sync
系统调用(没有参数的系统调用号0x24
)来确保正确刷新缓冲区;但是,在我的测试中,这是不必要的,因为输入数据的换行应该在技术上做到这一点,我相信。因此,正确打开文件的代码更新位应如下所示:
; Open file
mov eax, 5
mov ebx, a
mov ecx, 01h
mov edx, 1c0h
int 80h
希望这会有所帮助。祝你好运!