ELF: почему переменная структуры помещается в раздел с 32 байтами, выровненными в 64-битной системе - PullRequest
1 голос
/ 29 февраля 2020

Код:

// 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 байтов. Я обнаружил, что материал говорит, что

, когда структура больше 16 байтов, переменная будет преобразована в 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)

1 Ответ

2 голосов
/ 29 февраля 2020

так странно, эти 3 переменные расположены по адресу, выровненному по 0x20

Ваш вопрос очень запутанный, потому что он не имеет ничего общего с .

Ваш вопрос, по-видимому: «почему a, b и c разнесены на 32 байта, когда sizeof(cgi_t) == 24?».

Ваше предположение, что a, b и c следуют друг за другом в разделе .bss: недействительно . Компилятор может разместить их в b, a, c или любом другом порядке, или он может поместить некоторые другие данные между ними.

Чтобы сделать порядок и размещение четко определенными, вы должен объявить массив из них: static cgi_t cgicalls[3];.

...