0

I copy some code from a book, It just read text from a file, convert to uppercase, then write to another file. I just translate 32bit code to Linux 64bit one.

.section .data

# system call code
.equ SYS_OPEN,  5
.equ SYS_WRITE, 4
.equ SYS_READ,  3
.equ SYS_CLOSE, 6
.equ SYS_EXIT,  1

# standard file description
.equ STDIN, 0
.equ STDOUT, 1
.equ STDERR, 2

# file open options
.equ O_RDONLY, 0
.equ O_CREAT_WRONLY_TRUNC, 03101

#system call interuption
.equ LINUX_SYSCALL, 0x80

# for read file end
.equ END_OF_FILE, 0

.equ NUM_ARGUMENTS, 2


.section .bss

.equ BUFFER_SIZE, 500
.lcomm BUFFER_DATA, BUFFER_SIZE


.section .text

# stack position
.equ ST_SIZE_RESERVE, 16
.equ ST_FD_IN,   -8
.equ ST_FD_OUT, -16
.equ ST_ARGC, 0
.equ ST_ARGV_0, 8       # program name
.equ ST_ARGV_1, 16      # input file name
.equ ST_ARGV_2, 24      # output file name

.global _start

_start:

  mov %rsp, %rbp
  sub $ST_SIZE_RESERVE, %rsp

open_file:
open_fd_in:

  mov $SYS_OPEN, %rax
  mov ST_ARGV_1(%rbp), %rbx
  mov $O_RDONLY, %rcx
  mov $0666, %rdx
  # call linux 
  int $LINUX_SYSCALL

store_fd_in:
  mov %rax, ST_FD_IN(%rbp)


open_fd_out:

  mov $SYS_OPEN, %rax
  mov ST_ARGV_2(%rbp), %rbx
  mov $O_CREAT_WRONLY_TRUNC, %rcx
  mov $0666, %rdx
  int $LINUX_SYSCALL

store_fd_out:
  mov %rax, ST_FD_OUT(%rbp)


# main loop
read_loop_begin:
  mov $SYS_READ, %rax
  mov ST_FD_IN(%rbp), %rbx
  mov $BUFFER_DATA, %rcx
  mov $BUFFER_SIZE, %rdx
  int $LINUX_SYSCALL
  # check if reach the end of the file
  cmp $END_OF_FILE, %rax
  jle end_loop

continue_read_loop:
  push $BUFFER_DATA       # buffer address
  push %rax               # buffer size
  call convert_to_upper
  pop %rax                # reget buffer size
  add $8, %rsp            # recover stack

  # write buffer to output file
  mov %rax, %rdx
  mov $SYS_WRITE, %rax
  mov ST_FD_OUT(%rbp), %rbx
  mov $BUFFER_DATA, %rcx
  int $LINUX_SYSCALL

  jmp read_loop_begin


end_loop:
  # close file
  mov $SYS_CLOSE, %rax
  mov ST_FD_OUT(%rbp), %rbx
  int $LINUX_SYSCALL

  mov $SYS_CLOSE, %rax
  mov ST_FD_IN(%rbp), %rbx
  int $LINUX_SYSCALL

  mov $SYS_EXIT, %rax
  mov $0, %ebx
  int $LINUX_SYSCALL


.equ LOWERCASE_A, 'a'
.equ LOWERCASE_Z, 'z'
.equ UPPER_CONVERSION, 'A' - 'a'

# stack relative information
.equ ST_BUFFER_LEN, 16
.equ ST_BUFFER, 24
convert_to_upper:
  push %rbp
  mov %rsp, %rbp

  mov ST_BUFFER(%rbp), %rax
  mov ST_BUFFER_LEN(%rbp), %rbx
  mov $0, %rdi

  # check if buffer is zero?
  cmp $0, %rbx
  je end_convert_loop

convert_loop:
  movb (%rax, %rdi, 1), %cl
  cmpb $LOWERCASE_A, %cl
  jl next_byte
  cmpb $LOWERCASE_Z, %cl
  jl next_byte

  addb $UPPER_CONVERSION, %cl
  movb %cl, (%rax, %rdi, 1)     # put back

next_byte:
  inc %rdi
  cmp %rdi, %rbx
  jne convert_loop

end_convert_loop:
  mov %rbp, %rsp
  pop %rbp
  ret

But the code fail to open file.

dan@ubuntu:~/labs/asm/file$ gdb ./cf
GNU gdb (Ubuntu 7.7-0ubuntu3.1) 7.7
Copyright (C) 2014 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-linux-gnu".
Type "show configuration" for configuration details.
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>.
Find the GDB manual and other documentation resources online at:
<http://www.gnu.org/software/gdb/documentation/>.
For help, type "help".
Type "apropos word" to search for commands related to "word"...
Reading symbols from ./cf...done.
(gdb) set args lower.txt upper.txt
(gdb) b 58
Breakpoint 1 at 0x4000c9: file cf.s, line 58.
(gdb) run
Starting program: /home/dan/labs/asm/file/cf lower.txt upper.txt

Breakpoint 1, open_file () at cf.s:58
58    mov $0666, %rdx
(gdb) x /s $rbx
0x7fffffffe8b0: "lower.txt"
(gdb) step
60    int $LINUX_SYSCALL
(gdb) step
store_fd_in () at cf.s:63
63    mov %rax, ST_FD_IN(%rbp)
(gdb) p /d $rax
$1 = -14

the file description should not be a negative value. It seems that the code it's very simple, But why?

Thanks in advance!

Dan
  • 3,221
  • 7
  • 27
  • 24
  • You're running a 64-bit program. On 64-bit x86-64 linux, system calls are **not** done via `int`(errupt), but rather with `syscall/sysenter`. – EOF Oct 08 '14 at 12:13
  • But I had tried on other program, int 0x80 works. – Dan Oct 08 '14 at 14:30
  • I have just tried syscall, it works the same as int 0x80, get -14 as the file descriptor. – Dan Oct 08 '14 at 14:44

1 Answers1

0

Finally, I find the answer.

x86_64 is different to x86_32:

1 they have different calling convention(ABI), x64 pass some parameters via registers, p. 21 of the x86-64 ABI has a good explanation.

2 they have different system call code. check this post. In x86_32, open system call code is 5, while in x86_64 it's 2

the code should look like this one:

  mov $SYS_OPEN, %rax        # open operation, code is 2
  mov ST_ARGV_1(%rbp), %rdi  # input file name
  mov $O_RDONLY, %rsi        # flags
  #mov $0666, %rdx            # mode
  # call linux 
  syscall
store_fd_in:
  mov %rax, ST_FD_IN(%rbp)
Community
  • 1
  • 1
Dan
  • 3,221
  • 7
  • 27
  • 24
  • If you want to call this from c instead of asm, you can check out http://stackoverflow.com/a/25346514/2189500. While that is calling a different function, the basics of using syscall are there. – David Wohlferd Oct 08 '14 at 22:08