Reputation: 390
I'm trying to read (at least) first line of the file. I'm using syscalls to open and close file, but it seems I have a problem with reading contents from file, because the result is just some unknown symbol.
.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
Compiling it like gcc code.s -o code
and running ./code
Upvotes: 0
Views: 858
Reputation: 93127
There are three errors:
First, you store eax
to fd
as if fd
was 4 byte long, but it's actually only 1 byte long. Then you put the address of fd
into ebx
, not a value loaded from fd
. This gives some random pointer to the system call which is of course an invalid file descriptor.
Note that adding proper error handling would have avoided at least the second problem.
In addition, as Wumpus Q. Wumbley said, you should not store a file descriptor in a single byte as its value may exceed 255. To fix both issues, first make fd
a 4 byte quantity by allocating its space with .int
:
fd: .int 0
this immediately fixes the first issue. To fix the second issue, load ebx
from fd
, not $fd
:
mov fd, %ebx
The final errors are in the "print" block where you do movl $fd,%ecx
and movl $len, %edx
. This is equivalent to C like write(1, &fd, &len)
. (Again using the address of len as the length, instead of loading from memory). And you probably want to pass the address of buf
(where you read the file data), not fd
where you stored an integer (not ASCII). So you want write(1, buf, len)
, not write(1, &fd, len)
.
Or better, you should use the return value of read
as the length for write
, if it's not an error code. You don't want to write() the filler bytes. But if you do, you could make len
an assemble-time constant instead of storing it in memory. Use .equ
to have the assembler calculate the buffer length at assemble time so you can use mov $len, %edx
Note that after each system call, you should check if the system call was successful. You can do so by checking if the result is negative (strictly speaking, negative and its absolute value smaller than 4096). If it is, an error occured and the error code is the negated result. If you handle all your errors, it's very easy to see where and why your program failed.
You can also use the strace
utility to trace the system calls your program performs, decoding args.
Upvotes: 2