如何将64位功能转换为32位,16位转换为8位?

问题描述 投票:-1回答:1

我是汇编的新手,我不知道如何将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位的基本规则是什么。

assembly x86-64
1个回答
0
投票

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

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

此外,系统调用号和fd的大小仍然相同; mov ax,1mov di,1在寄存器的高字节中留下垃圾。使用strace ./my_program解码您实际传递给syscall的内容。


窄版本可以将其输入零扩展到32位,然后跳转到32位版本。

但是除此之外,基本规则是尽可能使用32位操作数大小;这是x86-64(The advantages of using 32bit registers/instructions in x86-64)的自然大小。例如xor edx,edx总是RDX / EDX / DX为零。

写一个32位寄存器零扩展到64位,不像8/16只是合并成旧值。Why do x86-64 instructions on 32-bit registers zero the upper part of the full 64-bit register?使用16位mov reg,imm16并留下大量垃圾是大概您的系统调用无法起作用的原因。Why doesn't GCC use partial registers?

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

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

所以mov edx, esp / sub edx, esi是所有版本中都应该执行的操作。由于完整的RSP和RSI都在附近,因此它们的差异很小。在减法之前截断输入而不是在截断之后截断结果不会改变结果;进位从低位传播到高位。参见Which 2's complement integer operations can be used without zeroing high bits in the inputs, if only the low part of the result is wanted?

使用LEA复制寄存器效率不高; lea dx, [rsp]在结构上与mov dx, sp相同,但速度较慢。

© www.soinside.com 2019 - 2024. All rights reserved.