From ac3227d2995f88758ff73c190c4a933ee91ec1fa Mon Sep 17 00:00:00 2001 From: Ali Gholami Rudi Date: Thu, 3 Jun 2010 18:37:40 +0430 Subject: [PATCH] support initializer for static variables --- gen.c | 53 +++++++++++++++++++++++-------- gen.h | 9 ++++-- ncc.c | 112 +++++++++++++++++++++++++++++++++++++++++++----------------------- out.c | 67 +++++++++++++++++++++++++++++---------- 4 files changed, 169 insertions(+), 72 deletions(-) diff --git a/gen.c b/gen.c index 85963d2..de04c12 100644 --- a/gen.c +++ b/gen.c @@ -68,6 +68,7 @@ static long maxsp; static struct tmp { long addr; + long off; /* used for LOC_SYM; offset from a symbol address */ unsigned flags; unsigned bt; } tmp[MAXTMP]; @@ -267,7 +268,7 @@ static void tmp_reg(struct tmp *tmp, int dst, unsigned bt, int deref) regop1(MOV_I2X, 0, dst, TMP_BT(tmp)); if (!nogen) out_rela(tmp->addr, codeaddr(), 0); - oi(0, 4); + oi(tmp->off, 4); tmp->addr = dst; regs[dst] = tmp; tmp->flags = LOC_NEW(tmp->flags, LOC_REG); @@ -368,6 +369,7 @@ void o_symaddr(long addr, unsigned bt) t->bt = bt; t->addr = addr; t->flags = LOC_SYM | TMP_ADDR; + t->off = 0; } void o_tmpdrop(int n) @@ -501,6 +503,8 @@ static unsigned bt_op(unsigned bt1, unsigned bt2) } #define TMP_CONST(t) ((t)->flags & LOC_NUM && !((t)->flags & TMP_ADDR)) +#define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR)) +#define SYM_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR)) int o_popnum(long *c) { @@ -512,31 +516,40 @@ int o_popnum(long *c) return 0; } -#define LOCAL_PTR(t) ((t)->flags & LOC_LOCAL && !((t)->flags & TMP_ADDR)) - static int c_binop(long (*cop)(long a, long b, unsigned bt), unsigned bt) { struct tmp *t1 = &tmp[ntmp - 1]; struct tmp *t2 = &tmp[ntmp - 2]; int locals = LOCAL_PTR(t1) + LOCAL_PTR(t2); - long ret; - if (!TMP_CONST(t1) && !LOCAL_PTR(t1) || !TMP_CONST(t2) && !LOCAL_PTR(t2)) + int syms = SYM_PTR(t1) + SYM_PTR(t2); + int nums = TMP_CONST(t1) + TMP_CONST(t2); + if (syms == 2 || syms && locals || syms + nums + locals != 2) return 1; if (!bt) { if (!locals) - bt = bt_op(t1->bt, t2->bt); + bt = syms ? 8 : bt_op(t1->bt, t2->bt); if (locals == 1) bt = 8; if (locals == 2) bt = 4 | BT_SIGNED; } - ret = cop(t2->addr, t1->addr, locals ? 4 | BT_SIGNED : bt); - o_tmpdrop(2); - if (locals == 1) { - o_local(-ret, bt); - o_addr(); + if (syms) { + long o1 = SYM_PTR(t1) ? t1->off : t1->addr; + long o2 = SYM_PTR(t2) ? t2->off : t2->addr; + long ret = cop(o2, o1, bt); + if (!SYM_PTR(t2)) + o_tmpswap(); + t2->off = ret; + o_tmpdrop(1); } else { - o_num(ret, bt); + long ret = cop(t2->addr, t1->addr, locals ? 4 | BT_SIGNED : bt); + o_tmpdrop(2); + if (locals == 1) { + o_local(-ret, bt); + o_addr(); + } else { + o_num(ret, bt); + } } return 0; } @@ -1074,7 +1087,7 @@ void o_call(int argc, unsigned *bt, unsigned ret_bt) os("\xe8", 1); /* call $x */ if (!nogen) out_rela(t->addr, codeaddr(), 1); - oi(-4, 4); + oi(-4 + t->off, 4); o_tmpdrop(1); } else { tmp_pop(0, R_RAX); @@ -1093,3 +1106,17 @@ void o_dogen(void) { nogen = 0; } + +void o_datset(long addr, int off, unsigned bt) +{ + struct tmp *t = &tmp[ntmp - 1]; + if (t->flags & LOC_NUM && !(t->flags & TMP_ADDR)) { + num_cast(t, bt); + out_datcpy(addr, off, (void *) &t->addr, BT_SZ(bt)); + } + if (t->flags & LOC_SYM && !(t->flags & TMP_ADDR)) { + out_datrela(tmp->addr, addr, off); + out_datcpy(addr, off, (void *) &t->off, BT_SZ(bt)); + } + o_tmpdrop(1); +} diff --git a/gen.h b/gen.h index 635f9f4..c6a08ba 100644 --- a/gen.h +++ b/gen.h @@ -54,13 +54,11 @@ void o_filljmp(long addr); void o_filljmp2(long addr, long jmpdst); void o_memcpy(int sz); void o_memset(int x, int sz); +void o_datset(long addr, int off, unsigned bt); long o_func_beg(char *name, int global); void o_func_end(void); void o_ret(unsigned bt); -long o_mkvar(char *name, int size, int global); -long o_mkdat(char *name, char *buf, int len, int global); -long o_mkundef(char *name, int sz); int o_nogen(void); void o_dogen(void); @@ -69,4 +67,9 @@ void out_init(void); void out_write(int fd); long out_func_beg(char *name, int global); void out_func_end(char *buf, int len); +long out_mkvar(char *name, int size, int global); +long out_mkdat(char *name, char *buf, int len, int global); +long out_mkundef(char *name, int sz); void out_rela(long addr, int off, int rel); +void out_datcpy(long addr, int off, char *buf, int len); +void out_datrela(long addr, long dataddr, int off); diff --git a/ncc.c b/ncc.c index 99899ec..2b68b49 100644 --- a/ncc.c +++ b/ncc.c @@ -495,7 +495,7 @@ static void readprimary(void) t.flags = 0; ts_push(&t); len = tok_str(buf); - o_symaddr(o_mkdat(NULL, buf, len, 0), TYPE_BT(&t)); + o_symaddr(out_mkdat(NULL, buf, len, 0), TYPE_BT(&t)); o_addr(); return; } @@ -528,7 +528,7 @@ static void readprimary(void) } if (tok_see() != '(') die("unknown symbol\n"); - unkn.addr = o_mkundef(unkn.name, 0); + unkn.addr = out_mkundef(unkn.name, 0); global_add(&unkn); ts_push_bt(8); o_symaddr(unkn.addr, 8); @@ -1107,19 +1107,6 @@ static void readestmt(void) } while (!tok_jmp(',')); } -#define F_GLOBAL(flags) (!((flags) & F_STATIC)) - -static void globaldef(void *data, struct name *name, unsigned flags) -{ - char *varname = flags & F_STATIC ? NULL : name->name; - int sz = type_totsz(&name->type); - if (flags & F_EXTERN) - name->addr = o_mkundef(varname, sz); - else - name->addr = o_mkvar(varname, sz, F_GLOBAL(flags)); - global_add(name); -} - static void o_localoff(long addr, int off, unsigned bt) { o_local(addr, bt); @@ -1138,29 +1125,11 @@ static struct type *innertype(struct type *t) return t; } -static void initexpr(struct type *t, long addr, int off) +static void initexpr(struct type *t, int off, void *obj, + void (*set)(void *obj, int off, struct type *t)) { - if (t->flags & T_ARRAY && tok_see() == TOK_STR) { - struct type *t_de = &arrays[t->id].type; - if (!t_de->ptr && !t_de->flags && TYPE_SZ(t_de) == 1) { - char buf[BUFSIZE]; - int len; - tok_expect(TOK_STR); - len = tok_str(buf); - o_localoff(addr, off, TYPE_BT(t)); - o_symaddr(o_mkdat(NULL, buf, len, 0), TYPE_BT(t)); - o_memcpy(len); - o_tmpdrop(1); - return; - } - } if (tok_jmp('{')) { - o_localoff(addr, off, TYPE_BT(t)); - ts_push(t); - readexpr(); - doassign(); - ts_pop(NULL); - o_tmpdrop(1); + set(obj, off, t); return; } if (!t->ptr && t->flags & T_STRUCT) { @@ -1173,7 +1142,7 @@ static void initexpr(struct type *t, long addr, int off) field = struct_field(t->id, tok_id()); tok_expect('='); } - initexpr(&field->type, addr, off + field->addr); + initexpr(&field->type, off + field->addr, obj, set); if (tok_jmp(',') || tok_see() == '}') break; } @@ -1192,7 +1161,7 @@ static void initexpr(struct type *t, long addr, int off) } if (tok_see() != '{') it = innertype(t_de); - initexpr(it, addr, off + type_totsz(it) * idx); + initexpr(it, off + type_totsz(it) * idx, obj, set); if (tok_jmp(',') || tok_see() == '}') break; } @@ -1241,6 +1210,71 @@ static int initsize(void) return n; } +#define F_GLOBAL(flags) (!((flags) & F_STATIC)) + +static void globalinit(void *obj, int off, struct type *t) +{ + long addr = *(long *) obj; + if (t->flags & T_ARRAY && tok_see() == TOK_STR) { + struct type *t_de = &arrays[t->id].type; + if (!t_de->ptr && !t_de->flags && TYPE_SZ(t_de) == 1) { + char buf[BUFSIZE]; + int len; + tok_expect(TOK_STR); + len = tok_str(buf); + out_datcpy(addr, off, buf, len); + return; + } + } + readexpr(); + o_datset(addr, off, TYPE_BT(t)); + ts_pop(NULL); +} + +static void globaldef(void *data, struct name *name, unsigned flags) +{ + struct type *t = &name->type; + char *varname = flags & F_STATIC ? NULL : name->name; + int sz; + if (t->flags & T_ARRAY && !t->ptr && !arrays[t->id].n) + arrays[t->id].n = initsize(); + sz = type_totsz(t); + if (flags & F_EXTERN) + name->addr = out_mkundef(varname, sz); + else if (flags & F_INIT) + name->addr = out_mkdat(varname, NULL, sz, F_GLOBAL(flags)); + else + name->addr = out_mkvar(varname, sz, F_GLOBAL(flags)); + global_add(name); + if (flags & F_INIT) + initexpr(t, 0, &name->addr, globalinit); +} + +static void localinit(void *obj, int off, struct type *t) +{ + long addr = *(long *) obj; + if (t->flags & T_ARRAY && tok_see() == TOK_STR) { + struct type *t_de = &arrays[t->id].type; + if (!t_de->ptr && !t_de->flags && TYPE_SZ(t_de) == 1) { + char buf[BUFSIZE]; + int len; + tok_expect(TOK_STR); + len = tok_str(buf); + o_localoff(addr, off, TYPE_BT(t)); + o_symaddr(out_mkdat(NULL, buf, len, 0), TYPE_BT(t)); + o_memcpy(len); + o_tmpdrop(1); + return; + } + } + o_localoff(addr, off, TYPE_BT(t)); + ts_push(t); + readexpr(); + doassign(); + ts_pop(NULL); + o_tmpdrop(1); +} + static void localdef(void *data, struct name *name, unsigned flags) { struct type *t = &name->type; @@ -1258,7 +1292,7 @@ static void localdef(void *data, struct name *name, unsigned flags) o_memset(0, type_totsz(t)); o_tmpdrop(1); } - initexpr(t, name->addr, 0); + initexpr(t, 0, &name->addr, localinit); } } diff --git a/out.c b/out.c index 9da7665..3b9d2d6 100644 --- a/out.c +++ b/out.c @@ -5,14 +5,15 @@ #define ALIGN(x, a) (((x) + (a) - 1) & ~((a) - 1)) -#define MAXSECS (1 << 7) -#define MAXSYMS (1 << 10) -#define MAXRELA (1 << 10) +#define MAXSECS (1 << 10) +#define MAXSYMS (1 << 12) +#define MAXRELA (1 << 12) #define SEC_SYMS 1 #define SEC_SYMSTR 2 #define SEC_DAT 3 -#define SEC_BSS 4 -#define SEC_BEG 5 +#define SEC_DATRELA 4 +#define SEC_BSS 5 +#define SEC_BEG 6 static Elf64_Ehdr ehdr; static Elf64_Shdr shdr[MAXSECS]; @@ -24,6 +25,8 @@ static int nsymstr = 1; static int bsslen; static char dat[SECSIZE]; static int datlen; +static Elf64_Rela datrela[MAXRELA]; +static int ndatrela; static struct sec { char buf[SECSIZE]; @@ -96,8 +99,25 @@ void out_rela(long addr, int off, int rel) rela->r_info = ELF64_R_INFO(addr, rel ? R_X86_64_PC32 : R_X86_64_32); } +void out_datrela(long addr, long dataddr, int off) +{ + Elf64_Rela *rela = &datrela[ndatrela++]; + rela->r_offset = syms[dataddr].st_value + off; + rela->r_info = ELF64_R_INFO(addr, R_X86_64_32); +} + #define SYMLOCAL(i) (ELF64_ST_BIND(syms[i].st_info) & STB_LOCAL) +static void mvrela(int *mv, Elf64_Rela *rela, int nrela) +{ + int i; + for (i = 0; i < nrela; i++) { + int sym = ELF64_R_SYM(rela[i].r_info); + int type = ELF64_R_TYPE(rela[i].r_info); + rela[i].r_info = ELF64_R_INFO(mv[sym], type); + } +} + static int syms_sort(void) { int mv[MAXSYMS]; @@ -122,14 +142,9 @@ static int syms_sort(void) mv[j] = i; } glob_beg = i; - for (i = 0; i < nsecs; i++) { - for (j = 0; j < secs[i].nrela; i++) { - Elf64_Rela *rela = &sec[i].rela[j]; - int sym = ELF64_R_SYM(rela->r_info); - int type = ELF64_R_TYPE(rela->r_info); - rela->r_info = ELF64_R_INFO(mv[sym], type); - } - } + for (i = 0; i < nsecs; i++) + mvrela(mv, sec[i].rela, sec[i].nrela); + mvrela(mv, datrela, ndatrela); return glob_beg; } @@ -138,6 +153,7 @@ void out_write(int fd) Elf64_Shdr *symstr_shdr = &shdr[SEC_SYMSTR]; Elf64_Shdr *syms_shdr = &shdr[SEC_SYMS]; Elf64_Shdr *dat_shdr = &shdr[SEC_DAT]; + Elf64_Shdr *datrela_shdr = &shdr[SEC_DATRELA]; Elf64_Shdr *bss_shdr = &shdr[SEC_BSS]; unsigned long offset = sizeof(ehdr); int i; @@ -175,6 +191,14 @@ void out_write(int fd) dat_shdr->sh_addralign = 8; offset += dat_shdr->sh_size; + datrela_shdr->sh_type = SHT_RELA; + datrela_shdr->sh_offset = offset; + datrela_shdr->sh_size = ndatrela * sizeof(datrela[0]); + datrela_shdr->sh_entsize = sizeof(datrela[0]); + datrela_shdr->sh_link = SEC_SYMS; + datrela_shdr->sh_info = SEC_DAT; + offset += datrela_shdr->sh_size; + bss_shdr->sh_type = SHT_NOBITS; bss_shdr->sh_flags = SHF_ALLOC | SHF_WRITE; bss_shdr->sh_offset = offset; @@ -209,6 +233,7 @@ void out_write(int fd) write(fd, shdr, sizeof(shdr[0]) * nshdr); write(fd, syms, sizeof(syms[0]) * nsyms); write(fd, dat, datlen); + write(fd, datrela, ndatrela * sizeof(datrela[0])); write(fd, symstr, nsymstr); for (i = 0; i < nsecs; i++) { struct sec *sec = &secs[i]; @@ -217,7 +242,7 @@ void out_write(int fd) } } -long o_mkvar(char *name, int size, int global) +long out_mkvar(char *name, int size, int global) { Elf64_Sym *sym = put_sym(name); sym->st_shndx = SEC_BSS; @@ -228,7 +253,7 @@ long o_mkvar(char *name, int size, int global) return sym - syms; } -long o_mkundef(char *name, int sz) +long out_mkundef(char *name, int sz) { Elf64_Sym *sym = put_sym(name); sym->st_shndx = SHN_UNDEF; @@ -237,14 +262,22 @@ long o_mkundef(char *name, int sz) return sym - syms; } -long o_mkdat(char *name, char *buf, int len, int global) +long out_mkdat(char *name, char *buf, int len, int global) { Elf64_Sym *sym = put_sym(name); sym->st_shndx = SEC_DAT; sym->st_value = datlen; sym->st_size = len; sym->st_info = ELF64_ST_INFO(S_BIND(global), STT_OBJECT); - memcpy(dat + datlen, buf, len); + if (buf) + memcpy(dat + datlen, buf, len); + else + memset(dat + datlen, 0, len); datlen = ALIGN(datlen + len, 8); return sym - syms; } + +void out_datcpy(long addr, int off, char *buf, int len) +{ + memcpy(dat + syms[addr].st_value + off, buf, len); +} -- 2.11.4.GIT