void CoffSymbol::Write(Bytes& bytes, const Symbol& sym, DiagnosticsEngine& diags, StringTable& strtab) const { int vis = sym.getVisibility(); IntNum value = 0; unsigned int scnum = 0xfffe; // -2 = debugging symbol unsigned long scnlen = 0; // for sect auxent unsigned long nreloc = 0; // for sect auxent // Look at symrec for value/scnum/etc. Location loc; if (sym.getLabel(&loc)) { Section* sect = 0; if (loc.bc) sect = loc.bc->getContainer()->getSection(); // it's a label: get value and offset. // If there is not a section, leave as debugging symbol. if (sect) { CoffSection* coffsect = sect->getAssocData<CoffSection>(); assert(coffsect != 0); scnum = coffsect->m_scnum; scnlen = coffsect->m_size; nreloc = sect->getRelocs().size(); value = sect->getVMA(); if (loc.bc) value += loc.getOffset(); } } else if (const Expr* equ_expr_c = sym.getEqu()) { Expr equ_expr = *equ_expr_c; if (!ExpandEqu(equ_expr)) { diags.Report(sym.getDefSource(), diag::err_equ_circular_reference); return; } SimplifyCalcDist(equ_expr, diags); // trivial case: simple integer if (equ_expr.isIntNum()) { scnum = 0xffff; // -1 = absolute symbol value = equ_expr.getIntNum(); } else { // otherwise might contain relocatable value (e.g. symbol alias) std::auto_ptr<Expr> equ_expr_p(new Expr); equ_expr_p->swap(equ_expr); Value val(64, equ_expr_p); val.setSource(sym.getDefSource()); if (!val.Finalize(diags, diag::err_equ_too_complex)) return; if (val.isComplexRelative()) { diags.Report(sym.getDefSource(), diag::err_equ_too_complex); return; } // set section appropriately based on if value is relative if (val.isRelative()) { SymbolRef rel = val.getRelative(); Location loc; if (!rel->getLabel(&loc) || !loc.bc) { // Referencing an undefined label? // GNU as silently allows this... but doesn't gen the symbol? // We make it an error instead. diags.Report(sym.getDefSource(), diag::err_equ_too_complex); return; } Section* sect = loc.bc->getContainer()->getSection(); CoffSection* coffsect = sect->getAssocData<CoffSection>(); assert(coffsect != 0); scnum = coffsect->m_scnum; value = sect->getVMA() + loc.getOffset(); } else { scnum = 0xffff; // -1 = absolute symbol value = 0; } // add in any remaining absolute portion if (Expr* abs = val.getAbs()) { SimplifyCalcDist(*abs, diags); if (abs->isIntNum()) value += abs->getIntNum(); else diags.Report(sym.getDefSource(), diag::err_equ_not_integer); } } } else { if (vis & Symbol::COMMON) { assert(getCommonSize(sym) != 0); Expr csize(*getCommonSize(sym)); SimplifyCalcDist(csize, diags); if (csize.isIntNum()) value = csize.getIntNum(); else { diags.Report(sym.getDefSource(), diag::err_common_size_not_integer); } scnum = 0; } if (vis & Symbol::EXTERN) scnum = 0; } bytes.setLittleEndian(); StringRef name; if (sym.isAbsoluteSymbol()) name = ".absolut"; else name = sym.getName(); size_t len = name.size(); if (len > 8) { Write32(bytes, 0); // "zeros" field Write32(bytes, strtab.getIndex(name)); // strtab offset } else { // <8 chars, so no string table entry needed bytes.WriteString(name); bytes.Write(8-len, 0); } Write32(bytes, value); // value Write16(bytes, scnum); // section number Write16(bytes, m_type); // type Write8(bytes, m_sclass); // storage class Write8(bytes, m_aux.size()); // number of aux entries assert(bytes.size() == 18); for (std::vector<AuxEntry>::const_iterator i=m_aux.begin(), end=m_aux.end(); i != end; ++i) { switch (m_auxtype) { case AUX_NONE: bytes.Write(18, 0); break; case AUX_SECT: Write32(bytes, scnlen); // section length Write16(bytes, nreloc); // number relocs bytes.Write(12, 0); // number line nums, 0 fill break; case AUX_FILE: len = i->fname.length(); if (len > 18) { Write32(bytes, 0); Write32(bytes, strtab.getIndex(i->fname)); bytes.Write(18-8, 0); } else { bytes.WriteString(i->fname); bytes.Write(18-len, 0); } break; default: assert(false); // unrecognized aux symtab type } } assert(bytes.size() == 18+18*m_aux.size()); }