ELF:为什么将结构变量放入在64位系统中以32字节对齐的部分

问题描述 投票:1回答:1

代码:

// test.c
#include <stdint.h>

typedef struct cgi
{
        const char *cgi_name;
        void *data;
        uint32_t flags;
} cgi_t;

static cgi_t a, b, c;

编译它:

$ cc -c test.c

readelf

$ readelf -a test.o

     5: 0000000000000000    24 OBJECT  LOCAL  DEFAULT    3 a
     6: 0000000000000020    24 OBJECT  LOCAL  DEFAULT    3 b
     7: 0000000000000040    24 OBJECT  LOCAL  DEFAULT    3 c

太奇怪了,将这3个变量放置为与0x20对齐的地址。此行为使以下代码失败:

extern cgi_t __start_cgicalls, __stop_cgicalls;

cgi_t * lookup_cgi(const char *name) {
    cgi_t *cgi_entry;
    for (cgi_entry = &__start_cgicalls;
        cgi_entry < &__stop_cgicalls; cgi_entry++) {
        if (!strcmp(name, cgi_entry->cgi_name))
            return cgi_entry;
    }   
    return NULL;                                                                                                                                                                                                                 
}

我将注册的cgi条目放在cgi节中,并查看它们,因为它们的位置偏移错误,所以我在程序崩溃时对其进行了查找。

===============

我通过强制将结构对齐到16个字节来修复它。我发现一种材料说,

当一个结构大于16bytes时,该变量将被赋值为16个字节

typedef int (* cgicb_t)(struct http_req *req, struct http_res *res);

/* note: because we look up cgi entry based on array align (8 bytes in 64bits system)
    but the variable may be put in section with different align (big struct is aligned to 16 bytes)
    so, here we force the align to 16 bytes !!!
 */
typedef struct cgi 
{
    const char *cgi_name;
    cgicb_t fn; 
    uint32_t flags;
} __attribute__ ((aligned (16))) cgi_t;

#define REGISTER_CGI(name, cb, flag) \
    static cgi_t __cgicall##cb \
        __attribute__((__section__("cgicalls"))) __attribute__((used)) \
        = { \
            .cgi_name = name, \
            .fn = cb, \
            .flags = flag, \
        } 

#define REG_CGI(cb) REGISTER_CGI(CGI_PATH #cb, cb, CGI_FLAG_PERM)
gcc 64-bit elf
1个回答
0
投票

很奇怪,这3个变量被放置为与0x20对齐的地址

您的问题非常令人困惑,因为它与nothing与任何部分无关。

您的问题似乎是:“ a时为什么bcsizeof(cgi_t) == 24间隔32个字节?”

您对abc.bss部分中彼此遵循的假设是无效。编译器可以按bac或任何其他顺序放置它们,也可以在它们之间放置一些其他数据。

为了使顺序和位置明确定义,您必须声明其中的一个[[array:static cgi_t cgicalls[3];

© www.soinside.com 2019 - 2024. All rights reserved.