如何将64位函数转换为32位到16位到8位



我是组装新手,不知道如何将64位函数转换为32位到16位到8位

以下功能的目的是打印数字并返回其中的位数。

64位:

global print_uint64
section .text
print_uint64:
mov rax,rdi
mov rdi,10
mov rsi,rsp
while:
xor  rdx  ,rdx
div  rdi
add  rdx  ,48
dec  rsi
mov  [rsi],dl
cmp  rax  ,0
jne  while 
mov rax,1
mov rdi,1
lea rdx,[rsp]
sub rdx,rsi
syscall
lea rax,[rsp]
sub rax,rsi
ret
this works fine 

32位:

global print_uint32
section .text
print_uint32:
mov eax,edi
mov edi,10
mov rsi,rsp
while:
xor  edx  ,edx
div  edi
add  edx  ,48
dec  rsi
mov  [rsi],dl
cmp  eax  ,0
jne  while 
mov eax,1
mov edi,1
lea edx,[rsp]
sub edx,esi
syscall
lea eax,[rsp]
sub eax,esi
ret

这很好

16位:

global print_uint16
section .text
print_uint16:
mov ax,di
mov di,10
mov rsi,rsp
while:
xor  dx  ,dx
div  di
add  dx  ,48
dec  rsi
mov  [rsi],dl
cmp  ax  ,0
jne  while 
mov ax,1
mov di,1
lea dx,[rsp]
sub dx,si
syscall
lea ax,[rsp]
sub ax,si
ret

但不起作用

关于这个问题,我研究了一些关于堆栈溢出的问题,我所理解的是,我不能将rsp更改为esp,因为esp将高32位设置为零,所以当我们在该访问上使用[]时,未分配给该程序的内存会引发段错误。

我的问题是:

1( 将64位转换为32位、将16位转换为8位的基本规则是什么。

基本规则是,无论数据宽度如何,指针都是64位的。就像在C中一样,sizeof(int*)sizeof(char*)是相同的(在正常系统上(。

这就是为什么您的所有版本都必须使用dec rsimov [rsi],dl:RSP持有一个64位指针。将其截断为32位将不会产生有效的指针。

此外,系统调用编号和fd的大小仍然相同;CCD_ 6和CCD_。使用strace ./my_program对实际传递给syscall的内容进行解码。


窄版本可以将其输入扩展到32位并跳转到32位版本。

但除此之外,基本规则是尽可能使用32位操作数大小;这是x86-64的自然大小(在x86-64中使用32位寄存器/指令的优点(。例如在CCD_ 10的情况下总是使RDX/EDX/DX为零。

写入32位寄存器0扩展到64位,而8/16只是合并到旧值中
为什么32位寄存器上的x86-64指令会将整个64位寄存器的上部清零?使用16位mov reg,imm16并留下大量垃圾可能是系统调用不起作用的原因
为什么GCC不使用部分寄存器?

值得注意的是,lea dx,[rsp]/sub dx,si可能会在RDX的高位留下垃圾,RDX是write系统调用的arg。

这是一个指针减法,用于计算char缓冲区中的元素数量。根据输入数字的大小为其选择操作数大小是没有意义的。实际上,只要你确保结果是零扩展到RDX,做窄减法是可以的,因为在这种情况下,你知道数字的数量最多是19(对于64位版本(,因为这就是2^64-1在基数10中的长度。

所以mov edx, esp/sub edx, esi是您在所有版本中应该做的。由于完整的RSP和RSI就在附近,它们的差异很小。在减法之前截断输入而不是在减法之后截断结果不会改变结果;进位从低位传播到高位。查看哪2';如果只需要结果的低部分,则可以在不将输入中的高位归零的情况下使用s补码整数运算?

使用LEA复制寄存器效率不高;CCD_ 18在架构上与CCD_。

最新更新