# #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-это всего лишь вводный курс, но я собираюсь узнать об этом больше. Спасибо вам обоим за вашу помощь и вклад!