0

一开始对内联汇编不是很熟悉,对 blackfin 处理器的了解就更少了。我正在将遗留的 C 应用程序迁移到 C++ 的过程中,今天早上遇到了关于以下例程的问题:

//
void clear_buffer ( short * buffer, int len ) {
    __asm__ (
            "/* clear_buffer */\n\t"
            "LSETUP (1f, 1f) LC0=%1;\n"
            "1:\n\t"
            "W [%0++] = %2;"
            :: "a" ( buffer ), "a" ( len ), "d" ( 0 )
            : "memory", "LC0", "LT0", "LB0"
    );
}

short我有一个类,其中包含一个用于音频处理的 s 数组:

class AudProc
{
    enum { buffer_size = 512 };

    short M_samples[ buffer_size * 2 ];

    // remaining part of class omitted for brevity
};

AudProc类中,我有一个调用 的方法,clear_buffer将样本数组传递给它:

clear_buffer ( M_samples, sizeof ( M_samples ) / 2 );

这会生成“总线错误”并中止应用程序。

我尝试将数组公开,并产生相同的结果。我也尝试过使其成为静态的;这允许调用没有错误地通过,但不再允许我的类的多个实例,因为每个实例都需要自己的缓冲区来使用。现在,我的第一个想法是,它与缓冲区在内存中的位置或访问它的位置有关。是否需要在内联程序集中更改某些内容以使其工作,或者以调用方式?

认为这与我试图完成的任务相似,但它使用的是不同的 asm 方言,我无法弄清楚我遇到的问题是否相同:

GCC 扩展 asm,struct 元素偏移编码

  1. 任何人都知道为什么会发生这种情况以及如何纠正它?
  2. 有谁知道哪里有关于 blackfin asm 指令集的有用文档?我试过在 ADSP 网站上查找,但无济于事。
4

3 回答 3

0

我怀疑您可以将您的定义clear_buffer

 inline void clear_buffer (short * buffer, int len) {
   memset (buffer, 0, sizeof(short)*len);
 }

-O2并且可能 GCC 能够巧妙地优化(当使用or调用时-O3)(因为 GCC 知道memset)。

为了理解汇编代码,我建议gcc -S -O -fverbose-asm在一些小的 C 文件上运行,然后查看生成的.s文件。

于 2012-12-04T16:16:35.543 回答
0

我会猜测,因为我不知道 Blackfin 汇编程序:

LC0听起来像“循环计数器”,LSETUP看起来像一个宏/insn,它在两个标签之间设置了一个循环,并带有一个特定的循环计数器。

“%0”操作数显然是要写入的地址,我们可以放心地猜测它在循环中递增,换句话说,它既是输入操作数又是输出操作数,应该这样描述。因此,我建议将其描述为输入输出操作数,使用“+”约束修饰符,如下所示:

void clear_buffer ( short * buffer, int len ) {
    __asm__ (
            "/* clear_buffer */\n\t"
            "LSETUP (1f, 1f) LC0=%1;\n"
            "1:\n\t"
            "W [%0++] = %2;"
            : "+a" ( buffer )
            : "a" ( len ), "d" ( 0 )
            : "memory", "LC0", "LT0", "LB0"
    );
}

当然,这只是一个假设,但您可以反汇编代码并检查 GCC 是否为“%0”和“%2”分配了相同的寄存器。

PS。实际上,只有“+a”就足够了,early-clobber 无关紧要。

于 2012-12-05T15:21:21.577 回答
0

对于遇到类似情况的其他人来说,这里的问题不在于内联程序集,也不在于它的调用方式:它在于程序中的类/结构。我认为是违规者的类不是问题 - 有另一个类持有它的实例,并且由于该外部类的其他成员,内部类没有在单词边界上对齐。这导致了我遇到的“总线错误”。我以前没有遇到过这种情况,因为这些类没有__attribute__((packed))在其他代码中声明,但它们在我的实现中。

提供类型属性 - 使用 GNU 编译器集合 (GCC)阅读实际上激发了我的答案。影响内存对齐的两个特定属性(以及我正在使用的内联汇编)是packedaligned.

取自上述链接:

对齐(对齐)

