7

我尝试构建一个使用 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", &y),我发现变量y不是16字节对齐的。

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

4

5 回答 5

7

在堆栈上分配一个比 大 15 字节的数组sizeof(__m128),并使用该数组中的第一个对齐地址。如果需要多个,请将它们分配到一个数组中,并留出 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);
   ...
}
于 2010-05-04T13:04:53.050 回答
3

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

void *f(void *x)
{
   __m128 y __attribute__ ((aligned (16)));
   ...
}
于 2010-05-04T12:47:42.997 回答
3

很抱歉复活一个旧线程......

对于那些使用比 OP 更新的编译器的人,OP 提到了一个-mstackrealign选项,这导致我使用__attribute__((force_align_arg_pointer)). 如果您的函数正在优化以使用 SSE,但未%ebp对齐,这将在您需要时透明地进行运行时修复。我还发现这只是i386. x86_64ABI 保证参数对齐到 16 个字节。

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

对于那些可能想了解更多信息的人来说,很酷的文章:http ://wiki.osdev.org/System_V_ABI

于 2017-06-15T18:18:46.073 回答
2

另一种解决方案是,使用填充函数,它首先对齐堆栈,然后调用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);
}
于 2010-05-05T12:47:22.987 回答
-2

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

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 字节对齐。

它有效!

于 2010-05-04T16:01:04.753 回答