【问题标题】:assembly code to open file wrong汇编代码打开文件错误
【发布时间】:2014-12-02 23:57:28
【问题描述】:

我从书中复制了一些代码,它只是从文件中读取文本,转换为大写,然后写入另一个文件。我只是将 32 位代码翻译成 Linux 64 位代码。

.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

但是代码无法打开文件。

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

文件描述不应为负值。看起来代码很简单,但是为什么呢?

提前致谢!

【问题讨论】:

  • 您正在运行 64 位程序。在 64 位 x86-64 linux 上,系统调用不是通过 int(errupt) 完成的,而是通过 syscall/sysenter 完成的。
  • 但是我在其他程序上试过,int 0x80 可以。
  • 我刚刚尝试了syscall,它的工作方式与int 0x80相同,获取-14作为文件描述符。

标签: assembly


【解决方案1】:

终于,我找到了答案。

x86_64 与 x86_32 不同:

1 它们有不同的调用约定(ABI),x64 通过寄存器传递一些参数,p。 x86-64 ABI中的21个有很好的解释。

2 他们有不同的系统调用代码。检查this post。在 x86_32 中,开放系统调用代码为 5,而在 x86_64 中为 2

代码应如下所示:

  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)

【讨论】:

  • 如果你想从 c 而不是 asm 调用它,你可以查看stackoverflow.com/a/25346514/2189500。虽然这是调用不同的函数,但使用 syscall 的基础知识就在那里。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-12-25
  • 2016-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多