此属性为指定类型的变量指定最小对齐方式(以字节为单位)。例如,声明:

          struct S { short f[3]; } __attribute__ ((aligned (8)));
          typedef int more_aligned_int __attribute__ ((aligned (8)));

强制编译器确保(尽可能)类型为struct Sor more_aligned_int 的每个变量都被分配并至少在 8 字节边界上对齐。在 SPARC 上,将所有类型的变量struct S对齐到 8 字节边界允许编译器在将一个类型的变量复制到另一个类型的变量时使用lddand (双字加载和存储)指令,从而提高运行时效率。stdstruct S

请注意,ISO C 标准要求任何给定struct或类型的对齐方式至少是orunion的所有成员的对齐方式的最小公倍数的完美倍数。这意味着您可以通过将属性附加到此类类型的任何一个成员来有效地调整 a or类型的对齐方式,但是上面示例中说明的符号是请求编译器的一种更明显、直观和可读的方式调整整个或类型的对齐方式。structunionstructunionalignedstructunion

与前面的示例一样,您可以显式指定希望编译器用于给定structunion类型的对齐方式(以字节为单位)。或者,您可以省略对齐因子,只要求编译器将类型对齐到您正在编译的目标机器的最大有用对齐。例如,您可以编写:

          struct S { short f[3]; } __attribute__ ((aligned));

每当您在对齐的属性规范中省略对齐因子时,编译器会自动将类型的对齐设置为您正在编译的目标机器上的任何数据类型曾经使用过的最大对齐。这样做通常可以使复制操作更有效,因为编译器可以使用任何指令在执行复制到或从具有您以这种方式对齐的类型的变量的变量时复制最大的内存块。

在上面的例子中,如果 each 的大小short是 2 个字节,那么整个struct S类型的大小是 6 个字节。大于或等于 8 的 2 的最小幂是 8,因此编译器将整个struct S类型的对齐设置为 8 个字节。

请注意,尽管您可以要求编译器为给定类型选择一种省时的对齐方式,然后只声明该类型的单个独立对象,但编译器选择一种省时的对齐方式的能力主要仅在您计划创建具有相关(有效对齐)类型的变量数组。如果您声明或使用有效对齐类型的变量数组,那么您的程序很可能还会对指向相关类型的指针以及编译器为这些指针算术运算生成对于有效对齐的类型通常比其他类型更有效。

对齐属性只能增加对齐;但您也可以通过指定打包来减少它。见下文。

请注意,对齐属性的有效性可能会受到链接器固有限制的限制。在许多系统上,链接器只能安排变量对齐到某个最大对齐。(对于某些链接器,支持的最大对齐可能非常小。)如果您的链接器最多只能将变量对齐到 8 字节对齐,那么aligned(16)__attribute__仍然指定的情况下只能为您提供 8 字节对齐。有关详细信息,请参阅您的链接器文档。

.

包装好的

这个属性,附加到structunion类型定义,指定结构或联合的每个成员(除了零宽度位字段)被放置以最小化所需的内存。当附加到enum定义时,它表示应该使用最小的整数类型。

struct为和类型指定此属性union等效于为每个结构或联合成员指定打包属性。-fshort-enums在行上指定标志等效于packed在所有enum定义上指定属性。

在下面的示例struct my_packed_struct中,成员紧密地打包在一起,但其s成员的内部布局没有打包——为此,也struct my_unpacked_struct需要打包。

          struct my_unpacked_struct
           {
              char c;
              int i;
           };

          struct __attribute__ ((__packed__)) my_packed_struct
            {
               char c;
               int  i;
               struct my_unpacked_struct s;
            };

您只能在或的定义上指定此属性enum,而不能在未定义枚举类型、结构或联合的 a 上指定此属性。structuniontypedef

我遇到的问题具体是由于使用packed. 我试图简单地将aligned属性添加到结构和类中,但错误仍然存​​在。只有删除packed属性才能解决问题。现在,我将aligned属性保留在它们上并进行测试,看看我是否发现上面提到的代码效率有任何改进,这仅仅是因为它们在字边界上对齐。应用程序使用了这些结构的数组,因此可能会有更好的性能,但只有分析代码才能确定。

于 2012-12-05T15:49:47.513 回答