从 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
您使用 eax
和 ebx
作为 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
我目前正在尝试 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
您使用 eax
和 ebx
作为 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