Home > OS >  Segmentation fault error when calling assembly function from C
Segmentation fault error when calling assembly function from C

Time:11-27

I'm currently trying to link assembly functions to my C code driver for a college assignment. Upon executing the program, I get a seg fault error.

Below will include what's in my C file, ASM file, and the info from the GDB debugger.

C code:

#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] = '\0';

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

                fgets(num2, 1024, stdin);

                num2[strlen(num2) - 1] = '\0';

                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;

}

One thing to note here, is that my professor is specifically stating I read in the two numbers as strings, and then use the atoi() function in assembly to convert from string to int.

Now, my ASM code:

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

Since I'm required to call atoi() from my Assembly function, I'd assume it's necessary to use a stack.

Finally, what the GDB debugger is saying:

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

A note on the debugger error: when stepping through the program, it says this error once it reaches add(num1, num2).

For some other important information, I'm using the GCC compiler, NASM compiler, Intel Assembler i386, and am running Debian 10 x86_64 in a virtual machine via VirtualBox.

Any help on the matter would be greatly appreciated!

CodePudding user response:

The first problem that I saw it's that you used:

fgets(num1, 1024, stdin); but num1 have only 3 bytes as a buffer, but this is not the root cause for the segmentation fault.

Another problem was that you declared your add function as:

void add(char*, char*);. I think it's easier to declare it as int add(char*, char*); and use the result from this function as the sum of both numbers.

The problem was in the assembly code, you didn't use the right parameter. For example in this part:

    push eax
    call atoi
    push ebx
    call atoi

You used eax and ebx as parameters for atoi, but the parameters for add function are in [ebp 8] and [ebp 12]. After the call you need to be sure that the stack is clean and you need to use add esp, 4(because it's only one parameter)

Another thing to remember is that after call atoi the result will be stored in eax register and because you call atoi after atoi you will lose the first result. You need to store the result from the first atoi(on stack/local variable) and then add it to the next result from the second call to atoi. I will put my version of C code and assembly that worked on 32 BITS.

C code:

#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;

}

Assembly code:

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

CodePudding user response:

Can you try increasing array size ? Most of the times accessing array element outside it's defined length is reason for Segmentation Fault.

  • Related