summaryrefslogtreecommitdiff
path: root/scripts/stdincludes/stdarg.h
blob: 73563b4f2369f4c4ae0f145337402683ef118287 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#ifndef _STDARG_H
#define _STDARG_H

typedef struct {
  unsigned int gp_offset; unsigned int fp_offset;
  void *overflow_arg_area; void *reg_save_area;
} __va_elem;
typedef __va_elem va_list;
typedef va_list __builtin_va_list;
typedef va_list __gnuc_va_list;

extern void __builtin_va_start(void *ap, void *last);
#define va_start(ap, last) do { void *_ap = ≈ __builtin_va_start(_ap, last); } while (0)
#define va_end(ap)
static void *__va_arg_mem(__va_elem *ap, int sz, int align) {
  unsigned long 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 (void*)p;
}
static void *__va_arg_gp(__va_elem *ap, int sz, int align) {
  if (ap->gp_offset >= 48)
    return __va_arg_mem(ap, sz, align);

  void *r = ap->reg_save_area + ap->gp_offset;
  ap->gp_offset += 8;
  return r;
}
static void *__va_arg_fp(__va_elem *ap, int sz, int align) {
  if (ap->fp_offset >= 112)
    return __va_arg_mem(ap, sz, align);

  void *r = ap->reg_save_area + ap->fp_offset;
  ap->fp_offset += 8;
  return r;
}
#define va_arg(ap, ty)                                                  \
  ({                                                                    \
    int klass = __builtin_reg_class(ty);                                \
    *(ty *)(klass == 0 ? __va_arg_gp(&ap, sizeof(ty), _Alignof(ty)) :    \
            klass == 1 ? __va_arg_fp(&ap, sizeof(ty), _Alignof(ty)) :    \
            __va_arg_mem(&ap, sizeof(ty), _Alignof(ty)));                \
  })

#endif
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback