2014-10-08 113 views
0

我从一本书复制一些代码,它只是从文件中读取文本,转换为大写,然后写入另一个文件。我只是将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 

但代码无法打开文件。

[email protected]:~/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 

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

在此先感谢!

+0

您运行的是64位程序。在64位x86-64 linux上,系统调用不是**通过“int”(中断)完成,而是通过“syscall/sysenter”完成。 – EOF 2014-10-08 12:13:41

+0

但我曾尝试过其他程序,int 0x80的作品。 – Dan 2014-10-08 14:30:49

+0

我刚刚尝试了系统调用,它的工作原理与int 0x80相同,得到-14作为文件描述符。 – Dan 2014-10-08 14:44:35

回答

0

最后,我找到了答案。

x86_64的是x86_32不同:

1它们具有不同的调用约定(ABI),64通过寄存器传递一些参数,第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) 
+0

如果你想从c而不是asm调用它,你可以查看http://stackoverflow.com/a/25346514/2189500。虽然这正在调用一个不同的函数,但使用系统调用的基础知识就在那里。 – 2014-10-08 22:08:15