2011-12-11 4 views
5

printf를 호출하는 몇 가지 서브 루틴을 정의하려고합니다. 다음 아주 사소한 예이다 : 여기서어셈블리 서브 루틴은 메인에서 호출조차하지 않고 두 번 호출됩니다.

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 

테스트는 화면에 출력 번호 10의 printf 호출을 갖는다. 내가 전화를받지 않아도 전화가 걸릴 것으로 기대하지는 않는다.

그러나 컴파일하고 실행하는 경우 :
nasm -f elf64 test.asm 
gcc -m64 -o test test.o 

내가 출력을 얻을 :

10 
10 

을 나는 완전히 당황 누군가가 이런 일이 이유를 설명 할 수 있다면 궁금 해요?

답변

3

int 80H은 a) 32 비트 시스템 호출 번호를 사용하고 b) 64 비트 코드가 아닌 32 비트 코드에서 사용하기위한 것입니다. 귀하의 코드는 실제로 무작위 매개 변수를 사용하여 umask 시스템 호출을 수행하고 있습니다.

... 
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

감사합니다 : 64 비트 시스템 호출에 대한

는 대신 syscall 명령을 사용! printf를 호출하는 것과 마찬가지로 rax 대신 rdi에 값 60 (EXIT)을 넣습니까? –

+0

아니요,'rax'에 syscall 번호를 넣고'rdi'에 첫 번째 인자를 넣는 것이 정확합니다. 커널 syscall ABI의 일부 문서 및 사용자 수준 호출 규칙과의 차이점은 http://www.x86-64.org/documentation/abi.pdf (특히 부록 A)를 참조하십시오. –

+0

계속해서 미안하지만, "int LINUX"라는 줄을 변경하여 syscall을 호출하고 extern syscall을 맨 위에 추가하고 여전히 10 개를 얻습니다. 당신이 저의 전화하는 방법에 대한 간단한 예를 보여줄 수 있습니까? 고마워요 :) –

2

당신이 ret에 반환 할 때 명령어로 돌아가 나는 exit로 호출이 실패하고 말 것, 그래서 반환 할 때, 그 다음 첫번째 (10)

를 인쇄하는의 test 기능을 통해 떨어진다 call os_return 바로 뒤에, 즉, 잘 os_return입니다. 종료 호출이 다시 실패하고 test 함수로 다시 전달됩니다. 그러나 이번에는 retmain 함수에서 돌아오고 프로그램이 종료됩니다.

exit 호출이 실패하는 이유는 무엇입니까? 64 비트 시스템을 사용할 수 없어서 말할 수 없습니다. 하지만 libc에서 exit 함수를 분해하고 어떻게 수행되는지 볼 수 있습니다. 내 생각에, int LINUX 인터페이스는 역사적인 호환성을 위해 존재하기 때문에 32 비트 전용이며 64 비트 리눅스는 그리 오래되지 않았습니다.