bool BinOutput::ConvertValueToBytes(Value& value, Location loc, NumericOutput& num_out) { // Binary objects we need to resolve against object, not against section. if (value.isRelative()) { Location label_loc; IntNum ssymval; Expr syme; SymbolRef rel = value.getRelative(); if (rel->isAbsoluteSymbol()) syme = Expr(0); else if (rel->getLabel(&label_loc) && label_loc.bc->getContainer()) syme = Expr(rel); else if (getBinSSymValue(*rel, &ssymval)) syme = Expr(ssymval); else goto done; // Handle PC-relative if (value.getSubLocation(&label_loc) && label_loc.bc->getContainer()) syme -= label_loc; // Add into absolute portion value.AddAbs(syme); value.ClearRelative(); } done: // Simplify absolute portion of value, transforming symrecs if (Expr* abs = value.getAbs()) { BinSimplify(*abs); abs->Simplify(getDiagnostics()); } // Output IntNum intn; m_object.getArch()->setEndian(num_out.getBytes()); if (value.OutputBasic(num_out, &intn, getDiagnostics())) return true; // Couldn't output, assume it contains an external reference. Diag(value.getSource().getBegin(), diag::err_bin_extern_ref); return false; }
// Transforms instances of Symbol-Symbol [Symbol+(-1*Symbol)] into single // ExprTerms if possible. Uses a simple n^2 algorithm because n is usually // quite small. Also works for loc-loc (or Symbol-loc, loc-Symbol). static void TransformDistBase(Expr& e, int pos, const TR1::function<bool (ExprTerm& term, Location loc1, Location loc2)> func) { ExprTerms& terms = e.getTerms(); if (pos < 0) pos += static_cast<int>(terms.size()); ExprTerm& root = terms[pos]; if (!root.isOp(Op::ADD)) return; // Handle symrec-symrec by checking for (-1*symrec) // and symrec term pairs (where both symrecs are in the same // segment). llvm::SmallVector<int, 3> relpos, subpos, subneg1, subroot; // Scan for symrec and (-1*symrec) terms (or location equivalents) int n = pos-1; while (n >= 0) { ExprTerm& child = terms[n]; if (child.isEmpty()) { --n; continue; } if (child.m_depth <= root.m_depth) break; if (child.m_depth != root.m_depth+1) { --n; continue; } // Remember symrec terms if (child.isType(ExprTerm::SYM | ExprTerm::LOC)) { relpos.push_back(pos-n); --n; continue; } int curpos = n; int sym, neg1; // Remember (-1*symrec) terms if (isNeg1Sym(e, &sym, &neg1, &n, true)) { subpos.push_back(pos-sym); subneg1.push_back(pos-neg1); subroot.push_back(pos-curpos); continue; } --n; } // Match additive and subtractive symbols. for (size_t i=0; i<relpos.size(); ++i) { ExprTerm& relterm = terms[pos-relpos[i]]; SymbolRef rel = relterm.getSymbol(); for (size_t j=0; j<subpos.size(); ++j) { if (subpos[j] == 0xff) continue; // previously matched ExprTerm& subterm = terms[pos-subpos[j]]; SymbolRef sub = subterm.getSymbol(); // If it's the same symbol, even if it's external, // they should cancel out. if (rel && rel == sub) { relterm.Zero(); terms[pos-subpos[j]].Clear(); terms[pos-subneg1[j]].Clear(); terms[pos-subroot[j]].Zero(); subpos[j] = 0xff; // mark as matched break; } Location rel_loc; if (rel) { if (!rel->getLabel(&rel_loc)) continue; // external } else if (const Location* loc = relterm.getLocation()) rel_loc = *loc; else assert(false); Location sub_loc; if (sub) { if (!sub->getLabel(&sub_loc)) continue; // external } else if (const Location* loc = subterm.getLocation()) sub_loc = *loc; else assert(false); // If both are in the same segment, we leave them in the // expression but consider them to "match". if (rel_loc.bc->getContainer() != sub_loc.bc->getContainer()) continue; if (func(relterm, sub_loc, rel_loc)) { // Set the matching (-1*Symbol) term to 0 // (will remove from expression during simplify) terms[pos-subpos[j]].Clear(); terms[pos-subneg1[j]].Clear(); terms[pos-subroot[j]].Zero(); subpos[j] = 0xff; // mark as matched break; // stop looking } } } }
void ElfSymbol::Finalize(Symbol& sym, Diagnostic& diags) { // If symbol is a weakrefr, make it weak at this point. if (m_weak_refr) { if (!sym.isDefined() && (sym.getVisibility() & (Symbol::GLOBAL | Symbol::COMMON)) == 0) { if (sym.isUsed()) { setInTable(true); sym.Declare(Symbol::GLOBAL); setBinding(STB_WEAK); } else { setInTable(false); return; } } else if (!sym.isDefined() && (sym.getVisibility() & Symbol::GLOBAL) != 0) { setBinding(STB_GLOBAL); } } // Don't put the LHS of weakrefs into the symbol table unless they're // specifically requested. if (m_weak_ref && (sym.getVisibility() == Symbol::DLOCAL || sym.getVisibility() == Symbol::LOCAL)) { setInTable(false); return; } // If symbol is in a TLS section, force its type to TLS. Location loc; Section* sect; ElfSection* elfsect; if (sym.getLabel(&loc) && (sect = loc.bc->getContainer()->AsSection()) && (elfsect = sect->getAssocData<ElfSection>()) && (elfsect->getFlags() & SHF_TLS)) { m_type = STT_TLS; } // get size (if specified); expr overrides stored integer if (!m_size.isEmpty()) { if (!ExpandEqu(m_size)) { diags.Report(m_size_source, diag::err_equ_circular_reference); return; } SimplifyCalcDist(m_size, diags); if (!m_size.isIntNum()) diags.Report(m_size_source, diag::err_size_integer); } // get EQU value for constants const Expr* equ_expr_c = sym.getEqu(); if (equ_expr_c != 0) { 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()) { m_index = SHN_ABS; m_value = equ_expr.getIntNum(); return; } // 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? Don't gen the symbol. diags.Report(sym.getDefSource(), diag::warn_equ_undef_ref); m_in_table = false; return; } m_sect = loc.bc->getContainer()->AsSection(); m_value = loc.getOffset(); m_value_rel = rel; } else { m_index = SHN_ABS; m_value = 0; } // add in any remaining absolute portion if (Expr* abs = val.getAbs()) { SimplifyCalcDist(*abs, diags); if (!abs->isIntNum()) { diags.Report(sym.getDefSource(), diag::err_equ_not_integer); return; } m_value += abs->getIntNum(); } } }
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()); }