我在Win32上使用图形用户界面应用程序的C++builder。Borland编译器优化非常糟糕,不知道如何使用SSE。我有一个函数,用名为gcc 4.7编译时,速度是原来的5倍。我想让gcc生成汇编代码,然后在我的C函数中使用这个代码,因为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++中函数参数访问是如何完成的帮助。我在Borland的C++中的函数类似于:
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等调用约定访问参数吗?
发布于 2013-04-08 15:14:55
在这两种情况下,参数的传递方式类似。不同之处在于Borland生成的代码表达了相对于EBP寄存器的参数位置和相对于ESP的GCC的参数位置,但它们都引用了相同的地址。
Borland将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,因此当访问参数时,关系保持不变。
在这两种情况下,调用约定似乎都是cdecl,并且函数的调用方式没有区别。您可以将关键字__cdecl添加到这两者中,以使这一点变得清晰。
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"选项的
发布于 2013-04-08 07:05:53
我建议您阅读一些有关应用程序二进制接口的内容。下面是一个相关链接,可以帮助您了解哪个编译器会生成哪种类型的代码:https://en.wikipedia.org/wiki/X86_calling_conventions
发布于 2013-04-08 07:53:28
我会尝试要么用GCC编译所有的东西,要么看看是不是只用GCC编译关键文件,其余的用Borland编译,并将作品链接在一起。您所解释的内容可以工作,但这将是一项艰巨的工作,可能不值得您投入时间(除非它将在许多机器上非常频繁地运行)。
https://stackoverflow.com/questions/15862979
复制相似问题