Assembly 美国电话电报公司;读取文件

Assembly 美国电话电报公司;读取文件,assembly,att,Assembly,Att,我正在尝试读取(至少)文件的第一行。我使用syscalls来打开和关闭文件,但从文件中读取内容似乎有问题,因为结果只是一些未知的符号 .data name: .string "temp.txt" fd: .byte 0 buf: .string "0" len: .long 512 .text .globl main .type main, @function main: # open file

我正在尝试读取(至少)文件的第一行。我使用syscalls来打开和关闭文件,但从文件中读取内容似乎有问题,因为结果只是一些未知的符号

.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那样编译它,并运行
/code>有三个错误:

首先,将
eax
存储到
fd
中,就好像
fd
的长度为4字节,但实际上只有1字节。然后将
fd
的地址放入
ebx
,而不是从
fd
加载的值。这会给出一些指向系统调用的随机指针,这当然是一个无效的文件描述符

请注意,添加正确的错误处理至少可以避免第二个问题


此外,正如Wumpus Q.Wumbley所说,您不应该在单个字节中存储文件描述符,因为它的值可能超过255。要解决这两个问题,首先通过使用
.int
分配其空间,使
fd
成为一个4字节的数量:

fd: .int 0
这立即解决了第一个问题。要解决第二个问题,请从
fd
加载
ebx
,而不是
$fd

mov fd, %ebx

最后的错误出现在“打印”块中,在该块中执行
movl$fd,%ecx
movl$len,%edx
。这相当于类似C的
write(1,&fd,&len)
。(再次使用len的地址作为长度,而不是从内存加载)。您可能希望传递
buf
(读取文件数据的位置)的地址,而不是存储整数(非ASCII)的
fd
。因此,您需要
write(1,buf,len)
,而不是
write(1,&fd,len)

或者更好,如果不是错误代码,您应该使用
read
的返回值作为
write
的长度。您不想写入()填充字节。但是如果你这样做了,你可以把
len
作为一个汇编时间常数,而不是存储在内存中。使用
.eq
让汇编程序在汇编时计算缓冲区长度,以便您可以使用
mov$len,%edx


请注意,在每次系统调用之后,您应该检查系统调用是否成功。您可以通过检查结果是否为负(严格来说,为负且其绝对值小于4096)来执行此操作。如果是,则发生错误,错误代码为否定结果。如果你处理了所有的错误,很容易看出你的程序失败的地方和原因


您还可以使用
strace
实用程序跟踪程序执行的系统调用,解码参数。

有三个错误:

首先,将
eax
存储到
fd
中,就好像
fd
的长度为4字节,但实际上只有1字节。然后将
fd
的地址放入
ebx
,而不是从
fd
加载的值。这会给出一些指向系统调用的随机指针,这当然是一个无效的文件描述符

请注意,添加正确的错误处理至少可以避免第二个问题


此外,正如Wumpus Q.Wumbley所说,您不应该在单个字节中存储文件描述符,因为它的值可能超过255。要解决这两个问题,首先通过使用
.int
分配其空间,使
fd
成为一个4字节的数量:

fd: .int 0
这立即解决了第一个问题。要解决第二个问题,请从
fd
加载
ebx
,而不是
$fd

mov fd, %ebx

最后的错误出现在“打印”块中,在该块中执行
movl$fd,%ecx
movl$len,%edx
。这相当于类似C的
write(1,&fd,&len)
。(再次使用len的地址作为长度,而不是从内存加载)。您可能希望传递
buf
(读取文件数据的位置)的地址,而不是存储整数(非ASCII)的
fd
。因此,您需要
write(1,buf,len)
,而不是
write(1,&fd,len)

或者更好,如果不是错误代码,您应该使用
read
的返回值作为
write
的长度。您不想写入()填充字节。但是如果你这样做了,你可以把
len
作为一个汇编时间常数,而不是存储在内存中。使用
.eq
让汇编程序在汇编时计算缓冲区长度,以便您可以使用
mov$len,%edx


请注意,在每次系统调用之后,您应该检查系统调用是否成功。您可以通过检查结果是否为负(严格来说,为负且其绝对值小于4096)来执行此操作。如果是,则发生错误,错误代码为否定结果。如果你处理了所有的错误,很容易看出你的程序失败的地方和原因


您还可以使用
strace
实用程序跟踪程序执行的系统调用,对参数进行解码。

A
.byte
对于
fd
是不够的,我想您需要的是
fd
,而不是
$fd
。对于
write
,您需要
$buf
。或者更好,
mov%eax,%ebx
。使用调试器,并且
strace./code
。对于
fd
而言,一个
字节
是不够的,我想您需要的是
fd
,而不是
$fd
。对于
write
,您需要
$buf
。或者更好,
mov%eax,%ebx
。使用调试器,然后
strace./code
@PeterCordes感谢您的改进。@PeterCordes感谢您的改进。