rusi/include/stdarg.h

145 lines
7.4 KiB
C
Raw Permalink Normal View History

// stdarg.h - Макросы для работы с переменным числом аргументов функций
//
// Этот заголовочный файл реализует механизм передачи переменного числа
// аргументов (variadic functions) согласно ABI System V для x86-64.
//
// Структура __va_state отражает внутреннее представление области
// сохранения регистров, создаваемой компилятором для variadic функций.
//
// Поддерживаются как стандартные макросы (va_start, va_arg, va_end, va_copy),
// так и русские синонимы (аргачало, арг_взять, аргонец, аргопия).
#ifndef _STDARG_H_RU
#define _STDARG_H_RU
// ============================================================
// Внутреннее состояние списка аргументов
// ============================================================
// Структура описывает состояние итератора по аргументам variadic функции.
// Она отражает ABI x86-64 System V:
// - gp_offset: смещение в области сохранения регистров общего назначения
// - fp_offset: смещение в области сохранения регистров с плавающей точкой
// - overflow_arg_area: указатель на аргументы, переданные через стек
// - reg_save_area: указатель на область сохранения регистров
typedef struct {
unsigned int gp_offset;
unsigned int fp_offset;
void *overflow_arg_area;
void *reg_save_area;
} __va_state;
// Список аргументов — массив из одного элемента __va_state.
// Такое представление позволяет передавать список по ссылке
// и модифицировать его внутри функций.
typedef __va_state va_list[1];
// ============================================================
// Инициализация и завершение работы с аргументами
// ============================================================
// Инициализация списка аргументов.
// Копирует состояние из специальной области __va_area__,
// которая создаётся компилятором для каждой variadic функции.
#define va_start(ap, last) \
do { *(ap) = *(__va_state *)__va_area__; } while (0)
// Завершение работы со списком аргументов.
// В данной реализации не требует никаких действий.
#define va_end(ap)
// ============================================================
// Внутренние функции извлечения аргументов
// ============================================================
// Извлечение аргумента из области переполнения (переданного через стек).
// Выравнивает указатель согласно требованиям типа и продвигает
// область переполнения вперёд с учётом размера и выравнивания.
static void *__va_read_from_stack(__va_state *ap, int sz, int align) {
void *p = ap->overflow_arg_area;
if (align > 8)
p = (p + 15) / 16 * 16;
ap->overflow_arg_area = ((unsigned long)p + sz + 7) / 8 * 8;
return p;
}
// Извлечение аргумента из области сохранения регистров общего назначения.
// Если регистры общего назначения исчерпаны (gp_offset >= 48),
// переключается на извлечение из стека.
static void *__va_read_from_gp(__va_state *ap, int sz, int align) {
if (ap->gp_offset >= 48)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->gp_offset;
ap->gp_offset += 8;
return r;
}
// Извлечение аргумента из области сохранения регистров с плавающей точкой.
// Если регистры с плавающей точкой исчерпаны (fp_offset >= 112),
// переключается на извлечение из стека.
static void *__va_read_from_fp(__va_state *ap, int sz, int align) {
if (ap->fp_offset >= 112)
return __va_read_from_stack(ap, sz, align);
void *r = ap->reg_save_area + ap->fp_offset;
ap->fp_offset += 8;
return r;
}
// ============================================================
// Извлечение следующего аргумента
// ============================================================
// Извлечение следующего аргумента заданного типа из списка.
// Использует встроенную функцию __builtin_reg_class для определения
// класса регистра (0 - общего назначения, 1 - плавающая точка, 2 - память)
// и вызывает соответствующую функцию извлечения.
#define va_arg(ap, ty) \
({ \
int klass = __builtin_reg_class(ty); \
*(ty *)(klass == 0 ? __va_read_from_gp(ap, sizeof(ty), _Alignof(ty)) : \
klass == 1 ? __va_read_from_fp(ap, sizeof(ty), _Alignof(ty)) : \
__va_read_from_stack(ap, sizeof(ty), _Alignof(ty))); \
})
// ============================================================
// Копирование списка аргументов
// ============================================================
// Копирование состояния списка аргументов.
// Позволяет итерироваться по аргументам независимо в разных местах.
#define va_copy(dest, src) ((dest)[0] = (src)[0])
// ============================================================
// Совместимость с GCC
// ============================================================
// Макрос, указывающий, что va_list совместим с GCC
#define __GNUC_VA_LIST 1
// Альтернативное имя типа для совместимости с GCC
typedef va_list __gnuc_va_list;
// ============================================================
// Русские синонимы для удобства
// ============================================================
// Тип списка аргументов
#define аргументы va_list
// Инициализация списка аргументов
// Пример: аргачало(args, последний);
#define аргачало va_start
// Завершение работы со списком аргументов
#define аргонец va_end
// Извлечение следующего аргумента
// Пример: цел x = арг_взять(args, цел);
#define арг_взять va_arg
// Копирование списка аргументов
#define аргопия va_copy
#endif // _STDARG_H_RU