[llvm-commits] [PATCH 4/5] Add ELF ObjectWriter and Streamer support.
Eli Friedman
eli.friedman at gmail.com
Mon Jul 26 14:36:35 PDT 2010
On Mon, Jul 26, 2010 at 1:00 PM, Matt Fleming <matt at console-pimps.org> wrote:
+// Because all the symbol flags need to be stored in the MCSymbolData
+// 'flags' variable we need to provide shift constants per flag type.
+enum {
+ STT_SHIFT = 0, // Shift value for STT_* flags.
+ STB_SHIFT = 4, // Shift value for STB_* flags.
+ STV_SHIFT = 8 // Shift value ofr STV_* flags.
+};
I don't think this belongs in ELF.h; it seems specific to the MC implementation.
> + static bool isFixupKindPCRel(unsigned Kind) {
> + switch (Kind) {
> + default:
> + return false;
> + case X86::reloc_pcrel_1byte:
> + case X86::reloc_pcrel_4byte:
> + case X86::reloc_riprel_4byte:
> + case X86::reloc_riprel_4byte_movq_load:
> + return true;
> + }
> + }
Change the name to indicate that this x86-specific?
> + static bool isFixupKindRIPRel(unsigned Kind) {
> + return Kind == X86::reloc_riprel_4byte ||
> + Kind == X86::reloc_riprel_4byte_movq_load;
> + }
Same.
> + // Emit the ELF header.
> + void WriteHeader(uint64_t SectionDataSize, unsigned NumberOfSections) {
(General comment) Could you move the large method implementations out of the
class definition?
> + Write8(ELF::EV_CURRENT); // e_ident[EI_VERSION]
> + Write8(ELF::ELFOSABI_LINUX); // e_ident[EI_OSABI]
> + Write8(0); // e_ident[EI_ABIVERSION]
Factor this out so that it's obvious something needs to change here to make
it crossplatform.
> + // FIXME
> + Write16(ELF::EM_X86_64); // e_machine = target
Same.
> + Write32(ELF::EV_CURRENT); // e_version
> + WriteWord(0); // e_entry, no entry point in .o file
> + WriteWord(0); // e_phoff, no program header for .o
> + WriteWord(SectionDataSize + 64); // e_shoff = sec hdr table off in bytes
Odd-looking indentation.
> + // FIXME
> + Write32(0); // e_flags = whatever the target wants
Factor out.
> + Write16(Is64Bit ? 64 : 52); // e_ehsize = ELF header size
sizeof(Elf32_Ehdr)? Or at least name these values somehow...
> + // e_shentsize = Section header entry size
> + Write16(Is64Bit ? 64 : 40);
See above.
> + // e_shnum = # of section header ents
> + Write16(NumberOfSections);
> +
> + // e_shstrndx = Section # of '.shstrtab'
> + Write16(ShstrtabIndex);
> + }
> +
> + void WriteSymbolEntry(MCDataFragment *F, uint64_t name, uint8_t info,
> + uint64_t value, uint64_t size,
> + uint8_t other, uint16_t shndx) {
> + if (Is64Bit) {
> + F->getContents() += StringRef((const char *)&name, 4); // st_name
> + F->getContents() += StringRef((const char *)&info, 1); // st_info
> + F->getContents() += StringRef((const char *)&other, 1); // st_other
> + F->getContents() += StringRef((const char *)&shndx, 2); // st_shndx
> + F->getContents() += StringRef((const char *)&value, 8); // st_value
> + // FIXME
> + F->getContents() += StringRef((const char *)&size, 8); // st_size
FIXME what? Same for all the unlableled FIXMEs.
> + Value = Layout.getSymbolAddress(&Data);
> + MCValue Res;
> + if (Data.getSizeSymbol()->EvaluateAsRelocatable(Res, &Layout)) {
> + MCSymbolData &A =
> + Layout.getAssembler().getSymbolData(Res.getSymA()->getSymbol());
> + MCSymbolData &B =
> + Layout.getAssembler().getSymbolData(Res.getSymB()->getSymbol());
> +
> + Size = Layout.getSymbolAddress(&A) - Layout.getSymbolAddress(&B);
How is this different from EvaluateAsAbsolute?
> + // XXX: this is currently X86_64 only
Don't use XXX; use FIXME instead.
> + if (Symbol.isUndefined()) {
> + MSD.SectionIndex = ELF::SHN_UNDEF;
> + // XXX: for some reason we dont Emit* this
> + it->setFlags(it->getFlags() | (ELF::STB_GLOBAL << ELF::STB_SHIFT));
> + UndefinedSymbolData.push_back(MSD);
Indentation?
> +
> + void WriteRelocations(MCAssembler &Asm, MCAsmLayout &Layout) {
> + for (MCAssembler::const_iterator it = Asm.begin(),
> + ie = Asm.end(); it != ie; ++it) {
> + const MCSectionData &SD = *it;
> +
> + WriteRelocation(Asm, Layout, SD);
WriteRelocation(Asm, Layout, *it);
> + void WriteSecHdrEntry(uint32_t Name, uint32_t Type, uint64_t Flags,
> + uint64_t Address, uint64_t Offset,
> + uint64_t Size, uint32_t Link, uint32_t Info,
> + uint64_t Alignment, uint64_t EntrySize) {
> + // Suppose that all non-initialized EntrySizes are actually a zero
> + if (EntrySize == ~0U)
> + EntrySize = 0;
Messy... would it be possible to just set it correctly in the first place?
> + F->getContents() += StringRef((const char *)&entry.r_offset, 8);
> + F->getContents() += StringRef((const char *)&entry.r_info, 8);
Is this endian-safe?
> + // Write out the ELF header ...
> + WriteHeader(SectionDataSize, NumSections);
> + FileOff = Is64Bit ? 64 : 52;
Again, names...
> + // ... and then the section header table.
> + // Should we align the section header table?
> + //
> + // Null secton first.
*section
> + switch(Section.getType()) {
> + case ELF::SHT_DYNAMIC:
> + sh_link = SectionStringTableIndex[&it->getSection()];
> + sh_info = 0;
> + break;
> +
> + case ELF::SHT_REL:
> + case ELF::SHT_RELA:
> + const MCSection *SymtabSection;
> + const MCSection *InfoSection;
> + const StringRef *SectionName;
> + const MCSectionData *SymtabSD;
> + const MCSectionData *InfoSD;
> +
> + SymtabSection = Asm.getContext().getELFSection(".symtab", ELF::SHT_SYMTAB, 0,
> + SectionKind::getReadOnly(), false);
> + SymtabSD = &Asm.getSectionData(*SymtabSection);
> + // we have to count the empty section in too
> + sh_link = SymtabSD->getLayoutOrder() + 1;
> +
> + SectionName = &Section.getSectionName();
> + SectionName = &SectionName->slice(5, SectionName->size());
> + InfoSection = Asm.getContext().getELFSection(*SectionName,
> + ELF::SHT_PROGBITS, 0, SectionKind::getReadOnly(), false);
> + InfoSD = &Asm.getSectionData(*InfoSection);
> + sh_info = InfoSD->getLayoutOrder() + 1;
> + break;
> +
> + case ELF::SHT_SYMTAB:
> + case ELF::SHT_DYNSYM:
> + sh_link = StringTableIndex;
> + sh_info = LastLocalSymbolIndex;
> + break;
> +
> + case ELF::SHT_HASH:
> + case ELF::SHT_GROUP:
> + case ELF::SHT_SYMTAB_SHNDX:
"default:" ?
> + assert(0 && "FIXME: sh_type value not supported!");
> + break;
> + }
> +
> + WriteSecHdrEntry(SectionStringTableIndex[&it->getSection()],
> + Section.getType(), Section.getFlags(),
> + Layout.getSectionAddress(&SD),
> + SectionOffsetMap.lookup(&SD.getSection()),
> + Layout.getSectionSize(&SD), sh_link,
> + sh_info, SD.getAlignment(),
> + SD.getEntrySize());
Indentation.
+namespace {
+
+class MCELFStreamer : public MCStreamer {
+private:
Should inherit from MCObjectStreamer.
> + MCFragment *getCurrentFragment() const {
> + assert(CurSectionData && "No current section!");
> +
> + if (!CurSectionData->empty())
> + return &CurSectionData->getFragmentList().back();
> +
> + return 0;
> + }
Shadows MCObjectStreamer::getCurrentFragment().
> + /// Get a data fragment to write into, creating a new one if the current
> + /// fragment is not a data fragment.
> + MCDataFragment *getOrCreateDataFragment() const {
> + MCDataFragment *F = dyn_cast_or_null<MCDataFragment>(getCurrentFragment());
> + if (!F)
> + F = new MCDataFragment(CurSectionData);
> + return F;
> + }
Shadows MCObjectStreamer::getOrCreateDataFragment().
> + MCAssembler &getAssembler() { return Assembler; }
Shadows MCObjectStreamer::getAssembler().
> + const MCExpr *AddValueSymbols(const MCExpr *Value) {
> + switch (Value->getKind()) {
> + case MCExpr::Target: assert(0 && "Can't handle target exprs yet!");
> + case MCExpr::Constant:
> + break;
> +
> + case MCExpr::Binary: {
> + const MCBinaryExpr *BE = cast<MCBinaryExpr>(Value);
> + AddValueSymbols(BE->getLHS());
> + AddValueSymbols(BE->getRHS());
> + break;
> + }
> +
> + case MCExpr::SymbolRef:
> + Assembler.getOrCreateSymbolData(
> + cast<MCSymbolRefExpr>(Value)->getSymbol());
> + break;
> +
> + case MCExpr::Unary:
> + AddValueSymbols(cast<MCUnaryExpr>(Value)->getSubExpr());
> + break;
> + }
> +
> + return Value;
> + }
Shadows MCObjectStreamer::AddValueSymbols.
> +
> + virtual void EmitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
Push definition outside of class defn.
> + virtual void EmitDwarfFileDirective(unsigned FileNo, StringRef Filename) {
> + errs() << "FIXME: MCELFStreamer:EmitDwarfFileDirective not implemented\n";
> + }
DEBUG(dbgs() << "")?
> + virtual void EmitInstruction(const MCInst &Inst);
> + virtual void Finish();
> +
> + /// @}
> +};
> +
> +} // end anonymous namespace.
> +
> +void MCELFStreamer::SwitchSection(const MCSection *Section) {
> + assert(Section && "Cannot switch to a null section!");
> +
> + // If already in this section, then this is a noop.
> + if (Section == CurSection) return;
> +
> + CurSection = Section;
> + CurSectionData = &Assembler.getOrCreateSectionData(*Section);
> +}
Identical to MCObjectStreamer::SwitchSection.
> +void MCELFStreamer::EmitLabel(MCSymbol *Symbol) {
> + assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
> +
> + // FIXME: This is wasteful, we don't necessarily need to create a data
> + // fragment. Instead, we should mark the symbol as pointing into the data
> + // fragment if it exists, otherwise we should just queue the label and set its
> + // fragment pointer when we emit the next fragment.
> + MCDataFragment *F = getOrCreateDataFragment();
> + MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
> + assert(!SD.getFragment() && "Unexpected fragment on symbol data!");
> + SD.setFragment(F);
> + SD.setOffset(F->getContents().size());
> +
> + Symbol->setSection(*CurSection);
> +}
> +
> +void MCELFStreamer::EmitAssemblerFlag(MCAssemblerFlag Flag) {
> + switch (Flag) {
> + case MCAF_SubsectionsViaSymbols:
> + Assembler.setSubsectionsViaSymbols(true);
> + return;
> + }
> +
> + assert(0 && "invalid assembler flag!");
> +}
> +
> +void MCELFStreamer::EmitAssignment(MCSymbol *Symbol, const MCExpr *Value) {
> + // Only absolute symbols can be redefined.
> + assert((Symbol->isUndefined() || Symbol->isAbsolute()) &&
> + "Cannot define a symbol twice!");
> +
> + // FIXME: Lift context changes into super class.
> + // FIXME: Set associated section.
> + // Symbol->setValue(AddValueSymbols(Value));
> +}
Should this be different from MCMachOStreamer::EmitAssignment?
> +void MCELFStreamer::EmitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
> +}
assert(0)? Or what is this supposed to be useful for?
> +void MCELFStreamer::EmitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
> + unsigned ByteAlignment) {
> + MCSymbolData &SD = Assembler.getOrCreateSymbolData(*Symbol);
> +
> + if ((SD.getFlags() & (0xff << ELF::STB_SHIFT)) == ELF::STB_LOCAL << ELF::STB_SHIFT) {
STB_* is only 4 bits, so 0xf, no?
> +void MCELFStreamer::EmitZerofill(const MCSection *Section, MCSymbol *Symbol,
> + unsigned Size, unsigned ByteAlignment) {
AFAIK, .zerofill is Darwin-only.
> +void MCELFStreamer::EmitTBSSSymbol(const MCSection *Section, MCSymbol *Symbol,
> + uint64_t Size, unsigned ByteAlignment) {
Also Darwin only, AFAIK.
> +void MCELFStreamer::EmitBytes(StringRef Data, unsigned AddrSpace) {
> + getOrCreateDataFragment()->getContents().append(Data.begin(), Data.end());
> +}
Same as MCMachOStreamer::EmitBytes; toss in a TODO?
> +void MCELFStreamer::EmitValue(const MCExpr *Value, unsigned Size,
> + unsigned AddrSpace) {
> + MCDataFragment *DF = getOrCreateDataFragment();
> +
> + // Avoid fixups when possible.
> + int64_t AbsValue;
> + if (AddValueSymbols(Value)->EvaluateAsAbsolute(AbsValue)) {
> + // FIXME: Endianness assumption.
> + for (unsigned i = 0; i != Size; ++i)
> + DF->getContents().push_back(uint8_t(AbsValue >> (i * 8)));
> + } else {
> + DF->addFixup(MCFixup::Create(DF->getContents().size(), AddValueSymbols(Value),
> + MCFixup::getKindForSize(Size)));
> + DF->getContents().resize(DF->getContents().size() + Size, 0);
> + }
> +}
Same as MCMachOStreamer::EmitValue; toss in a TODO?
> +void MCELFStreamer::EmitValueToAlignment(unsigned ByteAlignment,
> + int64_t Value, unsigned ValueSize,
> + unsigned MaxBytesToEmit) {
> + if (MaxBytesToEmit == 0)
> + MaxBytesToEmit = ByteAlignment;
> + new MCAlignFragment(ByteAlignment, Value, ValueSize, MaxBytesToEmit,
> + CurSectionData);
> +
> + // Update the maximum alignment on the current section if necessary.
> + if (ByteAlignment > CurSectionData->getAlignment())
> + CurSectionData->setAlignment(ByteAlignment);
> +}
Same as MCMachOStreamer::EmitValueToAlignment; toss in a TODO?
> +void MCELFStreamer::EmitCodeAlignment(unsigned ByteAlignment,
> + unsigned MaxBytesToEmit) {
> + if (MaxBytesToEmit == 0)
> + MaxBytesToEmit = ByteAlignment;
> + new MCAlignFragment(ByteAlignment, 0, 1, MaxBytesToEmit,
> + CurSectionData);
> +
> + // Update the maximum alignment on the current section if necessary.
> + if (ByteAlignment > CurSectionData->getAlignment())
> + CurSectionData->setAlignment(ByteAlignment);
> +}
Same as MCMachOStreamer::EmitCodeAlignment; toss in a TODO?
> +void MCELFStreamer::EmitValueToOffset(const MCExpr *Offset,
> + unsigned char Value) {
> + new MCOrgFragment(*Offset, Value, CurSectionData);
> +}
Same as MCMachOStreamer::EmitValueToOffset; toss in a TODO?
-Eli
More information about the llvm-commits
mailing list