我正在尝试(至少)读取文件的第一行。我正在使用syscalls打开和关闭文件,但似乎从文件读取内容时遇到了问题,因为结果只是一些未知的符号。
helm way
像.data
name: .string "temp.txt"
fd: .byte 0
buf: .string "0"
len: .long 512
.text
.globl main
.type main, @function
main:
# open file
movl $5, %eax # sys_open
movl $name, %ebx
movl $0, %ecx # access: read-only
movl $0777, %edx # read, write and execute by all
int $0x80
# get file descriptor
movl %eax, fd
# read from file
movl $3, %eax # sys_read
movl $fd, %ebx
movl $buf, %ecx
movl $len, %edx
int $0x80
# close file
movl $6, %eax # sys_close
movl $name, %ebx
int $0x80
# print
movl $4, %eax
movl $1, %ebx
movl $fd,%ecx
movl $len, %edx
int $0x80
# exit(0)
movl $1, %eax
movl $0, %ebx
int $0x80
.size main, . - main
一样编译并运行gcc code.s -o code
答案 0 :(得分:2)
有三个错误:
首先,将eax
存储到fd
就像fd
的长度为4字节,但实际上只有1字节的长度。然后,将fd
的地址放入ebx
中,而不是从fd
加载的值中。这给出了一些指向系统调用的随机指针,该指针当然是无效的文件描述符。
请注意,添加适当的错误处理至少可以避免第二个问题。
此外,正如Wumpus Q. Wumbley所说,您不应将文件描述符存储在单个字节中,因为其值可能会超过255。要解决这两个问题,请首先通过分配fd
的大小来使其为4字节.int
中的空格:
fd: .int 0
这立即解决了第一个问题。要解决第二个问题,请从ebx
而不是fd
加载$fd
:
mov fd, %ebx
最终的错误位于您执行movl $fd,%ecx
和movl $len, %edx
的“打印”块中。这等效于C,例如write(1, &fd, &len)
。 (再次使用len的 address 作为长度,而不是从内存中加载)。并且您可能希望传递buf
的地址(用于读取文件数据的地址),而不是传递存储整数(非ASCII)的fd
的地址。因此,您需要write(1, buf, len)
,而不是write(1, &fd, len)
。
或者更好,如果不是错误代码,则应使用返回值read
作为write
的长度。您不想write()填充字节。但是,如果这样做,则可以使len
为汇编时常量,而不是将其存储在内存中。使用.equ
使汇编器在汇编时计算缓冲区长度,因此可以使用mov $len, %edx
请注意,在每个系统调用之后,您应该检查系统调用是否成功。您可以通过检查结果是否为负(严格来说是负,并且其绝对值小于4096)来实现。如果是,则发生错误,并且错误代码为否定结果。如果您处理了所有错误,则很容易看到程序在哪里以及为什么失败。
您还可以使用strace
实用程序来跟踪程序执行的系统调用,并解码args。