void unittest_LEB128() { Outbuffer buf; static int values[] = { 0,1,2,3,300,4000,50000,600000, -0,-1,-2,-3,-300,-4000,-50000,-600000, }; for (size_t i = 0; i < sizeof(values)/sizeof(values[0]); ++i) { const int value = values[i]; buf.reset(); buf.writeuLEB128(value); assert(buf.size() == uLEB128size(value)); unsigned char *p = buf.buf; int result = uLEB128(&p); assert(p == buf.p); assert(result == value); buf.reset(); buf.writesLEB128(value); assert(buf.size() == sLEB128size(value)); p = buf.buf; result = sLEB128(&p); assert(p == buf.p); assert(result == value); } }
void unittest_actionTableInsert() { Outbuffer atbuf; static int tt1[] = { 1,2,3 }; static int tt2[] = { 2 }; int offset = -1; for (size_t i = sizeof(tt1)/sizeof(tt1[0]); i--; ) { offset = actionTableInsert(&atbuf, tt1[i], offset); } offset = -1; for (size_t i = sizeof(tt2)/sizeof(tt2[0]); i--; ) { offset = actionTableInsert(&atbuf, tt2[i], offset); } static unsigned char result[] = { 3,0,2,0x7D,1,0x7D,2,0 }; //for (int i = 0; i < atbuf.size(); ++i) printf(" %02x\n", atbuf.buf[i]); assert(sizeof(result) == atbuf.size()); int r = memcmp(result, atbuf.buf, atbuf.size()); assert(r == 0); }
/****************************************** * write lexical scope records up to the line where the symbol sa is created * if sa == NULL, flush all remaining records */ void cv8_writeLexicalScope(Funcsym *s, symbol *sa, VarStatistics* vs) { if (vs->cntUsedVarStats == 0) return; unsigned line; if(sa) { line = sa->lnoscopestart + 1; } else { // flush all line = vs->firstVarStatsLine + vs->cntUsedVarStats; } while (vs->nextVarStatsLine < line && vs->nextVarStatsLine < vs->firstVarStatsLine + vs->cntUsedVarStats) { Outbuffer *buf = currentfuncdata.f1buf; unsigned idx = vs->nextVarStatsLine - vs->firstVarStatsLine; for(int d = 0; d < vs->varStats[idx].numDel; d++) { static unsigned short s_end[] = { 2, S_END }; buf->write(s_end, sizeof(s_end)); } for(int n = 0; n < vs->varStats[idx].numNew; n++) { unsigned offset = vs->varStats[idx].offset; unsigned length = vs->varStats[vs->varStats[idx].endLine - vs->firstVarStatsLine].offset - offset; unsigned soffset = buf->size(); // parent and end to be filled by linker block_v3_data block32 = { sizeof(block_v3_data) - 2, S_BLOCK_V3, 0, 0, length, offset, 0, { 0 } }; buf->write(&block32, sizeof(block32)); size_t offOffset = (char*)&block32.offset - (char*)&block32; F1_Fixups f1f; f1f.s = s; f1f.offset = soffset + offOffset; f1f.value = offset; currentfuncdata.f1fixup->write(&f1f, sizeof(f1f)); } vs->nextVarStatsLine++; } }
void obj_start(char *srcfile) { //printf("obj_start()\n"); rtlsym_reset(); clearStringTab(); #if TARGET_WINDOS // Produce Ms COFF files for 64 bit code, OMF for 32 bit code assert(objbuf.size() == 0); objmod = global.params.mscoff ? MsCoffObj::init(&objbuf, srcfile, NULL) : Obj::init(&objbuf, srcfile, NULL); #else objmod = Obj::init(&objbuf, srcfile, NULL); #endif el_reset(); cg87_reset(); out_reset(); }
void cv8_outsym(Symbol *s) { //printf("cv8_outsym(s = '%s')\n", s->Sident); //type_print(s->Stype); //symbol_print(s); if (s->Sflags & SFLnodebug) return; idx_t typidx = cv_typidx(s->Stype); //printf("typidx = %x\n", typidx); const char *id = s->prettyIdent ? s->prettyIdent : prettyident(s); size_t len = strlen(id); if(len > CV8_MAX_SYMBOL_LENGTH) len = CV8_MAX_SYMBOL_LENGTH; F1_Fixups f1f; Outbuffer *buf = currentfuncdata.f1buf; unsigned sr; unsigned base; switch (s->Sclass) { case SCparameter: case SCregpar: case SCshadowreg: if (s->Sfl == FLreg) { s->Sfl = FLpara; cv8_outsym(s); s->Sfl = FLreg; goto case_register; } base = Para.size - BPoff; // cancel out add of BPoff goto L1; case SCauto: if (s->Sfl == FLreg) goto case_register; case_auto: base = Auto.size; L1: #if 1 // Register relative addressing buf->reserve(2 + 2 + 4 + 4 + 2 + len + 1); buf->writeWordn( 2 + 4 + 4 + 2 + len + 1); buf->writeWordn(0x1111); buf->write32(s->Soffset + base + BPoff); buf->write32(typidx); buf->writeWordn(I64 ? 334 : 22); // relative to RBP/EBP cv8_writename(buf, id, len); buf->writeByte(0); #else // This is supposed to work, implicit BP relative addressing, but it does not buf->reserve(2 + 2 + 4 + 4 + len + 1); buf->writeWordn( 2 + 4 + 4 + len + 1); buf->writeWordn(S_BPREL_V3); buf->write32(s->Soffset + base + BPoff); buf->write32(typidx); cv8_writename(buf, id, len); buf->writeByte(0); #endif break; case SCbprel: base = -BPoff; goto L1; case SCfastpar: if (s->Sfl != FLreg) { base = Fast.size; goto L1; } goto L2; case SCregister: if (s->Sfl != FLreg) goto case_auto; case SCpseudo: case_register: L2: buf->reserve(2 + 2 + 4 + 2 + len + 1); buf->writeWordn( 2 + 4 + 2 + len + 1); buf->writeWordn(S_REGISTER_V3); buf->write32(typidx); buf->writeWordn(cv8_regnum(s)); cv8_writename(buf, id, len); buf->writeByte(0); break; case SCextern: break; case SCstatic: case SClocstat: sr = S_LDATA_V3; goto Ldata; case SCglobal: case SCcomdat: case SCcomdef: sr = S_GDATA_V3; Ldata: //return; /* * 2 length (not including these 2 bytes) * 2 S_GDATA_V2 * 4 typidx * 6 ref to symbol * n 0 terminated name string */ if (s->ty() & mTYthread) // thread local storage sr = (sr == S_GDATA_V3) ? 0x1113 : 0x1112; buf->reserve(2 + 2 + 4 + 6 + len + 1); buf->writeWordn(2 + 4 + 6 + len + 1); buf->writeWordn(sr); buf->write32(typidx); f1f.s = s; f1f.offset = buf->size(); F1fixup->write(&f1f, sizeof(f1f)); buf->write32(0); buf->writeWordn(0); cv8_writename(buf, id, len); buf->writeByte(0); break; default: break; } }
void cv8_func_term(Symbol *sfunc) { //printf("cv8_func_term(%s)\n", sfunc->Sident); assert(currentfuncdata.sfunc == sfunc); currentfuncdata.section_length = retoffset + retsize; funcdata->write(¤tfuncdata, sizeof(currentfuncdata)); // Write function symbol assert(tyfunc(sfunc->ty())); idx_t typidx; func_t* fn = sfunc->Sfunc; if(fn->Fclass) { // generate member function type info // it would be nicer if this could be in cv4_typidx, but the function info is not available there unsigned nparam; unsigned char call = cv4_callconv(sfunc->Stype); idx_t paramidx = cv4_arglist(sfunc->Stype,&nparam); unsigned next = cv4_typidx(sfunc->Stype->Tnext); type* classtype = (type*)fn->Fclass; unsigned classidx = cv4_typidx(classtype); type *tp = type_allocn(TYnptr, classtype); unsigned thisidx = cv4_typidx(tp); // TODO debtyp_t *d = debtyp_alloc(2 + 4 + 4 + 4 + 1 + 1 + 2 + 4 + 4); TOWORD(d->data,LF_MFUNCTION_V2); TOLONG(d->data + 2,next); // return type TOLONG(d->data + 6,classidx); // class type TOLONG(d->data + 10,thisidx); // this type d->data[14] = call; d->data[15] = 0; // reserved TOWORD(d->data + 16,nparam); TOLONG(d->data + 18,paramidx); TOLONG(d->data + 22,0); // this adjust typidx = cv_debtyp(d); } else typidx = cv_typidx(sfunc->Stype); const char *id = sfunc->prettyIdent ? sfunc->prettyIdent : prettyident(sfunc); size_t len = strlen(id); if(len > CV8_MAX_SYMBOL_LENGTH) len = CV8_MAX_SYMBOL_LENGTH; /* * 2 length (not including these 2 bytes) * 2 S_GPROC_V3 * 4 parent * 4 pend * 4 pnext * 4 size of function * 4 size of function prolog * 4 offset to function epilog * 4 type index * 6 seg:offset of function start * 1 flags * n 0 terminated name string */ Outbuffer *buf = currentfuncdata.f1buf; buf->reserve(2 + 2 + 4 * 7 + 6 + 1 + len + 1); buf->writeWordn( 2 + 4 * 7 + 6 + 1 + len + 1); buf->writeWordn(sfunc->Sclass == SCstatic ? S_LPROC_V3 : S_GPROC_V3); buf->write32(0); // parent buf->write32(0); // pend buf->write32(0); // pnext buf->write32(currentfuncdata.section_length); // size of function buf->write32(startoffset); // size of prolog buf->write32(retoffset); // offset to epilog buf->write32(typidx); F1_Fixups f1f; f1f.s = sfunc; f1f.offset = buf->size(); currentfuncdata.f1fixup->write(&f1f, sizeof(f1f)); buf->write32(0); buf->writeWordn(0); buf->writeByte(0); buf->writen(id, len); buf->writeByte(0); // Write local symbol table bool endarg = false; for (SYMIDX si = 0; si < globsym.top; si++) { //printf("globsym.tab[%d] = %p\n",si,globsym.tab[si]); symbol *sa = globsym.tab[si]; if (endarg == false && sa->Sclass != SCparameter && sa->Sclass != SCfastpar && sa->Sclass != SCshadowreg) { buf->writeWord(2); buf->writeWord(S_ENDARG); endarg = true; } cv8_outsym(sa); } /* Put out function return record S_RETURN * (VC doesn't, so we won't bother, either.) */ // Write function end symbol buf->writeWord(2); buf->writeWord(S_END); currentfuncdata.f1buf = F1_buf; currentfuncdata.f1fixup = F1fixup; }
void genDwarfEh(Funcsym *sfunc, int seg, Outbuffer *et, bool scancode, unsigned startoffset, unsigned retoffset) { #ifdef DEBUG unittest_dwarfeh(); #endif /* LPstart = encoding of LPbase * LPbase = landing pad base (normally omitted) * TType = encoding of TTbase * TTbase = offset from next byte to past end of Type Table * CallSiteFormat = encoding of fields in Call Site Table * CallSiteTableSize = size in bytes of Call Site Table * Call Site Table[]: * CallSiteStart * CallSiteRange * LandingPad * ActionRecordPtr * Action Table * TypeFilter * NextRecordPtr * Type Table */ et->reserve(100); block *startblock = sfunc->Sfunc->Fstartblock; //printf("genDwarfEh: func = %s, offset = x%x, startblock->Boffset = x%x, scancode = %d startoffset=x%x, retoffset=x%x\n", //sfunc->Sident, (int)sfunc->Soffset, (int)startblock->Boffset, scancode, startoffset, retoffset); #if 0 printf("------- before ----------\n"); for (block *b = startblock; b; b = b->Bnext) WRblock(b); printf("-------------------------\n"); #endif unsigned startsize = et->size(); assert((startsize & 3) == 0); // should be aligned DwEhTable *deh = &dwehtable; deh->dim = 0; Outbuffer atbuf; Outbuffer cstbuf; /* Build deh table, and Action Table */ int index = -1; block *bprev = NULL; // The first entry encompasses the entire function { unsigned i = deh->push(); DwEhTableEntry *d = deh->index(i); d->start = startblock->Boffset + startoffset; d->end = startblock->Boffset + retoffset; d->lpad = 0; // no cleanup, no catches index = i; } for (block *b = startblock; b; b = b->Bnext) { if (index > 0 && b->Btry == bprev) { DwEhTableEntry *d = deh->index(index); d->end = b->Boffset; index = d->prev; if (bprev) bprev = bprev->Btry; } if (b->BC == BC_try) { unsigned i = deh->push(); DwEhTableEntry *d = deh->index(i); d->start = b->Boffset; block *bf = b->nthSucc(1); if (bf->BC == BCjcatch) { d->lpad = bf->Boffset; d->bcatch = bf; unsigned *pat = bf->BS.BIJCATCH.actionTable; unsigned length = pat[0]; assert(length); unsigned offset = -1; for (unsigned u = length; u; --u) { /* Buy doing depth-first insertion into the Action Table, * we can combine common tails. */ offset = actionTableInsert(&atbuf, pat[u], offset); } d->action = offset + 1; } else d->lpad = bf->nthSucc(0)->Boffset; d->prev = index; index = i; bprev = b->Btry; } if (scancode) { unsigned coffset = b->Boffset; int n = 0; for (code *c = b->Bcode; c; c = code_next(c)) { if (c->Iop == (ESCAPE | ESCdctor)) { unsigned i = deh->push(); DwEhTableEntry *d = deh->index(i); d->start = coffset; d->prev = index; index = i; ++n; } if (c->Iop == (ESCAPE | ESCddtor)) { assert(n > 0); --n; DwEhTableEntry *d = deh->index(index); d->end = coffset; d->lpad = coffset; index = d->prev; } coffset += calccodsize(c); } assert(n == 0); } } //printf("deh->dim = %d\n", (int)deh->dim); #if 1 /* Build Call Site Table * Be sure to not generate empty entries, * and generate nested ranges reflecting the layout in the code. */ assert(deh->dim); unsigned end = deh->index(0)->start; for (unsigned i = 0; i < deh->dim; ++i) { DwEhTableEntry *d = deh->index(i); if (d->start < d->end) { #if ELFOBJ #define WRITE writeuLEB128 #elif MACHOBJ #define WRITE write32 #else assert(0); #endif unsigned CallSiteStart = d->start - startblock->Boffset; cstbuf.WRITE(CallSiteStart); unsigned CallSiteRange = d->end - d->start; cstbuf.WRITE(CallSiteRange); unsigned LandingPad = d->lpad ? d->lpad - startblock->Boffset : 0; cstbuf.WRITE(LandingPad); unsigned ActionTable = d->action; cstbuf.writeuLEB128(ActionTable); //printf("\t%x %x %x %x\n", CallSiteStart, CallSiteRange, LandingPad, ActionTable); #undef WRITE } } #else /* Build Call Site Table * Be sure to not generate empty entries, * and generate multiple entries for one DwEhTableEntry if the latter * is split by nested DwEhTableEntry's. This is based on the (undocumented) * presumption that there may not * be overlapping entries in the Call Site Table. */ assert(deh->dim); unsigned end = deh->index(0)->start; for (unsigned i = 0; i < deh->dim; ++i) { unsigned j = i; do { DwEhTableEntry *d = deh->index(j); //printf(" [%d] start=%x end=%x lpad=%x action=%x bcatch=%p prev=%d\n", // j, d->start, d->end, d->lpad, d->action, d->bcatch, d->prev); if (d->start <= end && end < d->end) { unsigned start = end; unsigned dend = d->end; if (i + 1 < deh->dim) { DwEhTableEntry *dnext = deh->index(i + 1); if (dnext->start < dend) dend = dnext->start; } if (start < dend) { #if ELFOBJ #define WRITE writeLEB128 #elif MACHOBJ #define WRITE write32 #else assert(0); #endif unsigned CallSiteStart = start - startblock->Boffset; cstbuf.WRITE(CallSiteStart); unsigned CallSiteRange = dend - start; cstbuf.WRITE(CallSiteRange); unsigned LandingPad = d->lpad - startblock->Boffset; cstbuf.WRITE(LandingPad); unsigned ActionTable = d->action; cstbuf.WRITE(ActionTable); //printf("\t%x %x %x %x\n", CallSiteStart, CallSiteRange, LandingPad, ActionTable); #undef WRITE } end = dend; } } while (j--); } #endif /* Write LSDT header */ const unsigned char LPstart = DW_EH_PE_omit; et->writeByte(LPstart); unsigned LPbase = 0; if (LPstart != DW_EH_PE_omit) et->writeuLEB128(LPbase); const unsigned char TType = (config.flags3 & CFG3pic) ? DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4 : DW_EH_PE_absptr | DW_EH_PE_udata4; et->writeByte(TType); /* Compute TTbase, which is the sum of: * 1. CallSiteFormat * 2. encoding of CallSiteTableSize * 3. Call Site Table size * 4. Action Table size * 5. 4 byte alignment * 6. Types Table * Iterate until it converges. */ unsigned TTbase = 1; unsigned CallSiteTableSize = cstbuf.size(); unsigned oldTTbase; do { oldTTbase = TTbase; unsigned start = (et->size() - startsize) + uLEB128size(TTbase); TTbase = 1 + uLEB128size(CallSiteTableSize) + CallSiteTableSize + atbuf.size(); unsigned sz = start + TTbase; TTbase += -sz & 3; // align to 4 TTbase += sfunc->Sfunc->typesTableDim * 4; } while (TTbase != oldTTbase); if (TType != DW_EH_PE_omit) et->writeuLEB128(TTbase); unsigned TToffset = TTbase + et->size() - startsize; #if ELFOBJ const unsigned char CallSiteFormat = DW_EH_PE_absptr | DW_EH_PE_uleb128; #elif MACHOBJ const unsigned char CallSiteFormat = DW_EH_PE_absptr | DW_EH_PE_udata4; #else assert(0); #endif et->writeByte(CallSiteFormat); et->writeuLEB128(CallSiteTableSize); /* Insert Call Site Table */ et->write(&cstbuf); /* Insert Action Table */ et->write(&atbuf); /* Align to 4 */ for (unsigned n = (-et->size() & 3); n; --n) et->writeByte(0); /* Write out Types Table in reverse */ Symbol **typesTable = sfunc->Sfunc->typesTable; for (int i = sfunc->Sfunc->typesTableDim; i--; ) { Symbol *s = typesTable[i]; /* MACHOBJ 64: pcrel 1 length 1 extern 1 RELOC_GOT * 32: [0] address x004c pcrel 0 length 2 value x224 type 4 RELOC_LOCAL_SECTDIFF * [1] address x0000 pcrel 0 length 2 value x160 type 1 RELOC_PAIR */ dwarf_reftoident(seg, et->size(), s, 0); } assert(TToffset == et->size() - startsize); }