2017-10-30 15 views
0

NASM 어셈블러를 배우고 있으며 라인 피드를 처리하는 중 순간에 고생하고 있습니다.NASM의 스택에 PUSH 된 줄 바꿈을 인쇄 할 수 없습니다

어떻게 줄 바꿈을 인쇄합니까? 내가 보여줄거야. 중 하나를 사용할 수있는

sprint: 
    push rdx 
    push rbx 
    push rax 
    push rcx 
    mov rax, rcx 
    pop rcx 
    jmp next_char 
    ret 

sprint_syscall: 
    mov rbx, 1 
    mov rax, 4 
    int 80h 
    pop rax 
    pop rbx 
    pop rdx 
    ret 

sprint_linefeed: 
    call sprint 
    push rcx 
    mov rcx, 0Ah 
    push rcx 
    mov rcx, rsp 
    call sprint 
    pop rcx 
    pop rcx 
    ret 

next_char: 
    cmp byte [rax], 0 
    jz count_length 
    inc rax 
    jmp next_char 

count_length: 
    sub rax, rcx 
    mov rdx, rax 
    jmp sprint_syscall 

quit: 
    push rbx 
    push rax 
    mov rbx, 0 
    mov rax, 1 
    int 80h 
    pop rax 
    pop rbx 
    ret 

메인 응용 프로그램 : 나는 학습을 위해 준비했습니다

$ uname -a 
Linux 4.4.0-97-generiC#120-Ubuntu SMP Tue Sep 19 17:28:18 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux 

$ lsb_release -a 
No LSB modules are available. 
Distributor ID : Ubuntu 
Description : Ubuntu 16.04.3 LTS 
Release  : 16.04 
Codename  : xenial 

내 기능 : 나는 그것을 보여하지만 그 전에, 내 플랫폼에 대해 얘기하는 것이 중요합니다 주어진 기능 :

%include 'functions.asm' 

SECTION .data 
    msgFirst db "Hello World!", 0h 
    msgSecond db "Another string.", 0h 

SECTION .text 
global _start 

_start: 
    mov rcx, msgFirst 
    call sprint_linefeed 
    mov rcx, msgSecond 
    call sprint_linefeed 
    call quit 

모두 잘 컴파일되고 작동합니다. 와/링크를 컴파일 할 경우에도 불구하고, 당신이 볼 수 있듯이

Hello World!Another string 

어떤 라인 피드이되지 않은 :

nasm -g -f elf64 -l main.lst main.asm -o main.o && ld main.o -o main 

을 그리고 컴파일 된 응용 프로그램을 실행, 우리가 볼 수있어

sprint_linefeed: 
    call sprint 
    push rcx  ; push rcx onto the stack to preserve it 
    mov rcx, 0Ah ; move 0Ah into rcx, 0Ah is the ASCII char for a linefeed 
    push rcx  ; push the linefeed char onto the stack 
    mov rcx, rsp ; move the address of the pointer into rcx for the 'sys_write' syscall 
    call sprint 
    pop rcx  ; remove the linefeed char from the stack 
    pop rcx  ; restore the original value of rcx 
    ret 

그래서, 내 행동의 설명은을 참조 : 줄 바꿈을 인쇄하기 위해 다음 지침을 사용하는 sprint_linefeed 함수를 호출에주어진 문자열을 호출 한 다음 0Ah 문자를 스택으로 푸시합니다. 나중에 sprint() 함수를 다시 호출하기 위해 RSP 레지스터에서 포인터를 가져옵니다. syscall이 주어진 문자열 (http://fresh.flatassembler.net/lscr/data/004.html)을 인쇄하기 위해 포인터를 필요로하기 때문에 완료되었습니다.

SECTION .data 
    msgFirst db "Hello World!", 0Ah, 0h 

이 같은 함수를 호출하지만, sprint_linefeed() 정의 되었기 때문에 다른 문자열 값으로, 우리에게 기다려온 결과를 제공하지만, 그것은 아무 의미 :

경우 문자열 선언에 OAh 문자를 추가합니다 여분의 ASCII-char의 선언을 전달합니다.

sprint_linefeed()이 잘 작동하려면 소스 코드에서 무엇을 수정해야합니까?

+2

64 비트 코드에서 'int 80h'을 사용하지 마십시오. 32 비트 호환성 시스템 호출 인터페이스입니다. [64 비트 코드에서 32 비트 int 0x80 Linux ABI를 사용하면 어떻게됩니까?] (https://stackoverflow.com/questions/46087730/what-happens-if-you-use-the-32-bit) -int-0x80-linux-abi-in-64-bit-code) – Jester

+0

@Jester 조언을 주셔서 감사합니다. – Neverlands

+1

'rsp'는 32b 경계를 넘을 가능성이 매우 높으므로'int 0x80'은 스택 메모리에서'0A' 문자열을 읽지 못합니다.'strace'를 사용하여 시스템 호출이 무엇을 반환하는지 확인해보기를 권합니다. 그러나 64b 바이너리의'int 0x80'도 실제로 혼란 스러울 것입니다. 그래서 출력은 그다지 중요하지 않습니다. asm을 32b로 다시 작성하고 elf32로 컴파일하거나 시스템 호출을 수정하십시오. – Ped7g

답변

1

@Neverlands 내가 sprint_linefeed를 제거하여 functions.asm에 작은 변화를 만들어 파일의 맨 위에 다음을 넣어 :

%define newline 0Ah 

SECTION .data 
    lineEnding db newline, 0h 

sprint_linefeed: 
    call sprint 
    mov rcx, lineEnding 
    call sprint 
    ret 

그것은 당신이 원하는하지만 줄 않습니다 정확히 무엇을하지 않을 수 있습니다 :

Hello World! 
Another string. 

출력. 재미있어!

+0

동정,하지만 내가 원한 것이 아니 었습니다. 줄 바꿈을 문자열 정의에 정의하지 않고 내부 함수에서 줄 바꿈을 정확히 처리하려고합니다. 당신이 제공 한 방식은 이미 내 질문 내용의 끝에 언급되어 있습니다 ('% define'이 없어도). – Neverlands

+0

하지만 조금 더 가까이서 조금 보았는데 당신이 알아낼 것이라고 생각합니다. lineEnding과 msgFirst와 msgSecond 끝이 NUL –

+2

으로 끝나고 @KenSchumack'mov rcx, 0Ah' push rcx가 스택 메모리에 8 바이트 '0A 00 00 00 00 00 00 00'으로 설정되어 ** ** 이미 충분히 종결되었습니다. OP 문제는 스택의 개행 문자열에 대해 32b 메모리 경계를 넘는 방식처럼 꽤 옆으로 쳐다보아야한다는 것입니다. 그리고 'int 0x80'은 결코 그렇게 할 수 없습니다. '.data'에있는 당신의 문자열은 접근 가능합니다. 그래서 잘못된 시스템 호출로도 작동합니다. – Ped7g