gpt4 book ai didi

assembly - 如何在汇编中将 RAX 中的值写入 STDOUT?

转载 作者:行者123 更新时间:2023-12-02 00:30:21 26 4
gpt4 key购买 nike

我可以使用 syscall for write 将内存中的一些数据打印到 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

但是我怎样才能打印寄存器值呢?

更新

.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

最佳答案

您必须先将其转换为文本。您可以走简单的路线并使用例如printf 来自 libc,或者,如果您愿意,可以编写自己的转换实用程序。

更新:如果您希望代码与位置无关,那么使用堆栈会更容易。简单地将缓冲区移动到代码段中,因为您在注释中链接到的代码不再起作用,因为现代处理器将代码段设为只读。我已更新代码以使用堆栈进行临时存储。

    .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 将其作为独立文件进行测试。

更新 2:要在重定位代码时使用它,请使用 RIP 相对寻址。将 bufferend 更改为 bufferend(%rip)

关于assembly - 如何在汇编中将 RAX 中的值写入 STDOUT?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7176506/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com