Add support for emitting the symbol table (and its string table) of the

module to the ELF file.  Test it by adding support for emitting common
symbols.  This allows us to compile this:

%X = weak global int 0
%Y = weak global int 0
%Z = weak global int 0

to an elf file that 'readelf's this:

Symbol table '.symtab' contains 4 entries:
   Num:    Value  Size Type    Bind   Vis      Ndx Name
     0: 00000000     0 NOTYPE  LOCAL  DEFAULT  UND
     1: 00000004     4 OBJECT  GLOBAL DEFAULT  COM X
     2: 00000004     4 OBJECT  GLOBAL DEFAULT  COM Y
     3: 00000004     4 OBJECT  GLOBAL DEFAULT  COM Z


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@22343 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Chris Lattner 2005-07-07 07:02:20 +00:00
parent e578ab938b
commit 80ed8faaea

View File

@ -11,17 +11,18 @@
// the ELF file in the following order: // the ELF file in the following order:
// //
// #1. ELF Header // #1. ELF Header
// #2. '.data' section // #2. '.text' section
// #3. '.bss' section // #3. '.data' section
// #4. '.bss' section (conceptual position in file)
// ... // ...
// #X. '.shstrtab' section // #X. '.shstrtab' section
// #Y. Section Table // #Y. Section Table
// //
// The entries in the section table are laid out as: // The entries in the section table are laid out as:
// #0. Null entry [required] // #0. Null entry [required]
// #1. ".data" entry - global variables with initializers. [ if needed ] // #1. ".text" entry - the program code
// #2. ".bss" entry - global variables without initializers. [ if needed ] // #2. ".data" entry - global variables with initializers. [ if needed ]
// #3. ".text" entry - the program code // #3. ".bss" entry - global variables without initializers. [ if needed ]
// ... // ...
// #N. ".shstrtab" entry - String table for the section names. // #N. ".shstrtab" entry - String table for the section names.
@ -83,62 +84,50 @@ bool ELFWriter::doInitialization(Module &M) {
// Add the null section. // Add the null section.
SectionList.push_back(ELFSection()); SectionList.push_back(ELFSection());
// Okay, the ELF header has been completed, emit the .data section next. // Start up the symbol table. The first entry in the symtab is the null
ELFSection DataSection(".data", OutputBuffer.size()); // entry.
for (Module::global_iterator I = M.global_begin(), E = M.global_end(); SymbolTable.push_back(ELFSym(0));
I != E; ++I)
EmitDATASectionGlobal(I);
// If the .data section is nonempty, add it to our list.
if ((DataSection.Size = OutputBuffer.size()-DataSection.Offset)) {
DataSection.Align = 4; // FIXME: Compute!
SectionList.push_back(DataSection);
}
// Okay, emit the .bss section next.
ELFSection BSSSection(".bss", OutputBuffer.size());
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I)
EmitBSSSectionGlobal(I);
// If the .bss section is nonempty, add it to our list.
if ((BSSSection.Size = OutputBuffer.size()-BSSSection.Offset)) {
BSSSection.Align = 4; // FIXME: Compute!
SectionList.push_back(BSSSection);
}
// FIXME: Should start the .text section.
return false; return false;
} }
// isCOMM - A global variable should be emitted to the common area if it is zero void ELFWriter::EmitGlobal(GlobalVariable *GV, ELFSection &DataSection,
// initialized and has linkage that permits it to be merged with other globals. ELFSection &BSSSection) {
static bool isCOMM(GlobalVariable *GV) { // If this is an external global, emit it...
return GV->getInitializer()->isNullValue() && assert(GV->hasInitializer() && "FIXME: unimp");
(GV->hasLinkOnceLinkage() || GV->hasInternalLinkage() ||
GV->hasWeakLinkage()); // If this global has a zero initializer, it is part of the .bss or common
} // section.
if (GV->getInitializer()->isNullValue()) {
// If this global is part of the common block, add it now. Variables are
// part of the common block if they are zero initialized and allowed to be
// merged with other symbols.
if (GV->hasLinkOnceLinkage() || GV->hasWeakLinkage()) {
ELFSym CommonSym(GV);
// Value for common symbols is the alignment required.
const Type *GVType = (const Type*)GV->getType();
CommonSym.Value = TM.getTargetData().getTypeAlignment(GVType);
CommonSym.Size = TM.getTargetData().getTypeSize(GVType);
CommonSym.SetBind(ELFSym::STB_GLOBAL);
CommonSym.SetType(ELFSym::STT_OBJECT);
// TODO SOMEDAY: add ELF visibility.
CommonSym.SectionIdx = ELFSection::SHN_COMMON;
SymbolTable.push_back(CommonSym);
return;
}
// EmitDATASectionGlobal - Emit a global variable to the .data section if it // FIXME: Implement the .bss section.
// belongs there. return;
void ELFWriter::EmitDATASectionGlobal(GlobalVariable *GV) { }
if (!GV->hasInitializer()) return;
// Do not emit a symbol here if it should be emitted to the common area. // FIXME: handle .rodata
if (isCOMM(GV)) return; //assert(!GV->isConstant() && "unimp");
EmitGlobal(GV); // FIXME: handle .data
} //assert(0 && "unimp");
void ELFWriter::EmitBSSSectionGlobal(GlobalVariable *GV) {
if (!GV->hasInitializer()) return;
// FIXME: We don't support BSS yet!
return;
EmitGlobal(GV);
}
void ELFWriter::EmitGlobal(GlobalVariable *GV) {
} }
@ -149,6 +138,37 @@ bool ELFWriter::runOnMachineFunction(MachineFunction &MF) {
/// doFinalization - Now that the module has been completely processed, emit /// doFinalization - Now that the module has been completely processed, emit
/// the ELF file to 'O'. /// the ELF file to 'O'.
bool ELFWriter::doFinalization(Module &M) { bool ELFWriter::doFinalization(Module &M) {
// Okay, the .text section has now been finalized.
// FIXME: finalize the .text section.
// Okay, the ELF header and .text sections have been completed, build the
// .data, .bss, and "common" sections next.
ELFSection DataSection(".data", OutputBuffer.size());
ELFSection BSSSection (".bss");
for (Module::global_iterator I = M.global_begin(), E = M.global_end();
I != E; ++I)
EmitGlobal(I, DataSection, BSSSection);
// If the .data section is nonempty, add it to our list.
if (DataSection.Size) {
DataSection.Align = 4; // FIXME: Compute!
// FIXME: Set the right flags and stuff.
SectionList.push_back(DataSection);
}
// If the .bss section is nonempty, add it to our list.
if (BSSSection.Size) {
BSSSection.Offset = OutputBuffer.size();
BSSSection.Align = 4; // FIXME: Compute!
// FIXME: Set the right flags and stuff.
SectionList.push_back(BSSSection);
}
// Emit the symbol table now, if non-empty.
EmitSymbolTable();
// FIXME: Emit the relocations now.
// Emit the string table for the sections in the ELF file we have. // Emit the string table for the sections in the ELF file we have.
EmitSectionTableStringTable(); EmitSectionTableStringTable();
@ -163,13 +183,80 @@ bool ELFWriter::doFinalization(Module &M) {
return false; return false;
} }
/// EmitSymbolTable - If the current symbol table is non-empty, emit the string
/// table for it and then the symbol table itself.
void ELFWriter::EmitSymbolTable() {
if (SymbolTable.size() == 1) return; // Only the null entry.
// FIXME: compact all local symbols to the start of the symtab.
unsigned FirstNonLocalSymbol = 1;
SectionList.push_back(ELFSection(".strtab", OutputBuffer.size()));
ELFSection &StrTab = SectionList.back();
StrTab.Type = ELFSection::SHT_STRTAB;
StrTab.Align = 1;
// Set the zero'th symbol to a null byte, as required.
outbyte(0);
SymbolTable[0].NameIdx = 0;
unsigned Index = 1;
for (unsigned i = 1, e = SymbolTable.size(); i != e; ++i) {
// FIXME: USE A MANGLER!!
const std::string &Name = SymbolTable[i].GV->getName();
if (Name.empty()) {
SymbolTable[i].NameIdx = 0;
} else {
SymbolTable[i].NameIdx = Index;
// Add the name to the output buffer, including the null terminator.
OutputBuffer.insert(OutputBuffer.end(), Name.begin(), Name.end());
// Add a null terminator.
OutputBuffer.push_back(0);
// Keep track of the number of bytes emitted to this section.
Index += Name.size()+1;
}
}
StrTab.Size = OutputBuffer.size()-StrTab.Offset;
// Now that we have emitted the string table and know the offset into the
// string table of each symbol, emit the symbol table itself.
assert(!is64Bit && "Should this be 8 byte aligned for 64-bit?"
" (check .Align below also)");
align(4);
SectionList.push_back(ELFSection(".symtab", OutputBuffer.size()));
ELFSection &SymTab = SectionList.back();
SymTab.Type = ELFSection::SHT_SYMTAB;
SymTab.Align = 4; // FIXME: check for ELF64
SymTab.Link = SectionList.size()-2; // Section Index of .strtab.
SymTab.Info = FirstNonLocalSymbol; // First non-STB_LOCAL symbol.
SymTab.EntSize = 16; // Size of each symtab entry. FIXME: wrong for ELF64
assert(!is64Bit && "check this!");
for (unsigned i = 0, e = SymbolTable.size(); i != e; ++i) {
ELFSym &Sym = SymbolTable[i];
outword(Sym.NameIdx);
outaddr(Sym.Value);
outword(Sym.Size);
outbyte(Sym.Info);
outbyte(Sym.Other);
outhalf(Sym.SectionIdx);
}
SymTab.Size = OutputBuffer.size()-SymTab.Offset;
}
/// EmitSectionTableStringTable - This method adds and emits a section for the /// EmitSectionTableStringTable - This method adds and emits a section for the
/// ELF Section Table string table: the string table that holds all of the /// ELF Section Table string table: the string table that holds all of the
/// section names. /// section names.
void ELFWriter::EmitSectionTableStringTable() { void ELFWriter::EmitSectionTableStringTable() {
// First step: add the section for the string table to the list of sections: // First step: add the section for the string table to the list of sections:
SectionList.push_back(ELFSection(".shstrtab", OutputBuffer.size())); SectionList.push_back(ELFSection(".shstrtab", OutputBuffer.size()));
SectionList.back().Type = 3; // SHT_STRTAB SectionList.back().Type = ELFSection::SHT_STRTAB;
// Now that we know which section number is the .shstrtab section, update the // Now that we know which section number is the .shstrtab section, update the
// e_shstrndx entry in the ELF header. // e_shstrndx entry in the ELF header.