【发布时间】:2020-07-26 18:42:01
【问题描述】:
我是汇编新手,我想编写一个函数来打印汇编中的数字并从 c++ 调用它,请参见下面的代码
cpp:
#include <iostream>
#include <stdint.h>
extern "C" void printunum(uint64_t);
int main()
{
printunum(12345);
std::cout<<std::endl;
return 0;
}
组装:
global printunum
section .text
printunum:
mov rax,rdi
mov rdi,10
mov rsi,0
while1:
cmp rax,0
je endwhile1
mov rdx,0
div rdi
inc rsi
add rdx,48
push rdx
jmp while1
endwhile1:
mov r10,rsi
while2:
cmp r10,0
je endwhile2
mov rax,1
mov rdi,1
mov rsi,rsp ;to pass memory address
add rsp,8 ;it is equal to pop or it is wrong and it will add 8 bytes here?
mov rdx,1
syscall
dec r10
jmp while2
endwhile2:
ret
编辑的程序集:
global print_uint64
section .text
print_uint64:
;init
mov rax,rdi
mov rdi,10
mov rsi,rsp
;endinit
while:
xor rdx ,rdx
div rdi
add rdx ,48
dec rsi
mov [rsi],dl
cmp rax ,0
je else
if:
jmp while
else:
endwhile:
;print
mov rax,1
mov rdi,1
mov rdx,rsp
sub rdx,rsi
syscall
;endprint
;return
mov rax,rsp
sub rax,rsi
ret
我编译:
srilakshmikanthanp@HP-245-G5-NOTEBOOK-PC:~/Documents/Learn$ nasm -f elf64 asm.asm
srilakshmikanthanp@HP-245-G5-NOTEBOOK-PC:~/Documents/Learn$ g++ main.cpp asm.o -o main
srilakshmikanthanp@HP-245-G5-NOTEBOOK-PC:~/Documents/Learn$ ./main
12345
srilakshmikanthanp@HP-245-G5-NOTEBOOK-PC:~/Documents/Learn$
我的处理器 amd64(x86-x64) 我正在使用 kali linux
1)上面的代码是好的还是错的(在x64位机器中pop等于rsp+8)。
2)mul 操作将结果放入 rdx:rax 我如何将其放入单个内存中
3)div 操作从 rdx:rax 中获取红利我如何将单个值放入 rdx:rax。 感谢您的答复。
【问题讨论】:
-
这段代码效率非常低(将每个字符存储在一个单独的 qword 中,并对每个数字进行单独的系统调用),但它没有错。好吧,除了在 C 中实际声明 arg 时将其视为无符号 64 位之外,仅采用 32 位
int;通常调用者会写入一个 32 位的寄存器,因此它会隐式零扩展为 64 位。 -
不需要将值加载到寄存器中,只需将 RSI 指向它,所以是的,只需要 pop 的 rsp+=8 部分。它可以只使用
add rsi,8并在最后恢复 RSP,在循环之外,而不是使用 2 条指令。但显然这段代码根本不关心效率。它还在循环的顶部使用cmp/je,而不是像普通的asm 循环那样使用底部。这意味着如果你传递它0,它将不打印数字而不是'0'。更简单的代码见How do I print an integer in Assembly Level Programming without printf from the c library? -
@Peter Cordes 在你 cmets 之后我更改了我的代码中的一些内容,我将在编辑后的程序集中添加你能看到它以及存储在 rdx:rax 中的 mul 的结果如何将它存储到单个内存和 div 操作需要rdx:rax 来划分我如何将一个值放入 rdx:rax 你能解释一下吗?
-
你在乘以计算如何恢复RSP?不要将
mul用于 2 的幂,只需左移即可。或者更好的是,将原始 RSP 保存在另一个寄存器中,这样您就可以mov而不是计算任何东西。此外,您现在正在打印每个数字之间有 7 个字节的零的缓冲区。大多数程序都会对此感到窒息,尽管它在终端上看起来是正确的。但是通过管道将其输入less或hexdump -C以查看您实际输出的内容。首先不要使用push来存储8 个字节,只需使用mov并减少一个指针,就像我的链接答案中一样。 -
@Peter Cordes 根据您的建议和答案,我现在在编辑的程序集中进行了更改。你能看到吗