【问题标题】:Find holes in C structs due to alignment由于对齐而在 C 结构中查找孔
【发布时间】:2011-10-06 12:17:00
【问题描述】:

在 gcc 或 clang(或任何其他编译器)中是否有办法吐出有关结构中是否有孔(内存对齐方式)的信息?

谢谢。

ps:如果有其他方法,请告诉我。

【问题讨论】:

  • 有一些已知的编写结构的技术,因此您几乎可以确定它们不包含填充。如果这有帮助,请告诉我,我会为您提供详细信息。

标签: c struct memory-alignment


【解决方案1】:

您可以使用pahole 输出有关结构中孔洞的信息,并可选择尝试打包它们。

您可能想阅读"Poke-a-hole and friends"the pahole announcement 了解更多信息

【讨论】:

  • 谢谢。我想这就是我想要的。
【解决方案2】:

我不知道任何自动工具,但这可能是有用的示例:

#include <stddef.h>

struct test {
  typea a;
  typeb b;
  typec c;
};

int gapB = offsetof(struct test, b) - (offsetof(struct test, a) + sizeof(typea));
int gapC = offsetof(struct test, c) - (offsetof(struct test, b) + sizeof(typeb));

printf("Gap of b:%d/n", gapB);
printf("Gap of c:%d/n", gapC);

*注意:您必须为卡住的每两个成员都这样做。

【讨论】:

    【解决方案3】:

    Gimpel 的 FlexeLint/PClint 可以做到这一点。

    $ cat tst.c
    int main (void)
    {
        struct {
            char c;
            double d;
            short s;
        } f = { 1, 2.0, 3 };
    
        return f.c;
    }
    

    它会报告

    $ flexelint -w1 +e95? tst.c
    FlexeLint for C/C++ (Unix) Vers. 9.00L, Copyright Gimpel Software 1985-2014
    
    --- Module:   tst.c (C)
                    _
            double d;
    tst.c  5  Note 958: Padding of 7 byte(s) is required to align member on 8 byte
        boundary
        _
        } f = { 1, 2.0, 3 };
    tst.c  7  Note 959: Nominal struct size (18 bytes) is not an even multiple of
        the maximum member alignment (8 bytes)
    tst.c  7  Note 958: Padding of 6 byte(s) is required to align end of struct on
        8 byte boundary
    

    【讨论】:

      【解决方案4】:

      您可以通过使用sizeof&amp; 为特定struct 编写探测代码来探索这个问题;如果sizeofn个成员不等于下一个成员的地址减去那个成员的地址,那么就有一个漏洞。

      【讨论】:

        【解决方案5】:

        在不分析源代码和不添加检查(使用 offsetof() 等)的情况下找到此类漏洞的一种方法是使用一些工具从对象/可执行文件/符号文件中提取符号/调试信息,然后查看定义的结构和其中的成员,它们的偏移量和大小,看看是否一切都加起来了。不过,工会会使事情复杂化。

        【讨论】:

        • 所以我想没有编译器开关:)。然而,这是一个有趣的(至少对我而言)主题。如果我想分析目标文件,我应该从哪里开始?
        • @John:首先看看是否有任何工具可以读取符号/调试信息并将其转储为某种人类可读的形式。如果没有,请查看您拥有源代码的哪些工具使用这些数据并在此基础上开发自己的工具。而且,像往常一样,请参阅有关文件格式的文档。
        • 这就是 pahole 等人所做的
        【解决方案6】:

        您可以通过offsetof 宏检测此类“漏洞”:

        #include <stddef.h>
        
        struct test {
          char a;
          int b;
        };
        ...
        printf("%zu", offsetof(struct test, b));
        

        如果打印的次数超过1b 显然有对齐要求,编译器会在两者之间产生间隙。

        显然,这发生在运行时,而不是编译时,但您可以编写一个脚本来生成类似的源文件,在项目的其余部分之前编译并运行它,然后根据输出做出进一步的决定关于如何构建您的项目。

        我认为任何编译器都没有提供通知您这一点的工具。

        【讨论】:

        • 有没有办法自动化这个?
        • 研究结构可能还不够,代码甚至 CFLAGS 中都有对齐选项。你在说多少行代码?结构体是否有可能用于将数据存储在文件中?
        • 我的问题主要是学术性的,但我想测试几百万个 LOC。这些结构大多是 CAD/CAE 对象。
        【解决方案7】:

        您需要一个能够理解 c/c++ 结构并包含必要的包含文件的解析器。

        正如@roee-gavirel 的回答,我认为更简单的解决方案是创建一个测试程序来打印出偏移量

        #include <stdio.h>
        #include <stddef.h>
        
        typedef struct tData {
          long   id;       /* 8 bytes */
          char   name[8];  /* 8 bytes */
          float  salary;   /* 4 bytes */
        } tData;
        
        tData d;
        
        int main()
        {
          size_t s_tData  = sizeof(tData);
          size_t s_id     = sizeof(d.id);
          size_t s_name   = sizeof(d.name);
          size_t s_salary = sizeof(d.salary);
        
          printf("sizeof(tData) = %zu\n\n", sizeof(d));
        
          printf("'id'     is at = %3zu  occupies %zu bytes\n",
                 offsetof(tData, id), s_id);
          printf("'name'   is at = %3zu  occupies %zu bytes\n",
                 offsetof(tData, name), s_name);
          printf("'salary' is at = %3zu  occupies %zu bytes\n",
                 offsetof(tData, salary), s_salary);
        
          printf("\n");
        
          if (s_tData != s_id + s_name + s_salary)
            printf("There is/are holes\n");
        
          return 0;
        }
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2013-07-24
          • 2014-02-19
          • 1970-01-01
          • 2016-02-23
          • 1970-01-01
          • 2012-05-02
          • 1970-01-01
          相关资源
          最近更新 更多