У кого-нибудь есть ссылка на представление va_list
в ABI x86_64 (тот, который используется в Linux)? Я пытаюсь отладить некоторый код, где стек или аргументы кажутся коррумпированными, и это действительно поможет понять, что я должен видеть...
Каков формат структуры va_list x86_64?
Ответ 1
Я сделал свой комментарий в ответ.
Это может помочь. Это ссылка, пусть и легкая.
Ссылка на список аргументов Variable начинается на стр. 50, затем она продолжается, стр. 52-53 документы va_list
:
Тип va_list
Тип va_list - это массив содержащий один элемент из одного структура, содержащая необходимые информация для внедрения va_arg макро. Определение C va_list тип приведен на рисунке 3.34
// Figure 3.34
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} va_list[1];
Макрос va_start
Макрос va_start инициализирует структуры следующим образом:
reg_save_area
Элемент указывает на начало области сохранения регистров.
overflow_arg_area
Этот указатель используется для извлечения аргументов, переданных на стек. Он инициализируется адрес первого аргумента, переданного стек, если он есть, а затем всегда обновить, чтобы указать на начало следующий аргумент в стеке.
gp_offset
Элемент содержит смещение в байтах от reg_save_area до место, где следующий доступный общий регистр аргументов назначения сохраняется. В все регистры аргументов были исчерпан, он установлен в значение 48 (6 * 8).
fp_offset
Элемент содержит смещение в байтах от reg_save_area до место, где следующий доступный регистр точечного аргумента сохраняется. В все регистры аргументов были исчерпан, он установлен в значение 304 (6 * 8 + 16 * 16).
Ответ 2
Оказывается, проблема заключалась в том, что gcc создал va_list
тип массива. Моя функция была подписи:
void foo(va_list ap);
и я хотел передать указатель на ap
на другую функцию, поэтому я сделал:
void foo(va_list ap)
{
bar(&ap);
}
К сожалению, типы массивов распадаются на типы указателей в списках аргументов функций, поэтому вместо передачи указателя на исходную структуру я передавал указатель на указатель.
Чтобы обойти проблему, я изменил код на:
void foo(va_list ap)
{
va_list ap2;
va_copy(ap2, ap);
bar(&ap2);
va_end(ap2);
}
Это единственное портативное решение, которое я мог бы придумать, что объясняет как возможность, что va_list
- тип массива, так и возможность того, что это не так.