2013-07-02 2 views
6

그래서 NASM 구문 (오 신, 다시는이 아니라고 생각합니다.)을 사용하는 x86 Linux 어셈블리를 배우고 있습니다. 단순히 표준 출력 EAX 값을 인쇄하는 서브 루틴을 만들려고 해요. 코드가 실행되고 오류없이 종료되지만 아무 것도 인쇄되지 않습니다. 나는 이유를 알 수 없다. (I 과감한 뭔가를보고 싶어하지 않는 한이 아마 무관하다)이이 모양 내 주요 파일에서Linux x86 NASM - 서브 루틴 : EAX에서 dword 인쇄

segment .bss 
    to_print: resd 1 

segment .text 
    global print_eax_val 

print_eax_val:     ;  (top) 
    push dword ebx   ;Stack: edx 
    push dword ecx   ;  ecx 
    push dword edx   ;  ebx 
           ;  (bot) 

    mov  ecx,eax    ;ecx = eax 

    mov  [to_print],ecx  ;to_print = ecx 

    mov  eax, 4    ;sys_write 
    mov  ebx, 1    ;to stdout 
    add  ecx, 47    ;add 47 for ASCII numbers 
    mov  edx, 2    ;double word = 2 bytes 
    int  0x80 

    mov  eax, [to_print]  ;eax = original val 
    pop  edx     ;pop the registers back from the stack 
    pop  ecx 
    pop  ebx     ;Stack: empty 

    ret 

라고 : 우선, 나는 여기에서 일하고 있어요 파일입니다.

segment .data 
     hello db  "Hello world!", 0 
     newline db  0xA 
     len  equ $ - hello 
     len2 equ $ - newline 

segment .text 
     extern print_nl 
     extern print_eax_val 
     global main 

main: 
     enter 0,0 

     call print_nl 

     mov  eax, 1 

     call print_eax_val 

     mov  ebx, 0   ;exit code = 0 (normal) 
     mov  eax, 1   ;exit command 
     int  0x80   ;ask kernel to quit 

print_nl 정의하고 개행 문자를 인쇄 또 다른 서브 루틴입니다. 이 성공적으로 실행되고 예상대로 새 줄을 인쇄합니다.

문제가 내 sys_write 호출의 길이 매개 변수와 관련이 있습니까? 저는 dword의 크기 인 2를주고 있습니다. EAX 레지스터와 to_print 레이블의 크기는 resd 1으로 예약되어 있습니다. 나는 절망에서 1, 4, 8, 16, 32로 길이를 바꿨다. 아무 것도 효과가 없었다.

편집 : (내가 변화 라인에 별표를 둘 것이다) : 궁금해 사람들을위한, 여기에 내가 코드를 고정하는 방법이다 기본적으로

segment .bss 
    to_print: resd 1 

segment .text 
     global print_eax_val 

print_eax_val:      ;  (top) 
     push dword ebx   ;Stack: edx 
     push dword ecx   ;  ecx 
     push dword edx   ;  ebx 
            ;  (bot) 

     mov  ecx,eax    ;ecx = eax 

     mov  [to_print],ecx  ;to_print = ecx 

**** add  dword [to_print], 48 

     mov  eax, 4    ;sys_write 
     mov  ebx, 1    ;to stdout 
**** mov  ecx, to_print 
     mov  edx, 2 
     int  0x80 

**** sub  dword [to_print], 48 
     mov  eax, [to_print]  ;eax = original val 
     pop  edx     ;pop the registers back from the stack 
     pop  ecx 
     pop  ebx     ;Stack: empty 

     ret 

ecx주소를 포함해야합니다 인쇄하고자하는 블록의 값 자체가 아닌. 선택한 답변에서 지적한대로만 0-9 범위에있는 경우 작동합니다.

EDIT 2 : sys_write (edx에 저장된 것)의 두 번째 매개 변수에 대해 약간 혼란 스러웠습니다. 나는 그것이 단지 많은 바이트를 참조한다고 생각한다. 따라서 dword의 경우, 사용하고있는 것처럼 4를 사용하는 것이 적절합니다. 이중 단어는 4 바이트 또는 32 비트이기 때문입니다. 나는 x86이 리틀 엔디안이기 때문에 그것이 작동했다고 생각합니다.

