2011-08-24 32 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的行。

相关问题