ans
ans

Reputation: 390

AT&T - reading file

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

Answers (1)

fuz
fuz

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

Related Questions