90 00 00 00

을 그리고 둘의 공급 길이, sys_write와는 가져옵니다 : 그래서 메모리에, to_print의 16 진수 값이 같을 것이다

90 00

그래서 값이 운이 좋게하지 않습니다 타락하다. 나는 위의 to_print에게 값을 제공하지 않을거야 알고 있기 때문에

는 나중에, 바이트 여기 괜찮 ... resb 1을 사용하고 dword 대신 byte를 사용하여 액세스하는 대신 바이트로 to_print를 저장하는 코드를 변경 9.

답변

4

저는 어셈블러에서 녹슨 것이지만 작성해야 할 버퍼의 주소를 포함해야 할 때 ECX에 값 48이 들어있는 것처럼 보입니다.

print_eax_val은 EAX의 이진 값을 취하고 0 (47이 아닌 48) 숫자에 ASCII 오프셋을 추가 한 다음 그 단일 문자를 인쇄하는 것으로 가정합니다.이렇게하려면 to_print에 값을 저장하기 전에 48을 더하고의 주소를 ECX에 넣고 한 문자 만 쓰려면 길이 (EDX)를 1로 설정하십시오.

이제 0x0000과 0x0009 사이의 EAX 값에만 적용됩니다. 9 이상이되면 다른 ASCII 문자가 나옵니다.

EAX의 임의의 이진 값을 취하고이를 인쇄 할 수있는 십진수 문자열로 변환하는 방법을 설명하는 것은 그 범위를 훨씬 벗어납니다.

+0

대단히 감사합니다. 당신의 대답은 매우 도움이되었습니다. 예, 이것이 0에서 9까지만 작동한다는 것을 알았습니다. 기본 사항 중 일부를 보려고합니다. 어쩌면 배열/포인터 int-to-string 비즈니스로 시작하겠습니다. 내가 알고 싶은 사람을 위해 업데이트 된 코드로 내 게시물을 수정합니다. –

+3

어셈블리 언어에 대해 박수를 보냅니다. BTW, 귀하의 질문은 프로토 타입 좋은 질문입니다. 당신은 필요한 정보를 정확히주고, 당신이 시도한 것을 보여 주었고, 특정한 질문을했습니다. +1 –

+1

다시 한 번 감사드립니다. 나는 답을 "프로토 타입 좋은 결과"로 분류 할 것입니다. 거대한 C++ segfault/포인터 붕괴 이후에 내가 작업중인 프로젝트에서 일부 x86 어셈블리를 배우기로 결정했습니다. 우선, 좋은 전환기입니다. 둘째, 실제로 코드를 작성할 때 어떤 일을하는지 알고 싶습니다. –

3

시스템 호출은 인쇄 할 문자 버퍼를 취해 %ecx으로 지정하고 길이는 %edx입니다. 반면에 %eax 같은 레지스터는 32 비트 정수를 포함합니다.

실제로 %eax을 인쇄하려면 먼저 해당 정수를 문자 시퀀스로 변환해야합니다. ASCII 10 진수 또는 16 진수 또는 원하는 다른 기본 코드로 변환 할 수 있지만 문자로 변환해야합니다.

+0

도움 주셔서 감사합니다. 귀하의 답변은 전적으로 도움이되었습니다 (인터넷은 어셈블리 언어 q & a에서 실제로 놀랍도록 희소하게 보입니다. 또는 어쩌면 단지 어디에서보아야할지 모르겠습니다). 먼저 다른 답변을 얻었지만 두 가지 정답을 선택할 수 있다면 그렇게 할 수 있습니다. –

+0

아주 작은 nit :'dword'의 크기는 2가 아니라 4입니다 ... –

+0

Hah, 조립 과정에서 "사소한"실수는 없습니다 (지금까지 내가 배웠던 것에서). 나는 그 길이 매개 변수에 넣어야 할 것이 무엇인지 혼란스러워했습니다. 자세한 내용은 내 게시물의 2 수정을 참조하십시오. 하지만 고마워! –