在C+中使用GCC生成的汇编程序+;建设者

在C+中使用GCC生成的汇编程序+;建设者,gcc,assembly,x86,c++builder,calling-convention,Gcc,Assembly,X86,C++builder,Calling Convention,我正在Win32上使用C++builder作为GUI应用程序。Borland编译器优化非常糟糕,不知道如何使用SSE。 我有一个使用MingWGCC4.7编译时速度快5倍的函数。 我考虑让gcc生成汇编代码,然后在我的C函数中使用这个cod,因为Borland编译器允许内联汇编 C中的函数如下所示: void Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT) { double s = 77.777; size_t m =

我正在Win32上使用C++builder作为GUI应用程序。Borland编译器优化非常糟糕,不知道如何使用SSE。 我有一个使用MingWGCC4.7编译时速度快5倍的函数。 我考虑让gcc生成汇编代码,然后在我的C函数中使用这个cod,因为Borland编译器允许内联汇编

C中的函数如下所示:

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++编译器生成汇编代码:

  ;
  ; 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生成的汇编程序代码是:

 _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++中完成的帮助。 我在C++中对Borland的功能将类似于:

 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)生成用于访问参数的兼容代码?

我建议您阅读一下应用程序二进制接口。 下面是一个相关链接,可帮助您了解什么编译器生成什么类型的代码:

我建议您阅读一下应用程序二进制接口。 下面是一个相关链接,可帮助您了解什么编译器生成什么类型的代码:

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

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

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

Borlands将EBP设置为指向函数堆栈帧的开始,并表示相对于该堆栈帧的位置,而GCC不设置新的堆栈帧,而是表示相对于ESP的位置,调用方将ESP的位置向左指向调用方堆栈帧的结尾

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

push      ebp     ; decrease esp by 4
mov       ebp,esp ; ebp = the original esp decreased by 4
GCC代码不会更改ESP,Borland代码直到过程结束才会更改EBP,因此在访问参数时relationsip保持不变

调用约定似乎在这两种情况下都存在,函数的调用方式没有区别。您可以将关键字
\uuuu cdecl
添加到两者中,以明确这一点

 void __cdecl Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT)
但是,将使用GCC编译的内联程序集添加到使用Borland编译的函数并不简单,因为即使函数体仅包含内联程序集,Borland也可能会设置堆栈框架,从而导致ESP寄存器的值与GCC代码中使用的值不同。我认为有三种可能的解决办法:

  • 使用Borland编译,不带选项。如果编译器发现不需要堆栈帧,这可能会起作用
  • 使用GCC编译而不使用该选项。这应确保至少两种情况下EBP的值相同。该选项在-O、-O2、-O3和-Os级别启用
  • 手动编辑GCC生成的程序集,将对ESP的引用更改为EBP,并将4添加到偏移量

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

    Borlands将EBP设置为指向函数堆栈帧的开始,并表示相对于该堆栈帧的位置,而GCC不设置新的堆栈帧,而是表示相对于ESP的位置,调用方将ESP的位置向左指向调用方堆栈帧的结尾

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

    push      ebp     ; decrease esp by 4
    mov       ebp,esp ; ebp = the original esp decreased by 4
    
    GCC代码不会更改ESP,Borland代码直到过程结束才会更改EBP,因此在访问参数时relationsip保持不变

    调用约定似乎在这两种情况下都存在,函数的调用方式没有区别。您可以将关键字
    \uuuu cdecl
    添加到两者中,以明确这一点

     void __cdecl Test_Fn(double *x, size_t n,double *AV, size_t *mA, size_t NT)
    
    但是,将使用GCC编译的内联程序集添加到使用Borland编译的函数并不简单,因为即使函数体仅包含内联程序集,Borland也可能会设置堆栈框架,从而导致ESP寄存器的值与GCC代码中使用的值不同。我认为有三种可能的解决办法:

  • 使用Borland编译,不带选项。如果编译器发现不需要堆栈帧,这可能会起作用
  • 使用GCC编译而不使用该选项。这应确保至少两种情况下EBP的值相同。该选项在-O、-O2、-O3和-Os级别启用
  • 手动编辑GCC生成的程序集,将对ESP的引用更改为EBP,并将4添加到偏移量

  • 正如你所说,他们必须提到相同的地址。但是计算
    m=mA[NT-3]
    的Borland代码让我推断变量
    *mA
    位于ESP+20和变量