Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/linux/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 如何将64位函数转换为32位到16位到8位?_Assembly_X86 64 - Fatal编程技术网

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

Assembly 如何将64位函数转换为32位到16位到8位?,assembly,x86-64,Assembly,X86 64,我是汇编新手,我不知道如何将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

我是汇编新手,我不知道如何将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中一样,sizeofint*和sizeofchar*在普通系统上是相同的

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

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


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

但除此之外,基本规则是尽可能使用32位操作数大小;这是x86-64的自然尺寸。e、 g.始终为零RDX/EDX/DX和xor EDX,EDX

写入32位寄存器零扩展到64位,而8/16只是合并到旧值中。 使用16位mov reg、imm16并留下高垃圾大概就是系统调用无法工作的原因。

值得注意的是,lea-dx、[rsp]/sub-dx,si可能会在RDX的高位(写入系统调用的arg)留下垃圾

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

因此,在所有版本中,mov edx、esp/sub edx、esi都是您应该做的。由于完全RSP和RSI在附近,它们的差异很小。在减法之前截断输入,而不是在减法之后截断结果,不会改变结果;进位从低位传播到高位。看


使用LEA复制注册表是没有效率的;lea dx,[rsp]在架构上与mov dx,sp相同,但速度较慢

狭义版本可以将其输入零扩展到32位并跳转到该版本。但除此之外,基本规则是尽可能使用32位操作数大小;这是x86-64的自然大小,写入32位寄存器0会扩展到64位,与8/16不同感谢您在我添加xor时给出的答案代码有效: