首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在C++生成器中使用GCC生成的汇编器

在C++生成器中使用GCC生成的汇编器
EN

Stack Overflow用户
提问于 2013-04-07 21:35:34
回答 3查看 1.1K关注 0票数 2

我在Win32上使用图形用户界面应用程序的C++builder。Borland编译器优化非常糟糕,不知道如何使用SSE。我有一个函数,用名为gcc 4.7编译时,速度是原来的5倍。我想让gcc生成汇编代码,然后在我的C函数中使用这个代码,因为Borland编译器允许内联汇编。

C中的函数如下所示:

代码语言:javascript
复制
void Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT)
{
double s = 77.777;
size_t m = mA[NT-3];
AV[2]=x[n-4]+m*s;
}

为了简化我的问题,我把函数代码写得非常简单。我的实际函数包含许多循环。

Borland C++编译器生成了以下汇编代码:

代码语言:javascript
复制
  ;
  ; void Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT)
  ;
  @1:
push      ebp
mov       ebp,esp
add       esp,-16
push      ebx
 ;
 ;  {
 ;      double s = 77.777;
 ;
mov       dword ptr [ebp-8],1580547965
mov       dword ptr [ebp-4],1079210426
 ;
 ;      size_t m = mA[NT-3];
 ;
mov       edx,dword ptr [ebp+20]
mov       ecx,dword ptr [ebp+24]
mov       eax,dword ptr [edx+4*ecx-12]
 ;
 ;      AV[2]=x[n-4]+m*s;
 ;
 ?live16385@48: ; EAX = m
xor       edx,edx
mov       dword ptr [ebp-16],eax
mov       dword ptr [ebp-12],edx
fild      qword ptr [ebp-16]
mov       ecx,dword ptr [ebp+8]
mov       ebx,dword ptr [ebp+12]
mov       eax,dword ptr [ebp+16]
fmul      qword ptr [ebp-8]
fadd      qword ptr [ecx+8*ebx-32]
fstp      qword ptr [eax+16]
 ;
 ;  }
 ;
 ?live16385@64: ;
 @2:
pop       ebx
mov       esp,ebp
pop       ebp
ret

而gcc生成的汇编代码是:

代码语言:javascript
复制
 _Test_Fn:
mov edx, DWORD PTR [esp+20]
mov eax, DWORD PTR [esp+16]
mov eax, DWORD PTR [eax-12+edx*4]
mov edx, DWORD PTR [esp+8]
add eax, -2147483648
cvtsi2sd    xmm0, eax
mov eax, DWORD PTR [esp+4]
addsd   xmm0, QWORD PTR LC0
mulsd   xmm0, QWORD PTR LC1
addsd   xmm0, QWORD PTR [eax-32+edx*8]
mov eax, DWORD PTR [esp+12]
movsd   QWORD PTR [eax+16], xmm0
ret
 LC0:
   .long    0
   .long    1105199104
   .align 8
 LC1:
   .long    1580547965
   .long    1079210426
   .align 8

我喜欢得到关于在gcc和Borland C++中函数参数访问是如何完成的帮助。我在Borland的C++中的函数类似于:

代码语言:javascript
复制
 void Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT)
 {
__asm
  {
  put gcc generated assembler here
  }
 }

Borland开始使用ebp寄存器,而gcc使用esp寄存器。我可以强制其中一个编译器生成兼容的代码,以便使用cdecl ou stdcall等调用约定访问参数吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-04-08 15:14:55

在这两种情况下,参数的传递方式类似。不同之处在于Borland生成的代码表达了相对于EBP寄存器的参数位置和相对于ESP的GCC的参数位置,但它们都引用了相同的地址。

Borland将EBP设置为指向函数堆栈帧的开头,并表示相对于该堆栈帧的位置,而GCC不设置新的堆栈帧,而是表示相对于ESP的位置,调用者将ESP留在指向调用者堆栈帧的末尾。

Borland生成的代码在函数的开头设置了一个堆栈帧,导致Borland代码中的EBP等于GCC代码中的ESP减去4。这可以通过查看前两行Borland代码来看出:

代码语言:javascript
复制
push      ebp     ; decrease esp by 4
mov       ebp,esp ; ebp = the original esp decreased by 4

在过程结束之前,GCC代码不会改变ESP,Borland代码也不会改变EBP,因此当访问参数时,关系保持不变。

在这两种情况下,调用约定似乎都是cdecl,并且函数的调用方式没有区别。您可以将关键字__cdecl添加到这两者中,以使这一点变得清晰。

代码语言:javascript
复制
 void __cdecl Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT)

然而,在用Borland编译的函数中添加用GCC编译的内联程序集并不简单,因为Borland可能会设置一个堆栈帧,即使函数体中只包含内联程序集,也会导致ESP寄存器的值与GCC代码中使用的值不同。我认为有三种可能的解决方法:

不带"Standard stack frames"选项的

  1. 使用Borland进行编译。如果编译器计算出不需要堆栈帧,这可能会起作用。
  2. 使用不带-fomit-frame-pointer选项的GCC进行编译。这应该确保两者的EBP值至少是相同的。此选项在ESP、ESP、EBP和-Os.
  3. Manually级别上启用。编辑由GCC生产的装配件,将对-O的引用更改为-O2,并在偏移量上添加4。
票数 2
EN

Stack Overflow用户

发布于 2013-04-08 07:05:53

我建议您阅读一些有关应用程序二进制接口的内容。下面是一个相关链接,可以帮助您了解哪个编译器会生成哪种类型的代码:https://en.wikipedia.org/wiki/X86_calling_conventions

票数 1
EN

Stack Overflow用户

发布于 2013-04-08 07:53:28

我会尝试要么用GCC编译所有的东西,要么看看是不是只用GCC编译关键文件,其余的用Borland编译,并将作品链接在一起。您所解释的内容可以工作,但这将是一项艰巨的工作,可能不值得您投入时间(除非它将在许多机器上非常频繁地运行)。

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

https://stackoverflow.com/questions/15862979

复制
相关文章

相似问题

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