2011-08-24 79 views
2

我可以使用系統調用寫入打印內存中的一些數據到STDOUT:如何將RAX中的值寫入彙編中的STDOUT?

ssize_t write(int fd, const void *buf, size_t count); 

即:

movq $1, %rax 
movq $1, %rdi 
move address_of_variable %rsi 
movq $5, %rdx 
syscall 

但我怎麼能打印寄存器的值?

UPDATE

.text 
     call start 
    start: 
     movq $100, %rdi 
     movq $10, %rsi 
     call print_number 
     ret 

    buffer: 
     .skip 64 
    bufferend: 
    # rdi = number 
    # rsi = base 
    print_number: 
     leaq bufferend, %rcx 
     movq %rdi, %rax 
    1: 
     xorq %rdx, %rdx 
     divq %rsi 

     add $'0', %dl 
     cmp $'9', %dl 
     jbe 2f 
     add $'A'-'0'-10, %dl 

    2: 
     sub $1, %rcx 
     mov %dl, (%rcx) 

     and %rax, %rax 
     jnz 1b 

     mov %rcx, %rsi 
     lea bufferend, %rdx 
     sub %rcx, %rdx 

     movq $1, %rax 
     movq $1, %rdi 
     syscall 
     ret 
+0

http://stackoverflow.com/questions/7087020/outputting-registers-to-the-console-with-masm/7088064#7088064 –

回答

3

您必須先將其轉換爲文本。你可以走容易的路線,並使用例如來自libc的printf或者,如果您非常喜歡,請編寫您自己的轉換實用程序。

更新:如果您希望代碼獨立於位置,則可以更容易地使用堆棧。簡單地將緩衝區移動到代碼段中,因爲在註釋中鏈接的代碼不再有效,因爲現代處理器將代碼段設置爲只讀。我更新了代碼以使用該堆棧進行臨時存儲。

.text 

    call start 
start: 
    movq $186, %rax # sys_gettid 
    syscall 

    movq %rax, %rdi 
    movq $10, %rsi 
    call print_number 

    #ret 
    mov $60, %rax # sys_exit 
    mov $0, %rdi 
    syscall 

# rdi = number 
# rsi = base 
print_number: 
    sub $72, %rsp # alloc room for buffer on the stack, 8 more than needed 

    lea 64(%rsp), %rcx # 64(%rsp) == buffer end 
    movq %rdi, %rax # rax holds current number 
1: 
    xorq %rdx, %rdx # clear rdx (div uses the 128-bit number in rdx:rax) 
    divq %rsi # divide by base, updating rax for the next iteration 
       # and giving us our digit in rdx (dl) 
    add $'0', %dl # turn into printable character 
    cmp $'9', %dl # handle digits > 10 
    jbe 2f 
    add $'A'-'0'-10, %dl # adjust number so A=10, B=11 ... 

2: 
    sub $1, %rcx # subtract before adding character as we start from the end 
    mov %dl, (%rcx) # store character in string 

    and %rax, %rax # rax == 0? 
    jnz 1b # if not, then keep working 

    mov %rcx, %rsi # buf = address of last character stored 
    lea 64(%rsp), %rdx # calculate length by subtracting buffer end 
    sub %rcx, %rdx # from the buffer start 

    movq $1, %rax # sys_write 
    movq $1, %rdi # fd = STDOUT_FILENO 
    syscall 

    add $72, %rsp # adjust stack back 
    ret 

如果反過來說,您希望將緩衝區實際存儲在代碼段中,則可以完成。您必須將buffer所在的頁面標記爲可使用例如可寫入的頁面。 mprotect(2)。沒有裝配錯誤檢查(並假設sysconf(_SC_PAGE_SIZE) == 4096)在這裏完成:

 mov $10, %rax # sys_mprotect 
    lea buffer, %rdi # addr 
    and $-4096, %rdi # page align 
    mov $4096, %rsi # len 
    mov $7, %rdx #prot = PROT_READ|PROT_WRITE|PROT_EXEC 
    syscall 

現在當緩衝區位於代碼段,代碼應該甚至不工作。順便說一句,我在我的例子中使用sys_exit,因爲我測試它作爲一個獨立的文件與gcc x.s -nostdlib -ggdb -o x

Update2:要在代碼重定位時使用它,請使用RIP相對尋址。將​​更改爲bufferend(%rip)

+0

'.skip 64'是什麼意思? –

+0

它爲緩衝區保留了64個字節。它也可以用在'.bss'節中,緩衝區可能應該放在那裏。如果您願意,您也可以在堆棧上分配緩衝區。 – user786653

+0

這取決於字節順序嗎? –

0

,你可以不寫純數字(因爲它們將被解釋爲指針),你需要這個數字的指針轉換爲字符串,並傳遞給字符串作爲ARG write。一些沿着this的行。