【问题标题】:Call C function from Assembly -- the application freezes at "call printf" and I have no idea why从 Assembly 调用 C 函数——应用程序在“调用 printf”处冻结,我不知道为什么
【发布时间】:2009-10-11 14:00:32
【问题描述】:

我将从事一个大型汇编项目,但现在才刚刚开始学习这种新语言。我正在尝试做一些简单的例子,就像你在高中时可能会发现的 c++ 一样(两个数字相加,是一个素数等)。

现在我必须显示直到 n 的所有素数。问题是应用程序在“调用 printf”处冻结,我不知道为什么。

你能帮我解决这个问题吗?

.section    .data
prime_number_str:
.asciz  "%d "

.section    .text

.global     _start
_start:
pushl   $20
call .first_prime_numbers
addl $4, %esp
pushl $0
call exit


.first_prime_numbers:       #argument first n numbers
movl 4(%esp), %ecx  #get the first argument
do_test:
pushl %ecx      #push function arguments
call .prime 
addl $4, %esp       #restore the stack

#if not prime jump to the next number   
cmpl $0, %eax
je no_not_prime

#print the number
pushl %eax          #save eax
pushl %ecx          #first argument
pushl $prime_number_str     #text to print
call printf
addl $4, %esp
popl %eax           #restore eax

no_not_prime:
loop do_test
ret


.prime:             #argument: number to check
movl 4(%esp), %eax  #get the first argument

#divide the argument by 2   
xorl %edx, %edx             
movl $2, %ecx           
pushl %eax      #save the value of eax
divl %ecx       
movl %eax, %ecx     #init the counter register
popl %eax       #restore the value of eax

movl $1, %ebx       #assume the argument is prime
test_prime:
# if ecx == 1 then return exit the function
cmpl $1, %ecx       
jle return_value

pushl %eax      #save the old value of eax  

#divide the value by the value of counter   
xorl %edx, %edx     
divl %ecx       

#if the reminder is 0 then the number is not prime
cmpl $0, %edx   
popl %eax       #restore the value of eax   
je not_prime


subl $1, %ecx       #decrease counter
jmp test_prime      #try next division

not_prime:
movl $0, %ebx
return_value:
movl %ebx, %eax
ret 

【问题讨论】:

    标签: assembly printf


    【解决方案1】:

    可能是因为调用printf后你的寄存器都乱了,你需要保存printf后常用的寄存器,调用后恢复。

    当您拨打syscall 或其他可能会篡改您的寄存器的电话时,您应该始终这样做。

    您还应该查看gdb(gnu 调试器)看起来您正在编写 GAS,所以如果您使用的是 gnu / linux 系统,请尝试:

    gdb youprogram
    

    然后运行它以查看失败的地方。

    【讨论】:

      【解决方案2】:

      另一个问题是您在调用 printf 后没有正确清理堆栈。您需要将 8 添加到 ESP,因为您推送了 ECX(4 字节)和地址(32 位模式下为 4 字节)。

      另外,请注意,至少在 Windows(使用 MinGW)上,printf 会踩踏 EAX(返回值)、ECX 和 EDX,并修改 EFLAGS。到目前为止,我使用的所有标准 C 函数也是如此。

      【讨论】:

        【解决方案3】:

        还请注意,在 C/C++ 中,您需要自己弹出寄存器(例如,在 Pascal 调用转换中,过程发出“ret 8”)。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2023-02-06
          • 1970-01-01
          • 2020-05-08
          • 2011-04-24
          • 1970-01-01
          相关资源
          最近更新 更多