【问题标题】:nasm segmentation fault while using arg使用 arg 时出现 nasm 分段错误
【发布时间】:2016-11-16 10:14:22
【问题描述】:
extern puts
global main

section .text
main:
    mov rax, rdi
label:
    test rax, rax
    je exit
    push rsi
    mov rdi, [rsi]
    call puts
    pop rsi
    dec rax
    add rsi, 8
    jmp label
exit:
    pop rsi
    ret

我写了这样的 nasm 代码。然而,分段错误发生在最后。我不明白为什么会发生分段错误。

【问题讨论】:

    标签: linux gcc assembly nasm x86-64


    【解决方案1】:

    rax 不能保证在函数调用中保留,因为它用于从函数返回整数结果(在puts 的情况下“成功时为非负数,错误时为 EOF”) 你需要在调用puts 之前保存rax 的值,就像你对rsi 所做的那样,然后再恢复它。

    【讨论】:

      【解决方案2】:

      显然,您希望在 64 位 Linux 上的 GCC 环境中获取命令行参数,它们是根据遵循 Linux 调用约定“System V AMD64 ABI”的 GCC 调用约定传递的。

      让我们把程序逻辑翻译成C:

      #include <stdio.h>
      
      int main ( int argc, char** argv )
      {
          if (argc != 0)
          {
              do
              {
                  puts (*argv);
                  argc--;
                  argv++;
              } while (argc);
          }
          return;
      }
      

      asm 程序不返回退出代码。当函数返回时,该退出代码应该在RAX 中。顺便说一句:argc 始终 >0,因为argv 的第一个字符串包含程序名称。

      main 函数既是“调用者”(调用 puts)又是“被调用者”(返回 GCC 环境)。作为调用者,它必须在调用puts 之前保留RAXRSI,并在需要时恢复它们。不使用被调用者保存的寄存器。不要忘记将堆栈对齐 16。

      这行得通:

      extern puts
      global main
      
      section .text
      main:                       ; RDI: argc, RSI: argv, stack is unaligned by 8
          mov rax, rdi
      label:
          test rax, rax
          je exit
          push rbx                ; Push 8 bytes to align the stack before the call
          push rax                ; Save it (caller-saved)
          push rsi                ; Save it (caller-saved)
          mov rdi, [rsi]          ; Argument for puts
          call puts
          pop rsi                 ; Restore it
          pop rax                 ; Restore it
          pop rbx                 ; "Unalign" the stack
          dec rax
          add rsi, 8
          jmp label
      exit:
      ;    pop rsi                ; Once too much
          xor eax, eax            ; RAX = 0 (return 0)
          ret                     ; RAX: return value
      

      【讨论】:

        猜你喜欢
        • 2013-04-16
        • 2021-10-16
        • 1970-01-01
        • 1970-01-01
        • 2016-09-10
        • 2014-01-31
        • 2017-06-06
        • 2017-08-26
        相关资源
        最近更新 更多