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,%ecxmovl $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。