2013-07-02 25 views
6

Vì vậy, tôi đang học x86 Linux với cú pháp NASM (Ôi trời, không phải lần này, bạn đều đang suy nghĩ). Tôi đang cố gắng để làm cho một chương trình con sẽ chỉ đơn giản là in giá trị trong EAX để stdout. Mã chạy và thoát mà không có lỗi, nhưng không có gì in. Tôi không thể hiểu tại sao. Trước hết, đây là file tôi đang làm việc tại:Linux x86 NASM - Chương trình con: In từ dword từ EAX

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 

này được gọi là từ tập tin chính của tôi, trông như thế này (điều này có lẽ không thích hợp, trừ khi tôi đang thiếu một cái gì đó mạnh mẽ).

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 chỉ là một chương trình con khác định nghĩa và in dòng mới. Điều này chạy thành công và in một dòng mới như mong đợi.

Sự cố có liên quan đến thông số độ dài cho lệnh gọi sys_write của tôi không? Tôi tặng nó 2, có kích thước là dword, đó là kích thước của cả thanh ghi EAX và nhãn to_print của tôi, mà tôi đã đặt trước với resd 1. Tôi đã cố gắng thay đổi độ dài thành 1, 4, 8, 16 và 32 trong tuyệt vọng ... Không có gì hiệu quả.

EDIT: Đối với những ai đang tự hỏi, đây là cách tôi cố định mã: (Tôi sẽ đặt dấu hoa thị trên các tuyến đường mà tôi đã thay đổi):

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 

Về cơ bản, ecx phải chứa địa chỉ của khối bạn muốn in, KHÔNG phải giá trị của chính nó. Như được chỉ ra trong câu trả lời đã chọn, điều này sẽ chỉ chỉ hoạt động nếu eax nằm trong khoảng 0-9.

CHỈNH SỬA 2: Vì vậy, tôi hơi bối rối về tham số thứ 2 cho sys_write (số được lưu trữ trong edx). Tôi nghĩ nó chỉ đề cập đến một số byte. Vì vậy, đối với một dword, như tôi đã sử dụng, nó sẽ là thích hợp để sử dụng 4 ở đó, bởi vì một từ kép là 4 byte, hoặc 32 bit. Tôi đoán nó làm việc vì x86 là một người rất ít tuổi. Vì vậy, trong bộ nhớ, giá trị hex của to_print sẽ trông như thế này:

90 00 00 00

Và với chiều dài cung cấp hai, sys_write được:

90 00

Vì vậy, giá trị may mắn không bị hỏng.

sau, tôi đã thay đổi mã để lưu trữ to_print như một byte thay vào đó, sử dụng resb 1 và truy cập nó bằng cách sử byte thay vì dword ... Một byte là tốt ở đây, bởi vì tôi biết tôi sẽ không để cho to_print một giá trị trên 9.

Trả lời

4

Tôi rất chắc chắn với bộ lắp ráp, nhưng có vẻ như ECX chứa giá trị 48, khi nó phải chứa địa chỉ của bộ đệm được ghi.

Tôi đoán những gì bạn dự định trong print_eax_val là lấy giá trị nhị phân của EAX, thêm bù trừ ASCII vào số 0 (phải là 48, không 47) và sau đó in ký tự đơn.Để thực hiện việc này, hãy thêm 48 trước khi lưu trữ giá trị trong to_print, đặt địa chỉ to_print vào ECX và đặt độ dài (EDX) thành 1, vì bạn chỉ viết một ký tự.

Hãy nhớ rằng thao tác này sẽ chỉ hoạt động đối với các giá trị EAX trong khoảng từ 0x0000 đến 0x0009. Khi bạn đi qua 9 bạn sẽ nhận được các ký tự ASCII khác.

Giải thích cách lấy giá trị nhị phân tùy ý của EAX và chuyển đổi nó thành chuỗi thập phân có thể được in vượt quá phạm vi của SO.

+0

Cảm ơn rất nhiều! Câu trả lời của bạn rất hữu ích. Vâng, tôi nhận ra điều này sẽ chỉ làm việc cho 0 đến 9, tôi chỉ cố gắng để có được một số vấn đề cơ bản. Có lẽ tôi sẽ bắt đầu với một số mảng/con trỏ int-to-string kinh doanh cuối cùng. Tôi sẽ chỉnh sửa bài đăng của mình bằng mã được cập nhật, cho bất kỳ ai khác muốn biết. –

+3

Tôi hoan nghênh bạn vì đã giải quyết ngôn ngữ lắp ráp và chúc bạn may mắn. BTW, câu hỏi của bạn là một câu hỏi SO nguyên mẫu tốt. Bạn đã cung cấp chính xác thông tin cần thiết, cho thấy những gì bạn đã thử và hỏi một câu hỏi cụ thể. +1 –

+1

Cảm ơn một lần nữa, và tôi chắc chắn sẽ phân loại câu trả lời của bạn thành câu trả lời "nguyên mẫu tốt". Tôi quyết định tìm hiểu một số x86 lắp ráp sau khi một lớn C + + segfault/con trỏ meltdown trong một dự án tôi đang làm việc trên. Trước hết, đó là một sự chuyển hướng tốt đẹp, thứ hai, tôi muốn biết tôi thực sự * đang làm gì khi viết mã. –

3

Cuộc gọi hệ thống write có bộ đệm các ký tự cần in, được trỏ bởi %ecx với độ dài được cho bởi %edx. Mặt khác, thanh ghi như %eax có chứa số nguyên 32 bit.

Vì vậy, nếu bạn thực sự muốn in %eax, trước tiên bạn cần chuyển đổi số nguyên đó thành chuỗi ký tự. Bạn có thể chuyển nó thành số thập phân ASCII, hoặc hệ thập lục phân hoặc bất kỳ cơ sở nào khác mà bạn thích, nhưng bạn cần phải biến nó thành ký tự.

+0

Cảm ơn sự giúp đỡ của bạn! Câu trả lời của bạn là hoàn toàn hữu ích (internet thực sự là đáng ngạc nhiên thưa thớt về ngôn ngữ lắp ráp q & a, hoặc có lẽ tôi chỉ không biết nơi để tìm). Tôi đã nhận được câu trả lời khác trước, nhưng nếu tôi có thể chọn hai câu trả lời đúng, tôi sẽ. –

+0

Rất nhỏ nit: kích thước của một 'dword' là 4, không 2 ... –

+0

Hah, không có sai lầm là" nhỏ "trong lắp ráp (từ những gì tôi đã học được cho đến nay). Tôi đã nhầm lẫn về những gì tôi được cho là để đưa vào tham số chiều dài đó. Xem Chỉnh sửa 2 trong bài đăng của tôi để được giải thích thêm. Nhưng cảm ơn! –

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