我怎样写在RAX到STDOUT组装的价值? [英] How do I write the value in RAX to STDOUT in assembly?

查看:151
本文介绍了我怎样写在RAX到STDOUT组装的价值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我可以使用系统调用写入到内存中的一些数据打印到STDOUT:

  ssize_t供写入(INT FD,常量无效* buf中,为size_t计数);

这就是:

  MOVQ $ 1%RAX
MOVQ $ 1,%RDI
移动address_of_variable%RSI
MOVQ $ 5%的RDX
系统调用

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

更新

 的.text
        呼叫开始
    开始:
        MOVQ $ 100%RDI
        MOVQ $ 10%RSI
        调用print_number
        RET    缓冲:
        .skip 64
    bufferend:
    #RDI =号
    #RSI =基地
    print_number:
        leaq bufferend,RCX%
        MOVQ%RDI,RAX%
    1:
        xorq%的RDX,RDX%
        divq%RSI        加$'0',DL%
        CMP $'9',DL%
        JBE 2F
        加$'A' - '0'10%DL    2:
        分$ 1,%RCX
        MOV%DL,(RCX%)        和%RAX,RAX%
        JNZ 1B        MOV%RCX,RSI%
        LEA bu​​fferend,RDX%
        子%RCX,RDX%        MOVQ $ 1,RAX%
        MOVQ $ 1,%RDI
        系统调用
        RET


解决方案

您必须将其转换先文本。你可以去简单的方法,并使用例如的printf 从libc中,或者,如果你愿意,编写自己的转换工具。

更新:如果你想在code以独立定位它更容易使用堆栈。只需移动缓存到code段为code你在评论挂钩,因为现代处理器有code段为只读不工作了。我已经更新了code使用堆栈临时存储。

 的.text    呼叫开始
开始:
    MOVQ $ 186%RAX#sys_gettid
    系统调用    MOVQ%RAX,%RDI
    MOVQ $ 10%RSI
    调用print_number    #RET
    MOV $ 60%RAX#sys_exit
    MOV $ 0%RDI
    系统调用#RDI =号
#RSI =基地
print_number:
    子$ 72超过需要的缓冲区%RSP#页头房在堆栈中,8    LEA 64(%RSP),%#RCX 64(%RSP)==缓冲结束
    MOVQ%RDI,RAX%RAX#目前持有数量
1:
    xorq%的RDX,RDX%#清除RDX(DIV用于RDX的128位数字:RAX)
    通过基地divq%RSI#鸿沟,为下一次迭代更新RAX
              #和给我们的RDX我们的数字(DL)
    加$'0',DL%#转成可打印字符
    CMP $'9',DL%#拉手数字> 10
    JBE 2F
    加$'A' - '0'10%DL#调整号码,这样A = 10,B = 11 ...2:
    分$ 1,%#RCX加入减字符前我们从月底开始
    MOV%DL,(RCX%)的字符串#存储字符    和%RAX,RAX%RAX#== 0?
    JNZ 1B#如果没有,则继续工作    MOV%RCX,RSI%BUF#=存储最后一个字符地址
    LEA 64(%RSP)%的RDX#减去缓冲结束长度计算
    子%RCX,从缓冲区起始%的RDX#    MOVQ $ 1,RAX%SYS_WRITE#
    MOVQ $ 1,%RDI#FD = STDOUT_FILENO
    系统调用    加$ 72%RSP#调整堆栈回
    RET

如果偏偏要实际存储在code段是可以做到的缓冲区。你必须标记,其中缓存使用例如驻留可写的页面则mprotect(2)。没有错误检查在这里完成(假定的sysconf(_SC_PAGE_SIZE)== 4096 )的集会:

  MOV $ 10%RAX#sys_mprotect
     LEA缓冲,%RDI#地址
     和$ -4096,%RDI#页对齐
     MOV $ 4096%RSI#LEN
     MOV $ 7,%的RDX #prot = PROT_READ | PROT_WRITE | PROT_EXEC
     系统调用

而现在的code应该工作,即使当缓冲区位于code段。 BTW我用sys_exit在我的例子,因为我与 GCC x.s -nostdlib -ggdb -o X 测试它作为一个单独的文件。

UPDATE2:要使用它时,code搬迁使用RIP相对寻址。更改 bufferend bufferend(%RIP)

I can use syscall for write to print some data in memory to STDOUT:

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

That is:

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

But how can I print register values?

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

解决方案

You have to convert it to text first. You can go the easy route and use e.g. printf from libc or, if you're so inclined, write your own conversion utility.

Update: If you want the code to be position independent it's easier to use the stack. Simply moving the buffer into the code segment as the code you linked to in the comments doesn't work anymore since modern processors have code segments as read only. I have updated the code to use the stack for temporary storage.

    .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

If, perversely, you want to actually store the buffer in the code segment it can be done. You have to mark the page where buffer resides as writable using e.g. mprotect(2). Here done without error checking (and assuming sysconf(_SC_PAGE_SIZE) == 4096) in assembly:

     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

And now the code should work even when the buffer is located in the code segment. BTW I use sys_exit in my example because I'm testing it as a stand alone file with gcc x.s -nostdlib -ggdb -o x.

Update2: To use it when the code is relocated use RIP-relative addressing. Change bufferend to bufferend(%rip).

这篇关于我怎样写在RAX到STDOUT组装的价值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