c - 在 Assembly x86 中获取三个数字的最大值时出现段错误

标签 c assembly

我试图使用 C 来调用 Assembly 32 位 AT&T 中的方法来获取三个数字的最大值。当程序运行时,我收到段错误(核心转储)错误,并且无法弄清楚原因。我的输入是正数/负数和 1、2、3 的混合,结果都具有相同的错误。

组装

# %eax - first parameter
# %ecx - second parameter
# %edx - third parameter

.code32
.file "maxofthree.S"
.text 
.global maxofthree
.type maxofthree @function

maxofthree:
    pushl %ebp # old ebp
    movl %esp, %ebp # skip over
    movl 8(%ebp), %eax # grab first value
    movl 12(%ebp), %ecx # grab second value
    movl 16(%ebp), %edx # grab third value
    #test for first
    cmpl %ecx, %eax # compare first and second
    jl firstsmaller # first smaller than second, exit if
    cmpl %edx, %eax # compare first and third
    jl firstsmaller # first smaller than third, exit if
    leave # reset the stack pointer and pop the old base pointer
    ret # return since first > second and first > third
    firstsmaller:  # first smaller than second or third, resume comparisons
    #test for second and third against each other
    cmpl %edx, %ecx # compare second and third
    jg secondgreatest # second is greatest, so jump to end
    movl %eax, %edx # third is greatest, move third to eax
    leave # reset the stack pointer and pop the old base pointer
    ret # return third
    secondgreatest: # second > third
    movl %ecx, %eax #move second to eax
    leave # reset the stack pointer and pop the old base pointer
    ret # return second

C代码

#include <stdio.h>
#include <inttypes.h>
long int maxofthree(long int, long int, long int);

int main(int argc, char *argv[]) {
if (argc != 4) {
    printf("Missing command line arguments. Instructions to"
            " execute this  program:- .\a.out <num1> <num2> <num3>");
    return 0;
}

long int x = atoi(argv[1]);
long int y = atoi(argv[2]);
long int z = atoi(argv[3]);
printf("%ld\n", maxofthree(x, y, z)); // TODO change back to (x, y, z)
}

最佳答案

该代码导致段错误,因为在执行 ret 指令时它试图跳回到无效的返回地址。所有三个不同的 ret 指令都会发生这种情况。

发生这种情况的原因是因为您在返回之前没有弹出旧的基指针。对代码进行小的更改即可消除该错误。将每个 ret 指令更改为:

leave
ret

leave 指令将执行以下操作:

movl %ebp, %esp
popl %ebp

这将重置堆栈指针并弹出您保存的旧基指针。

此外,您的比较没有按照注释中指定的方式进行。当你这样做时:

cmp %eax, %edx
jl  firstsmaller

%edx小于%eax时发生跳转。所以你希望代码是

cmpl %edx, %eax
jl   firstsmaller

%eax 小于 %edx 时将跳转,如注释中所指定。

引用这个this page有关 AT&T/GAS 语法中 cmp 指令的详细信息。

关于c - 在 Assembly x86 中获取三个数字的最大值时出现段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22292548/

相关文章:

编译器使用局部变量而不调整 RSP

c - 如何通过 C 中的套接字发送和接收内存地址?

c - 如何在 ANSI C 中定义 NaN 值?

c - 我的 C 程序有一个 char,我希望它能容纳更多数据,我应该用什么数据类型替换它?

c++ - 通过 CreateProcessW 使用 "mkdir"创建的目录名称中的垃圾?

c - 如何将优化的 x86-64 asm 循环转换回 C for 循环?

assembly - JMP 对堆栈和帧指针执行什么操作?

c - Mac OS X x86-64 中指令指针的寻址

c - 堆栈缓冲区溢出文章中的奇怪地址

C 程序读取/写入文件,同时递增文件中的数字