2014-03-19 1 views
4

나는 'O'와 'K'다음에 개행 문자를 인쇄하기위한 간단한 64 비트 어셈블리 프로그램이 있습니다. 그러나 'K'는 절대로 인쇄되지 않습니다. 이 프로그램의 목표 중 하나는 rax 레지스터의 하위 비트에있는 값을 ASCII 문자로 인쇄하는 것입니다. 이 프로그램은 교육용으로 작성된 64 비트 Linux 전용이므로 C 스타일 시스템 호출을 사용할 필요가 없습니다.64 비트 Linux에서 인터럽트 0x80 사용

문제가 mov QWORD [rsp], rax 또는 mov rcx, rsp 인 것으로 의심됩니다.

현재 프로그램은 'O'다음에 개행 문자 만 출력합니다.

어떻게하면 렉스의 값을 사용하도록 프로그램을 변경 한 다음 'K'를 출력하여 전체 출력이 'OK'다음에 개행이되도록 할 수 있습니까?

bits 64 

section .data 

o: db "O"  ; 'O' 
nl: dq 10  ; newline 

section .text 

;--- function main --- 
global main   ; make label available to the linker 
global _start  ; make label available to the linker 
_start:    ; starting point of the program 
main:    ; name of the function 

;--- call interrupt 0x80 --- 
mov rax, 4   ; function call: 4 
mov rbx, 1   ; parameter #1 is 1 
mov rcx, o   ; parameter #2 is &o 
mov rdx, 1   ; parameter #3 is length of string 
int 0x80   ; perform the call 

;--- rax = 'K' --- 
mov rax, 75   ; rax = 75 

;--- call interrupt 0x80 --- 
sub rsp, 8   ; make some space for storing rax on the stack 
mov QWORD [rsp], rax  ; move rax to a memory location on the stack 
mov rax, 4   ; function call: 4 
mov rbx, 1   ; parameter #1 is 1 
mov rcx, rsp   ; parameter #2 is rsp 
mov rdx, 1   ; parameter #3 is length of string 
int 0x80   ; perform the call 
add rsp, 8   ; move the stack pointer back 

;--- call interrupt 0x80 --- 
mov rax, 4   ; function call: 4 
mov rbx, 1   ; parameter #1 is 1 
mov rcx, nl   ; parameter #2 is nl 
mov rdx, 1   ; parameter #3 is length of string 
int 0x80   ; perform the call 

;--- exit program --- 
mov rax, 1   ; function call: 1 
xor rbx, rbx   ; return code 0 
int 0x80   ; exit program 

답변

4

분명히 64 비트 프로그램을 작성하고 "int 0x80"명령을 사용합니다. 그러나 "int 0x80"은 32 비트 프로그램에서만 올바르게 작동합니다.

스택의 주소가 32 비트 프로그램에서 액세스 할 수없는 범위에 있습니다. 따라서 "int 0x80"스타일 시스템 호출이이 메모리 영역에 액세스하는 것을 허용하지 않을 가능성이 큽니다. 32 비트 프로그램 등

  • 컴파일 (RAX 같이 EAX와 같은 32 비트 레지스터 대신에 64 비트 레지스터를 사용)

    는 두 가지 가능성이있다이 문제를 해결한다. 공유 라이브러리를 사용하지 않고 링크하면 32 비트 프로그램이 64 비트 Linux에서 완벽하게 작동합니다.
  • "int 0x80"스타일 시스템 호출 대신 "syscall"스타일 시스템 호출을 사용하십시오. 이것들의 사용은 "int 0x80"스타일의 것들과 많이 다릅니다!

32 비트 코드 :

mov eax,4 ; In "int 0x80" style 4 means: write 
mov ebx,1 ; ... and the first arg. is stored in ebx 
mov ecx,esp ; ... and the second arg. is stored in ecx 
mov edx,1 ; ... and the third arg. is stored in edx 
int 0x80 

64 비트 코드 :

mov rax,1 ; In "syscall" style 1 means: write 
mov rdi,1 ; ... and the first arg. is stored in rdi (not rbx) 
mov rsi,rsp ; ... and the second arg. is stored in rsi (not rcx) 
mov rdx,1 ; ... and the third arg. is stored in rdx 
syscall 

편집 --- ---

배경 정보 :

"int 0x80"은 32-bi 용입니다. t 프로그램. 64 비트 프로그램에서 호출 될 때 32 비트 프로그램에서 호출 된 것처럼 동작합니다 (32 비트 호출 규칙 사용).

"int 0x80"의 매개 변수는 의 32 비트 레지스터에 전달되고 64 비트 레지스터의 상위 32 비트는 무시됩니다.

이 다소 만 이하로 메모리에 접근 할 수 있다는 것을 의미 (I는 우분투 16.10 64 비트. 해당 시험) 2^32 "INT 0x80으로"사용하는 경우 (또는 31^2 이하)을 때문에 32 비트 레지스터에서 2^32보다 큰 주소를 전달할 수 없습니다.

쓰여질 데이터가 2^31 이하의 주소에있는 경우 "int 0x80"을 사용하여 데이터를 쓸 수 있습니다. 그것이 2^32 이상이면 당신은 할 수 없습니다. 스택 (RSP)은 2^32 이상에 위치 할 가능성이 높으므로 "int 0x80"을 사용하여 스택에 데이터를 쓸 수 없습니다.

프로그램이 2^32 이상의 메모리를 사용할 가능성이 높기 때문에 "int 0x80은 64 비트 프로그램에서 작동하지 않습니다."라고 썼습니다.

+0

eax, ebx, ecx 및 edx 대신 rax, rdi, rsi 및 rdx를 사용하고''int 0x80'''을''''syscall'''으로 변경하면 프로그램이 " O "와 개행 문자가 있습니다. 32 비트 버전이 올바르게 작동합니다. – Alexander

+2

'int 0x80'도 64 비트 모드에서도 작동하지만 64 비트 호출 규칙 (레지스터와 syscall 번호를 사용해야 함)을 따라야합니다. – Jester

+0

@jester 제 답변에 좀 더 명확하게 "편집"을 추가했습니다. –