2011-12-11 42 views
5

Tôi đang cố xác định một số chương trình con có các cuộc gọi đến printf trong chúng. Một ví dụ rất tầm thường như sau:các chương trình con hội họp được gọi hai lần mà không bị gọi từ chính

extern printf 
LINUX  equ  80H 
EXIT   equ  60 

section .data 
    intfmt: db "%ld", 10, 0 

segment .text 
    global main 

main: 
    call os_return  ; return to operating system 

os_return: 
    mov rax, EXIT  ; Linux system call 60 i.e. exit() 
    mov rdi, 0  ; Error code 0 i.e. no errors 
    int LINUX  ; Interrupt Linux kernel 

test: 
    push rdi 
    push rsi 
    mov rsi, 10 
    mov rdi, intfmt 
    xor rax, rax 
    call printf 
    pop rdi 
    pop rsi 
    ret 

đây kiểm tra chỉ có một cuộc gọi đến printf rằng kết quả đầu ra số lượng từ 10 đến màn hình. Tôi sẽ không mong đợi điều này để được gọi là tôi không có cuộc gọi đến nó.

Tuy nhiên khi biên dịch và chạy:

nasm -f elf64 test.asm 
gcc -m64 -o test test.o 

tôi nhận được kết quả:

10 
10 

Tôi hoàn toàn bối rối và tự hỏi nếu ai đó có thể giải thích tại sao điều này xảy ra?

Trả lời

3

int 80H gọi giao diện cuộc gọi hệ thống 32 bit, trong đó a) sử dụng số gọi hệ thống 32 bit và b) được dùng để sử dụng mã 32 bit chứ không phải mã 64 bit. Mã của bạn thực sự đang thực hiện cuộc gọi hệ thống umask với thông số ngẫu nhiên.

Đối với một cuộc gọi hệ thống 64-bit, sử dụng syscall hướng dẫn thay vì:

... 
os_return: 
    mov rax, EXIT  ; Linux system call 60 i.e. exit() 
    mov rdi, 0  ; Error code 0 i.e. no errors 
    syscall   ; Interrupt Linux kernel 
... 
+0

Cảm ơn! Tôi có đặt giá trị 60 (EXIT) vào rdi sau đó thay vì rax, tương tự như gọi printf? –

+0

Không, đặt số syscall trong 'rax' và đối số đầu tiên trong' rdi' là chính xác. Xem http://www.x86-64.org/documentation/abi.pdf (phụ lục A đặc biệt) cho một số tài liệu về syscall ABI hạt nhân và sự khác biệt từ các quy ước gọi điện cấp người dùng. –

+0

Xin lỗi để giữ cho bạn xấu về điều này nhưng tôi đã thay đổi dòng "int LINUX" để gọi syscall và thêm syscall extern vào đầu và vẫn nhận được hai của mười. Có cơ hội nào bạn có thể chỉ cho tôi một ví dụ nhỏ về cách gọi syscall không? Cảm ơn rất nhiều :) –

2

tôi sẽ nói rằng cuộc gọi của bạn để exit là không, vì vậy khi nó trả về, nó rơi thông qua các test chức năng, mà in đầu tiên 10

Sau đó, khi bạn quay trở lại với ret bạn quay trở lại giảng dạy chỉ sau call os_return, tức là, cũng os_return. Cuộc gọi để thoát không thành công một lần nữa và rơi vào chức năng test một lần nữa. Nhưng lần này, trả về ret từ chức năng main và chương trình kết thúc.

Tại sao cuộc gọi exit bị lỗi, tôi không thể nói là tôi không có hệ thống 64 bit. Nhưng bạn có thể tháo rời hàm exit khỏi libc và xem cách nó được thực hiện ở đó. Tôi đoán là giao diện int LINUX chỉ là 32 bit, vì nó chỉ tồn tại đối với tính tương thích lịch sử và Linux 64 bit không quá cũ.

Các vấn đề liên quan