2014-10-08 140 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