Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 汇编函数到C程序,无需传递参数或返回值_Assembly_C_Gcc_Function_Parameter Passing - Fatal编程技术网

Assembly 汇编函数到C程序,无需传递参数或返回值

Assembly 汇编函数到C程序,无需传递参数或返回值,assembly,c,gcc,function,parameter-passing,Assembly,C,Gcc,Function,Parameter Passing,我需要创建一个汇编函数,将两个正数相加,由C程序调用 C程序如下所示: #include <stdio.h> int main(void){ int a = 0; int b = 0; int c = 0; printf( "Enter first number: " ); scanf( "%d", &a ); printf( "Enter second number: " ); scanf( "%d", &b ); sum(); printf( "Answer i

我需要创建一个汇编函数,将两个正数相加,由C程序调用

C程序如下所示:

#include <stdio.h>

int main(void){
int a = 0;
int b = 0;
int c = 0;
printf( "Enter first number: " );
scanf( "%d", &a );
printf( "Enter second number: " );
scanf( "%d", &b );
sum();
printf( "Answer is %d\n", sum );
}
#包括
内部主(空){
int a=0;
int b=0;
int c=0;
printf(“输入第一个数字:”);
scanf(“%d”和“&a”);
printf(“输入第二个数字:”);
scanf(“%d”和“b”);
sum();
printf(“答案是%d\n”,总和);
}
要求汇编函数(
sum()
)不应传递任何参数,也不应返回任何值。此外,如果有必要,汇编函数位于单独的文件sum.s中

我试了很多,读了很多。但是,我仍然无法访问
main()
中的变量。谢谢你的帮助。:)

调用sum()时,编译器会将当前指令指针的地址推送到堆栈上,然后跳转到子例程的位置。按下当前指令指针是为了使子例程可以通过弹出地址返回

因此,在子例程中,第一件事情是返回地址(即,在堆栈的底部,因为堆栈从上到下推动)。紧接在堆栈上的是调用子例程的例程的局部变量

因此,如果
esp
是堆栈指针寄存器,
[esp]
是内存中
sp
指向的位置,并且假设是32位代码,
求和
子例程应该找到像
[esp+4]
[esp+8]
[esp+12]这样的地址
包含局部变量的地址

为了证实我所说的,我建议您查看C代码发出的程序集:使用调试器反汇编机器代码,或者使用编译器命令行选项生成汇编语言列表文件


编辑:moonshadow认为这是一个“脆弱”的解决方案是正确的。例如,“
c
”变量是存储在堆栈中还是存储在寄存器中(或者它是否被定义,而不是编译器假设它是硬编码常量零),这可能取决于是否启用了编译器优化。

调用sum()时,编译器将推送(在堆栈上)当前指令指针的地址,然后跳转到子例程的位置。按下当前指令指针可以使子例程通过弹出地址返回

因此,在子例程内部,第一件事是返回地址(即在堆栈的底部,因为堆栈从上到下推动)。堆栈上的返回地址正上方是调用子例程的例程的局部变量

因此,如果
esp
是堆栈指针寄存器,
[esp]
是内存中
sp
指向的位置,并且假设是32位代码,
求和
子例程应该找到像
[esp+4]
[esp+8]
[esp+12]这样的地址
包含局部变量的地址

为了证实我所说的,我建议您查看C代码发出的程序集:使用调试器反汇编机器代码,或者使用编译器命令行选项生成汇编语言列表文件



编辑:moonshadow认为这是一个“脆弱”的解决方案,这是正确的。例如,“
c
”变量是存储在堆栈上还是存储在寄存器中(或者它甚至是定义的,而不是编译器假设它是硬编码常量零)根据是否启用编译器优化,可能会有所不同。

没有参数传递似乎是一个奇怪的要求-这可能会导致非常脆弱的代码;通常情况下,您会让C代码像正常情况一样传递参数,并且汇编函数会将它们从相应的寄存器和/或调用定义的堆栈中提取出来修改约定,并将结果写入其中

不过,如果这确实是您想要的,那么它是可行的。您需要做的是阅读编译器的ABI文档,了解它是如何布局堆栈框架的。然后,您的汇编函数将需要确定调用方堆栈框架的位置—指向它的指针或偏移量,以及返回地址和任何参数,通常是PUSH当调用任何函数时,堆栈上的d—以及局部变量a、b和c在内存中的位置。布局将取决于ABI,当您阅读这些文档时,您会发现它还取决于调用约定和您在调用方的作用域中本地声明的内容,以及可能的优化级别。因此,生成的程序集函数ion将与您当前的实现紧密地结合在一起—很脆弱—如果几乎任何事情发生变化,ion很可能会崩溃。通用解决方案是不可能的


顺便说一句,在你的
printf(“答案是%d\n”,
sum
);
行中,我想你的意思是
c
,而不是
sum
将生成sum的地址()函数,它可能会被编译器硬连线并在链接时固定,因此无法使该符号打印运行时结果。

没有参数传递似乎是一个奇怪的要求-它可能会导致非常脆弱的代码;通常,您会让C代码像正常情况一样传递参数,而汇编函数uld从调用约定定义的适当寄存器和/或堆栈中提取它们,并将结果写入其中

不过,如果这确实是您想要的,那么它是可行的。您需要做的是阅读编译器的ABI文档,了解它是如何布局堆栈框架的。然后,您的汇编函数将需要确定调用方堆栈框架的位置—指向它的指针或偏移量,以及返回地址和任何参数,通常是PUSH当任何函数
-------
|  a  |
-------
|  b  |
-------
|  c  |
-------
------- TOS
|  a  |
------- TOS - 4
|  b  |
------- TOS - 8
|  c  |
------- TOS - 12
| ret |
| eip | 
------- TOS - 16
ESP = TOS - 16
mov eax, ss:[esp + 12] ; eax = a
add eax, ss:[esp +  8] ; eax += b
mov ss:[esp +  4], eax ; c   = eax
ret