GCC - 如何重新排列堆栈?

时间:2010-05-04 12:41:23

标签: c gcc stack pthreads sse

我尝试构建一个使用pthreads和__m128 SSE类型的应用程序。根据GCC手册,默认堆栈对齐是16个字节。为了使用__m128,要求是16字节对齐。

我的目标CPU支持SSE。我使用的GCC编译器不支持运行时堆栈重组(例如-mstackrealign)。我不能使用任何其他GCC编译器版本。

我的测试应用程序如下:

#include <xmmintrin.h>
#include <pthread.h>
void *f(void *x){
   __m128 y;
   ...
}
int main(void){
  pthread_t p;
  pthread_create(&p, NULL, f, NULL);
}

应用程序生成异常并退出。经过简单的调试(printf“%p”,&amp; y)后,我发现变量y不是16字节对齐的。

我的问题是:如何在不使用任何GCC标志和属性(它们没有帮助)的情况下正确地重新对齐堆栈(16字节)?我应该在这个线程函数f()中使用GCC内联汇编程序吗?

5 个答案:

答案 0 :(得分:7)

在堆栈上分配一个比sizeof(__m128)大15个字节的数组,并使用该数组中的第一个对齐地址。如果需要多个,请将它们分配到一个具有15个字节边距的数组中进行对齐。

我不记得分配一个unsigned char数组是否可以使您免受编译器严格别名优化的影响,或者它是否仅适用于其他方式。

#include <stdint.h>

void *f(void *x)
{
   unsigned char y[sizeof(__m128)+15];
   __m128 *py = (__m128*) (((uintptr_t)&y) + 15) & ~(uintptr_t)15);
   ...
}

答案 1 :(得分:3)

这不应该首先发生,但要解决问题,你可以尝试:

void *f(void *x)
{
   __m128 y __attribute__ ((aligned (16)));
   ...
}

答案 2 :(得分:1)

另一个解决方案是,使用填充函数,首先对齐堆栈,然后调用f。因此,不要直接调用f,而是调用pad,先填充堆栈,然后使用对齐的堆栈调用foo

代码如下所示:

#include <xmmintrin.h>
#include <pthread.h>

#define ALIGNMENT 16

void *f(void *x) {
    __m128 y;
    // other stuff
}

void * pad(void *val) {
    unsigned int x; // to get the current address from the stack
    unsigned char pad[ALIGNMENT - ((unsigned int) &x) % ALIGNMENT];
    return f(val);
}

int main(void){
    pthread_t p;
    pthread_create(&p, NULL, pad, NULL);
}

答案 3 :(得分:0)

我已经解决了这个问题。 这是我的解决方案:

void another_function(){
   __m128 y;
   ...
}
void *f(void *x){
asm("pushl    %esp");
asm("subl    $16,%esp");
asm("andl    $-0x10,%esp");
another_function();
asm("popl %esp");
}

首先,我们将堆栈增加16个字节。其次,我们使最不重要的半字节等于0x0。我们使用push / pop操作数保留堆栈指针。我们调用另一个函数,它具有16字节对齐的所有自己的局部变量。所有嵌套函数的局部变量也都是16字节对齐的。

它有效!

答案 4 :(得分:0)

很抱歉复活旧帖...

对于使用比OP更新的编译器的用户,OP会提到-mstackrealign选项,这会将我引导至__attribute__((force_align_arg_pointer))。如果您的函数正在优化以使用SSE,但%ebp未对齐,则会根据您的需要透明地执行运行时修复。我还发现这只是i386上的一个问题。 x86_64 ABI保证参数与16个字节对齐。

__attribute__((force_align_arg_pointer)) void i_crash_when_not_aligned_to_16_bytes() { ... }

为那些可能想要了解更多信息的人提供的文章:http://camel.apache.org/message-endpoint.html