首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >内联程序集- cdecl和准备堆栈

内联程序集- cdecl和准备堆栈
EN

Stack Overflow用户
提问于 2012-05-05 16:51:27
回答 4查看 1.2K关注 0票数 2

最近,我一直试图在C++中实现动态函数,方法是使用不同装配操作符的缓冲区和原始十六进制等价物。为了说明一个简单的跳转:

代码语言:javascript
复制
byte * buffer = new buffer[5];
*buffer = '0xE9'; // Hex for jump
*(uint*)(buffer + 1) = 'address destination';

我没有装配方面的经验,但我知道的足够创建非常简单的功能。现在,我正在原始内存中创建cdecl函数。问题是,我不知道我想用sub推动堆栈(对于内存)有多大。让我们以这个函数为例:

代码语言:javascript
复制
int MyTest(int x, int y) { return x + y; }

long TheTest(int x, int y)
{
    return MyTest(x, 5);
}

08048a20 <_Z6TheTestii>:
_Z6TheTestii():
 8048a20:   55                      push   %ebp
 8048a21:   89 e5                   mov    %esp,%ebp
 8048a23:   83 ec 18                sub    $0x18,%esp
 8048a26:   c7 44 24 04 05 00 00    movl   $0x5,0x4(%esp)
 8048a2d:   00 
 8048a2e:   8b 45 08                mov    0x8(%ebp),%eax
 8048a31:   89 04 24                mov    %eax,(%esp)
 8048a34:   e8 c2 ff ff ff          call   80489fb <_Z6MyTestii>
 8048a39:   c9                      leave  
 8048a3a:   c3                      ret    

如您所见,首先是C++代码,下面是'TheTest‘函数的ASM。人们可以立即注意到堆栈按24 (0x18)字节(正如前面提到的,我没有使用程序集的经验,所以我可能没有使用正确的术语和/或完全正确)。这对我来说没有任何意义。当只使用两个不同的整数时,为什么需要24个字节?变量'x‘是4个字节,而值'5’也使用4个字节(记住它是cdecl,因此调用函数处理函数参数的内存)不足以弥补24.

下面是另一个让我对程序集输出感到好奇的例子:

代码语言:javascript
复制
int NewTest(int x, char val) { return x + val; }

long TheTest(int x, int y)
{
    return NewTest(x, (char)6);
}

08048a3d <_Z6TheTestiiii>:
_Z6TheTestiiii():
 8048a3d:   55                      push   %ebp
 8048a3e:   89 e5                   mov    %esp,%ebp
 8048a40:   83 ec 08                sub    $0x8,%esp
 8048a43:   c7 44 24 04 06 00 00    movl   $0x6,0x4(%esp)
 8048a4a:   00 
 8048a4b:   8b 45 08                mov    0x8(%ebp),%eax
 8048a4e:   89 04 24                mov    %eax,(%esp)
 8048a51:   e8 ca ff ff ff          call   8048a20 <_Z7NewTestic>
 8048a56:   c9                      leave  
 8048a57:   c3                      ret    

这里唯一的区别(值除外)是,我使用的是'char‘(1字节)而不是整数。如果然后查看程序集代码,这只会将堆栈指针推送8个字节。这与前面的例子相差了16个字节。作为一个彻头彻尾的C++人,我不知道发生了什么.如果有人能在这个问题上启发我,我会非常感激的!

注意:我之所以在这里发帖而不是阅读ASM书籍,是因为我需要为这个函数使用程序集。所以我不想读40行代码的整本书.

编辑:我也不关心平台依赖性,我只关心Linux 32位:)

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-05-05 17:07:49

TheTest中创建的堆栈框架包含本地(自动)变量和函数的参数,如由TheTest调用的MyTestNewTest。框架是由TheTest推送和弹出的,所以只要它足够大,足以容纳它调用的函数的参数,大小就无关紧要了。

您正在看到的编译器输出是编译器几次传递的结果。每一次传递都可能执行转换和优化,以减少所需的帧大小;我怀疑编译器在某种早期状态下需要24字节的帧,即使对代码进行了优化,它也不会减少。

您平台上编译器的ABI将建立一些关于堆栈对齐的规则,您必须遵循这些规则,因此帧大小被舍入以满足这些要求。

这些函数使用框架指针%ebp%,尽管这不是代码大小或性能的胜利;不过,这可能有助于调试。

票数 2
EN

Stack Overflow用户

发布于 2012-05-05 17:19:07

在我看来,您的编译器似乎犯了第一个函数的错误(可能缺少堆栈使用优化)。这也是奇怪的是,您的编译器使用两个指令(移动到一个预先分配的堆栈槽),而不是一个推送指令。

您是否正在编译而不进行优化?你能张贴你的编译器命令行吗?

票数 1
EN

Stack Overflow用户

发布于 2012-05-06 11:25:27

这是为了保持堆栈对齐到32字节的多个字节,以便SIMD指令可以与堆栈上的变量一起使用。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/10463960

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档