summaryrefslogtreecommitdiff
path: root/src/Runtime/__va_arg.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Runtime/__va_arg.c')
-rw-r--r--src/Runtime/__va_arg.c57
1 files changed, 57 insertions, 0 deletions
diff --git a/src/Runtime/__va_arg.c b/src/Runtime/__va_arg.c
new file mode 100644
index 0000000..fd0e182
--- /dev/null
+++ b/src/Runtime/__va_arg.c
@@ -0,0 +1,57 @@
+typedef struct {
+ char gpr;
+ char fpr;
+ char reserved[2];
+ char* input_arg_area;
+ char* reg_save_area;
+} va_list[1];
+
+typedef enum {
+ ARGPOINTER,
+ WORD,
+ DOUBLEWORD,
+ REAL,
+} _va_arg_type;
+
+#define ALIGN(addr, amount) (((unsigned int)(addr) + ((amount)-1)) & ~((amount)-1))
+
+void* __va_arg(va_list ap, _va_arg_type type) {
+ char* addr;
+ char* curGprPtr = &(ap->gpr);
+ int curGpr = ap->gpr;
+ int max = 8;
+ int size = 4;
+ int inc = 1;
+ int even = 0;
+ int fprOffset = 0;
+ int regSize = 4;
+
+ if (type == 3) {
+ curGprPtr = &(ap->fpr);
+ curGpr = ap->fpr;
+ size = 8;
+ fprOffset = 8 * 4;
+ regSize = 8;
+ }
+ if (type == 2) {
+ size = 8;
+ max = max - 1;
+ if (curGpr & 1)
+ even = 1;
+ inc = 2;
+ }
+ if (curGpr < max) {
+ curGpr += even;
+ addr = ap->reg_save_area + fprOffset + (curGpr * regSize);
+ *curGprPtr = curGpr + inc;
+ } else {
+ *curGprPtr = 8;
+ addr = ap->input_arg_area;
+ addr = (char*)ALIGN(addr, size);
+ ap->input_arg_area = addr + size;
+ }
+ if (type == ARGPOINTER)
+ addr = *((char**)addr);
+
+ return addr;
+}