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