【问题标题】:Converting C to NASM assembly with segmentation issue将 C 转换为具有分段问题的 NASM 程序集
【发布时间】:2015-07-09 10:21:30
【问题描述】:

我正在尝试获取此 c 代码:

main()

 {int x, y, count ;

  count = 0 ;
  x = 10 ; 
  y = 2 ;
  while (y < x)
    { x = x + 1 ;
      y = y + 2 ;
      count = count + 1 ;
     } 

    printf(“ It took %d iterations to complete loop. That seems like a     lot\n”,count) ;
}

到我目前拥有的 NASM 等价物:

segment .data

out1    db "It took ", 0
out2    db "%i ", 0
out3    db "iterations to complete the loop. That seems like a lot.", 10, 0

segment .bss

segment .text

global     main
extern printf

main:

    mov    eax, 0        ;count
    mov    ebx, 10        ;x
    mov    ecx, 2        ;y

    jmp     lp

    mov    eax, 0
    ret

lp:
    cmp    ecx, ebx    ;compare y to x
    jge    end        ;jump to end if y >= x
    add    eax, 1
    add    ebx, 1
    add    ecx, 2
    jmp    lp

end:

    push    out1
    call    printf

   push    eax
   push    out2
   call    printf

   push    out3
   call    printf

我不断收到分段错误,但我不明白为什么它会一直发生。我尝试在任何地方添加打印语句,但找不到故障所在。任何建议都会很棒!谢谢!

【问题讨论】:

  • 我觉得你的 asm 没问题。
  • printfs 之后有ret 指令吗?
  • 是的,我厌倦了它没有解决分段问题:(

标签: c nasm fault


【解决方案1】:

我认为您没有遵循 printf 的调用约定(它是 cdecl IIRC)。

  1. 调用者必须在调用后清理堆栈
  2. 并且 eax 被第一次调用 printf 及其返回值所破坏

main返回时,第一个会引起麻烦。实际上,在printfs 之后没有ret 指令导致执行继续,直到出现问题:)

打印后添加以下内容:

   add     esp, 16  ; Fix stack, usually it's done after each call
                    ; with the appropiate values.
                    ; In this way (one fixup for many calls) stack
                    ; grows unnecessarily
   xor     eax, eax ; set return value to 0
   ret              ; Return from main

虽然,这并不能解决第二个问题。

【讨论】:

  • 谢谢,确实帮了不少忙,我看看它是否有效。
  • Diego,由于这是一个独立的汇编程序,所以没有main,也无需返回。需要的是进行系统调用以退出以在程序终止时进行清理。退出代码设置在ebx,退出的x86系统调用是1(见:/usr/include/asm/unistd_32.h)并进入eax,然后调用内核执行命令@ 987654334@ 或 int 80h.
  • @DavidC.Rankin:进行退出系统调用而不是返回显然很好,但是这个程序显然确实有一个main 函数。大多数链接到标准 C 库的汇编程序都有一个。
  • 你们能不能也快点帮我看看这段代码?它还有一个我无法弄清楚的细分问题。这是一个类似的练习,我们采用一个 c 程序并从中创建一个 nasm 程序。 stackoverflow.com/questions/29956567/…
【解决方案2】:

更新完整示例:

segment .data
out1    db      "It took %d iterations to complete loop. That seems like "
        db      "a lot.", 0aH, 00H
segment .bss
segment .text
        global  main
        extern  printf
main:   xor     eax, eax
        mov     ebx, 10
        mov     ecx, 2
loop0:  inc     ebx
        add     ecx, 2
        inc     eax
        cmp     ecx, ebx
        jl      loop0
        push    eax
        push    offset out1
        call    printf
        add     esp, 8
        xor     eax, eax
        ret
        end

【讨论】:

  • 我仍然因为更改而遇到分段错误
【解决方案3】:

如果您还没有解决问题,则问题是由于 eax 在您的 printf 通话中受到打击。怎么修?在第一次调用printf 之前将其保存到缓冲区,并在第二次调用之前加载eax。例如。添加:

segment .bss

buffer resd  1          ; reserve 32 bit buffer
...
mov     [buffer], eax   ; save eax in the buffer

push    out1
call    printf

mov     eax, [buffer]   ; load eax from the buffer

push    eax
push    out2
call    printf

push    out3
call    printf

xor     ebx, ebx         ; exit nicely 
mov     eax, 1
int     0x80

使用/输出

$ ./bin/pt
It took 8 iterations to complete the loop. That seems like a lot.

【讨论】:

  • 当你有一个非常好的堆栈等待使用时,我不确定我是否会浪费时间和精力为它编写一个缓冲区 :-) 换句话说,@987654327 @, pop eax.
猜你喜欢
  • 2013-07-14
  • 2020-07-26
  • 2022-01-19
相关资源
最近更新 更多