从 C 调用汇编函数时出现段错误

Segmentation fault error when calling assembly function from C

我目前正在尝试 link 将函数汇编到我的 C 代码驱动程序中以用于大学作业。执行程序后,出现段错误。

下面将包括我的 C 文件、ASM 文件和来自 GDB 调试器的信息。

C代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void add(char*, char*); //would extern be needed here maybe?

int main(){

    int choice;

    char num1[3];
    char num2[3];

    printf("Welcome to the back and forth program!\n\n");
    
    do{

        printf("What would you like to do?\n\n");
        printf("1. Add two numbers together.\n");
        printf("2. Find if a string is a palindrome. (ASM Version)\n");
        printf("3. Find the factorial of a number.\n");
        printf("4. Find if a string is a palindrome. (C Version)\n");
        printf("5. Exit Program.\n\n");
        printf("choose 1-5: ");

        scanf("%d", &choice);
        getchar();

        while(choice < 1 || choice > 5){

            printf("\nPlease choose an option between 1 and 5.\n");
            
            scanf("%d", &choice);
            getchar();

        }

        switch(choice){

            case 1:

                printf("\n*Add two numbers together*\n\n");
                printf("Please enter a number: ");

                fgets(num1, 1024, stdin);

                num1[strlen(num1) - 1] = '[=10=]';

                printf("\nPlease enter a second number: ");

                fgets(num2, 1024, stdin);

                num2[strlen(num2) - 1] = '[=10=]';

                add(num1, num2);

                printf("\nResult: %s\n", num2);

            case 2:

            case 3:

            case 4:

            case 5:

                printf("\nThanks for using!\n");

                break;

        }

    }while(choice != 5);

    return 0;

}

这里要注意一件事,我的教授特别指出我将两个数字作为字符串读入,然后使用汇编中的 atoi() 函数将字符串转换为 int。

现在,我的 ASM 代码:

BITS 32
GLOBAL add
EXTERN atoi

section .data

section .bss

section .text

add:
    push ebp
    mov ebp, esp

    push eax
    call atoi
    push ebx
    call atoi

    mov eax, [ebp+8]
    mov ebx, [ebp+12]
    add eax, ebx

    pop ebx
    ret

由于我需要从我的汇编函数中调用 atoi(),我认为有必要使用堆栈。

最后,GDB 调试器说的是:

Program received signal SIGSEGV, Segmentation fault.
0xffffcdbc in ?? ()

有关调试器错误的说明:单步执行程序时,一旦达到 add(num1, num2) 就会显示此错误。

关于其他一些重要信息,我正在通过 VirtualBox 在虚拟机中使用 GCC 编译器、NASM 编译器、Intel Assembler i386 和 运行 Debian 10 x86_64 .

如有任何帮助,我们将不胜感激!

我看到的第一个问题就是你用的:

fgets(num1, 1024, stdin); 但是 num1 只有 3 个字节作为缓冲区,但这不是分段错误的根本原因。

另一个问题是您将 add 函数声明为:

void add(char*, char*);。我认为将其声明为 int add(char*, char*); 并将此函数的结果用作两个数字的总和会更容易。

问题出在汇编代码中,您没有使用正确的参数。例如这部分:

    push eax
    call atoi
    push ebx
    call atoi

您使用 eaxebx 作为 atoi 的参数,但 add 函数的参数在 [ebp + 8][ebp+12] 中.调用后你需要确保堆栈是干净的,你需要使用add esp, 4(因为它只有一个参数)

要记住的另一件事是,在 call atoi 之后,结果将存储在 eax 寄存器中,因为你在 atoi 之后调用 atoi,你将丢失第一个结果.您需要存储第一个 atoi(在 stack/local 变量上)的结果,然后将其添加到第二次调用 atoi 的下一个结果中。我将放置在 32 位上工作的我的 C 代码和程序集版本。

C代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int add(char*, char*); //would extern be needed here maybe?

int main(){

    int choice;
    int sum;

    char num1[3];
    char num2[3];

    printf("Welcome to the back and forth program!\n\n");
    
    do{

        printf("What would you like to do?\n\n");
        printf("1. Add two numbers together.\n");
        printf("2. Find if a string is a palindrome. (ASM Version)\n");
        printf("3. Find the factorial of a number.\n");
        printf("4. Find if a string is a palindrome. (C Version)\n");
        printf("5. Exit Program.\n\n");
        printf("choose 1-5: ");

        scanf("%d", &choice);
        getchar();

        while(choice < 1 || choice > 5){

            printf("\nPlease choose an option between 1 and 5.\n");
            
            scanf("%d", &choice);
            getchar();

        }

        switch(choice){

            case 1:

                printf("\n*Add two numbers together*\n\n");
                printf("Please enter a number: ");
                scanf("%s", num1);

                printf("\nPlease enter a second number: ");
                scanf("%s", num2);

                sum = add(num1, num2);
                printf("\nResult: %d\n", sum);

            case 2:

            case 3:

            case 4:

            case 5:

                printf("\nThanks for using!\n");

                break;

        }

    }while(choice != 5);

    return 0;

}

汇编代码:

BITS 32
GLOBAL add
EXTERN atoi

section .data

section .bss

section .text

add:
    push ebp
    mov ebp, esp

    push dword [ebp + 8]
    call atoi
    add esp, 4

    push eax
    
    push dword [ebp + 12]
    call atoi
    add esp, 4
    
    pop ecx

    add eax, ecx

    leave
    ret