Ошибка сегментации при вызове функции сборки из C

# #c #assembly #gcc #x86 #nasm

Вопрос:

В настоящее время я пытаюсь связать функции сборки с моим драйвером кода C для задания в колледже. При выполнении программы я получаю ошибку ошибки seg.

Ниже будет указано, что находится в моем файле C, файле ASM и информации из отладчика GDB.

Код C:

 #include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;string.hgt;  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!nn");    do{   printf("What would you like to do?nn");  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.nn");  printf("choose 1-5: ");   scanf("%d", amp;choice);  getchar();   while(choice lt; 1 || choice gt; 5){   printf("nPlease choose an option between 1 and 5.n");    scanf("%d", amp;choice);  getchar();   }   switch(choice){   case 1:   printf("n*Add two numbers together*nn");  printf("Please enter a number: ");   fgets(num1, 1024, stdin);   num1[strlen(num1) - 1] = '';   printf("nPlease enter a second number: ");   fgets(num2, 1024, stdin);   num2[strlen(num2) - 1] = '';   add(num1, num2);   printf("nResult: %sn", 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) .

Для получения другой важной информации я использую компилятор GCC, компилятор NASM, ассемблер Intel i386 и запускаю Debian 10 x86_64 на виртуальной машине через VirtualBox.

Любая помощь по этому вопросу будет весьма признательна!

Комментарии:

1. pop ebx вероятно, это опечатка для pop ebp ?

Ответ №1:

Первая проблема, которую я увидел, это то, что вы использовали:

fgets(num1, 1024, stdin); но у num1 есть только 3 байта в качестве буфера, но это не является основной причиной ошибки сегментации.

Другая проблема заключалась в том, что вы объявили свою add функцию как:

void add(char*, char*); . Я думаю, что проще объявить его как int add(char*, char*); и использовать результат этой функции как сумму обоих чисел.

Проблема была в коде сборки, вы не использовали правильный параметр. Например, в этой части:

 push eax  call atoi  push ebx  call atoi  

Вы использовали eax и ebx в качестве параметров для atoi , но параметры для add функции находятся в [ebp 8] и [ebp 12] . После вызова вам нужно убедиться, что стек чист, и вам нужно использовать add esp, 4 (потому что это только один параметр)

Еще одна вещь, которую следует помнить, это то, что после call atoi того, как результат будет сохранен в eax реестре, и потому, что вы позвоните atoi после atoi того, как потеряете первый результат. Вам нужно сохранить результат из первого atoi (в стеке/локальной переменной), а затем добавить его в следующий результат из второго вызова atoi . Я помещу свою версию кода на C и сборку, которая работала на 32 битах.

Код C:

 #include lt;stdio.hgt; #include lt;stdlib.hgt; #include lt;string.hgt;  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!nn");    do{   printf("What would you like to do?nn");  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.nn");  printf("choose 1-5: ");   scanf("%d", amp;choice);  getchar();   while(choice lt; 1 || choice gt; 5){   printf("nPlease choose an option between 1 and 5.n");    scanf("%d", amp;choice);  getchar();   }   switch(choice){   case 1:   printf("n*Add two numbers together*nn");  printf("Please enter a number: ");  scanf("%s", num1);   printf("nPlease enter a second number: ");  scanf("%s", num2);   sum = add(num1, num2);  printf("nResult: %dn", 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   

Комментарии:

1. Классно!! Итак, сначала у меня была та же идея add , что и функция int, но по какой-то странной причине мой профессор требует, чтобы я имел эту функцию как пустую… Спасибо, что указали на то, что вы сделали! Я все еще учусь передавать информацию между ASM и C, и это очень помогает.

2. Затем файл asm нуждается в нескольких изменениях. Вам нужно перезаписать [ebp 8] или [ebp 12] использовать целое число из eax . Но будьте осторожны, потому [ebp 8} что и [ebp 12] являются адресами, а eax-это в основном целое число.

3.Лучше писать mov [ebp-4], eax вместо пары add esp, 4 push eax .

4. @SepRoland Да, но было бы сложнее понять.

5. @MocanuGabriel Я обязательно посмотрю, как это сделать@Sep Roland Я также посмотрю на это и выясню, что это такое, ха-ха! Мой курс ASM-это всего лишь вводный курс, но я собираюсь узнать об этом больше. Спасибо вам обоим за вашу помощь и вклад!