Assembly 美国电话电报公司;读取文件
我正在尝试读取(至少)文件的第一行。我使用syscalls来打开和关闭文件,但从文件中读取内容似乎有问题,因为结果只是一些未知的符号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
.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感谢您的改进。