llvm-mc/Mach-O: Add section padding where needed (to align the next section).

Also, simplify some of Mach-O writer code which can now use section addresses.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@80067 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Daniel Dunbar 2009-08-26 04:13:32 +00:00
parent 5e835967dd
commit 6742e34385
4 changed files with 286 additions and 43 deletions

View File

@ -82,7 +82,7 @@ public:
uint64_t getAddress() const; uint64_t getAddress() const;
unsigned getFileSize() const { uint64_t getFileSize() const {
assert(FileSize != ~UINT64_C(0) && "File size not set!"); assert(FileSize != ~UINT64_C(0) && "File size not set!");
return FileSize; return FileSize;
} }
@ -267,6 +267,9 @@ private:
/// initialized. /// initialized.
uint64_t Address; uint64_t Address;
/// Size - The content size of this section. This is ~0 until initialized.
uint64_t Size;
/// FileSize - The size of this section in the object file. This is ~0 until /// FileSize - The size of this section in the object file. This is ~0 until
/// initialized. /// initialized.
uint64_t FileSize; uint64_t FileSize;
@ -305,13 +308,19 @@ public:
// //
// FIXME: This could all be kept private to the assembler implementation. // FIXME: This could all be kept private to the assembler implementation.
unsigned getAddress() const { uint64_t getAddress() const {
assert(Address != ~UINT64_C(0) && "Address not set!"); assert(Address != ~UINT64_C(0) && "Address not set!");
return Address; return Address;
} }
void setAddress(uint64_t Value) { Address = Value; } void setAddress(uint64_t Value) { Address = Value; }
unsigned getFileSize() const { uint64_t getSize() const {
assert(Size != ~UINT64_C(0) && "File size not set!");
return Size;
}
void setSize(uint64_t Value) { Size = Value; }
uint64_t getFileSize() const {
assert(FileSize != ~UINT64_C(0) && "File size not set!"); assert(FileSize != ~UINT64_C(0) && "File size not set!");
return FileSize; return FileSize;
} }
@ -414,7 +423,11 @@ private:
/// LayoutSection - Assign offsets and sizes to the fragments in the section /// LayoutSection - Assign offsets and sizes to the fragments in the section
/// \arg SD, and update the section size. The section file offset should /// \arg SD, and update the section size. The section file offset should
/// already have been computed. /// already have been computed.
void LayoutSection(MCSectionData &SD); ///
/// \param NextAlign - The alignment for the section end address, which may
/// add padding bytes to the section (these are included in the section "file"
/// size, but not its regular size).
void LayoutSection(MCSectionData &SD, unsigned NextAlign);
public: public:
/// Construct a new assembler instance. /// Construct a new assembler instance.

View File

@ -217,7 +217,7 @@ public:
WriteString(Section.getSectionName(), 16); WriteString(Section.getSectionName(), 16);
WriteString(Section.getSegmentName(), 16); WriteString(Section.getSegmentName(), 16);
Write32(SD.getAddress()); // address Write32(SD.getAddress()); // address
Write32(SD.getFileSize()); // size Write32(SD.getSize()); // size
Write32(FileOffset); Write32(FileOffset);
assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!");
@ -508,11 +508,6 @@ public:
ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData,
UndefinedSymbolData); UndefinedSymbolData);
// Compute the file offsets for all the sections in advance, so that we can
// write things out in order.
SmallVector<uint64_t, 16> SectionFileOffsets;
SectionFileOffsets.resize(NumSections);
// The section data starts after the header, the segment load command (and // The section data starts after the header, the segment load command (and
// section headers) and the symbol table. // section headers) and the symbol table.
unsigned NumLoadCommands = 1; unsigned NumLoadCommands = 1;
@ -525,27 +520,22 @@ public:
LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize; LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize;
} }
uint64_t FileOffset = Header32Size + LoadCommandsSize; uint64_t SectionDataStart = Header32Size + LoadCommandsSize;
uint64_t SectionDataStartOffset = FileOffset; uint64_t SectionDataEnd = SectionDataStart;
uint64_t SectionDataSize = 0; uint64_t SectionDataSize = 0;
unsigned Index = 0; if (!Asm.getSectionList().empty()) {
for (MCAssembler::iterator it = Asm.begin(), MCSectionData &SD = Asm.getSectionList().back();
ie = Asm.end(); it != ie; ++it, ++Index) { SectionDataSize = SD.getAddress() + SD.getSize();
SectionFileOffsets[Index] = FileOffset; SectionDataEnd = SectionDataStart + SD.getAddress() + SD.getFileSize();
FileOffset += it->getFileSize();
SectionDataSize += it->getFileSize();
} }
// Write the prolog, starting with the header and load command... // Write the prolog, starting with the header and load command...
WriteHeader32(NumLoadCommands, LoadCommandsSize); WriteHeader32(NumLoadCommands, LoadCommandsSize);
WriteSegmentLoadCommand32(NumSections, SectionDataStartOffset, WriteSegmentLoadCommand32(NumSections, SectionDataStart, SectionDataSize);
SectionDataSize);
// ... and then the section headers. // ... and then the section headers.
Index = 0; for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it)
for (MCAssembler::iterator it = Asm.begin(), WriteSection32(*it, SectionDataStart + it->getAddress());
ie = Asm.end(); it != ie; ++it, ++Index)
WriteSection32(*it, SectionFileOffsets[Index]);
// Write the symbol table load command, if used. // Write the symbol table load command, if used.
if (NumSymbols) { if (NumSymbols) {
@ -563,11 +553,10 @@ public:
// If used, the indirect symbols are written after the section data. // If used, the indirect symbols are written after the section data.
if (NumIndirectSymbols) if (NumIndirectSymbols)
IndirectSymbolOffset = SectionDataStartOffset + SectionDataSize; IndirectSymbolOffset = SectionDataEnd;
// The symbol table is written after the indirect symbol data. // The symbol table is written after the indirect symbol data.
uint64_t SymbolTableOffset = uint64_t SymbolTableOffset = SectionDataEnd + IndirectSymbolSize;
SectionDataStartOffset + SectionDataSize + IndirectSymbolSize;
// The string table is written after symbol table. // The string table is written after symbol table.
uint64_t StringTableOffset = uint64_t StringTableOffset =
@ -675,6 +664,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A)
: Section(_Section), : Section(_Section),
Alignment(1), Alignment(1),
Address(~UINT64_C(0)), Address(~UINT64_C(0)),
Size(~UINT64_C(0)),
FileSize(~UINT64_C(0)) FileSize(~UINT64_C(0))
{ {
if (A) if (A)
@ -701,26 +691,24 @@ MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {}
MCAssembler::~MCAssembler() { MCAssembler::~MCAssembler() {
} }
void MCAssembler::LayoutSection(MCSectionData &SD) { void MCAssembler::LayoutSection(MCSectionData &SD, unsigned NextAlign) {
uint64_t Offset = 0; uint64_t Address = SD.getAddress();
for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) { for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) {
MCFragment &F = *it; MCFragment &F = *it;
F.setOffset(Offset); F.setOffset(Address - SD.getAddress());
// Evaluate fragment size. // Evaluate fragment size.
switch (F.getKind()) { switch (F.getKind()) {
case MCFragment::FT_Align: { case MCFragment::FT_Align: {
MCAlignFragment &AF = cast<MCAlignFragment>(F); MCAlignFragment &AF = cast<MCAlignFragment>(F);
uint64_t AlignedOffset = RoundUpToAlignment(Offset, AF.getAlignment()); uint64_t Size = RoundUpToAlignment(Address, AF.getAlignment()) - Address;
uint64_t PaddingBytes = AlignedOffset - Offset; if (Size > AF.getMaxBytesToEmit())
if (PaddingBytes > AF.getMaxBytesToEmit())
AF.setFileSize(0); AF.setFileSize(0);
else else
AF.setFileSize(PaddingBytes); AF.setFileSize(Size);
break; break;
} }
@ -735,22 +723,24 @@ void MCAssembler::LayoutSection(MCSectionData &SD) {
if (!OF.getOffset().isAbsolute()) if (!OF.getOffset().isAbsolute())
llvm_unreachable("FIXME: Not yet implemented!"); llvm_unreachable("FIXME: Not yet implemented!");
uint64_t OrgOffset = OF.getOffset().getConstant(); uint64_t OrgOffset = OF.getOffset().getConstant();
uint64_t Offset = Address - SD.getAddress();
// FIXME: We need a way to communicate this error. // FIXME: We need a way to communicate this error.
if (OrgOffset < Offset) if (OrgOffset < Offset)
llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + llvm_report_error("invalid .org offset '" + Twine(OrgOffset) +
"' (section offset '" + Twine(Offset) + "'"); "' (at offset '" + Twine(Offset) + "'");
F.setFileSize(OrgOffset - Offset); F.setFileSize(OrgOffset - Offset);
break; break;
} }
} }
Offset += F.getFileSize(); Address += F.getFileSize();
} }
// FIXME: Pad section? // Set the section sizes.
SD.setFileSize(Offset); SD.setSize(Address - SD.getAddress());
SD.setFileSize(RoundUpToAlignment(Address, NextAlign) - SD.getAddress());
} }
/// WriteFileData - Write the \arg F data to the output file. /// WriteFileData - Write the \arg F data to the output file.
@ -836,16 +826,32 @@ static void WriteFileData(raw_ostream &OS, const MCSectionData &SD,
ie = SD.end(); it != ie; ++it) ie = SD.end(); it != ie; ++it)
WriteFileData(OS, *it, MOW); WriteFileData(OS, *it, MOW);
// Add section padding.
assert(SD.getFileSize() >= SD.getSize() && "Invalid section sizes!");
MOW.WriteZeros(SD.getFileSize() - SD.getSize());
assert(OS.tell() - Start == SD.getFileSize()); assert(OS.tell() - Start == SD.getFileSize());
} }
void MCAssembler::Finish() { void MCAssembler::Finish() {
// Layout the sections and fragments. // Layout the sections and fragments.
uint64_t Address = 0; uint64_t Address = 0;
for (iterator it = begin(), ie = end(); it != ie; ++it) { for (iterator it = begin(), ie = end(); it != ie;) {
it->setAddress(Address); MCSectionData &SD = *it;
LayoutSection(*it);
Address += it->getFileSize(); // Select the amount of padding alignment we need, based on either the next
// sections alignment or the default alignment.
//
// FIXME: This should probably match the native word size.
unsigned NextAlign = 4;
++it;
if (it != ie)
NextAlign = it->getAlignment();
// Layout the section fragments and its size.
SD.setAddress(Address);
LayoutSection(SD, NextAlign);
Address += SD.getFileSize();
} }
// Write the object file. // Write the object file.

View File

@ -0,0 +1,87 @@
// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s
name:
.byte 0
// Check that symbol table is aligned to 4 bytes.
// CHECK: ('cputype', 7)
// CHECK: ('cpusubtype', 3)
// CHECK: ('filetype', 1)
// CHECK: ('num_load_commands', 1)
// CHECK: ('load_commands_size', 228)
// CHECK: ('flag', 0)
// CHECK: ('load_commands', [
// CHECK: # Load Command 0
// CHECK: (('command', 1)
// CHECK: ('size', 124)
// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('vm_addr', 0)
// CHECK: ('vm_size', 1)
// CHECK: ('file_offset', 256)
// CHECK: ('file_size', 1)
// CHECK: ('maxprot', 7)
// CHECK: ('initprot', 7)
// CHECK: ('num_sections', 1)
// CHECK: ('flags', 0)
// CHECK: ('sections', [
// CHECK: # Section 0
// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('address', 0)
// CHECK: ('size', 1)
// CHECK: ('offset', 256)
// CHECK: ('alignment', 0)
// CHECK: ('reloc_offset', 0)
// CHECK: ('num_reloc', 0)
// CHECK: ('flags', 0x80000000)
// CHECK: ('reserved1', 0)
// CHECK: ('reserved2', 0)
// CHECK: ),
// CHECK: ])
// CHECK: ),
// CHECK: # Load Command 1
// CHECK: (('command', 2)
// CHECK: ('size', 24)
// CHECK: ('symoff', 260)
// CHECK: ('nsyms', 1)
// CHECK: ('stroff', 272)
// CHECK: ('strsize', 8)
// CHECK: ('_string_data', '\x00name\x00\x00\x00')
// CHECK: ('_symbols', [
// CHECK: # Symbol 0
// CHECK: (('n_strx', 1)
// CHECK: ('n_type', 0xe)
// CHECK: ('n_sect', 1)
// CHECK: ('n_desc', 0)
// CHECK: ('n_value', 0)
// CHECK: ('_string', 'name')
// CHECK: ),
// CHECK: ])
// CHECK: ),
// CHECK: # Load Command 2
// CHECK: (('command', 11)
// CHECK: ('size', 80)
// CHECK: ('ilocalsym', 0)
// CHECK: ('nlocalsym', 1)
// CHECK: ('iextdefsym', 1)
// CHECK: ('nextdefsym', 0)
// CHECK: ('iundefsym', 1)
// CHECK: ('nundefsym', 0)
// CHECK: ('tocoff', 0)
// CHECK: ('ntoc', 0)
// CHECK: ('modtaboff', 0)
// CHECK: ('nmodtab', 0)
// CHECK: ('extrefsymoff', 0)
// CHECK: ('nextrefsyms', 0)
// CHECK: ('indirectsymoff', 0)
// CHECK: ('nindirectsyms', 0)
// CHECK: ('extreloff', 0)
// CHECK: ('nextrel', 0)
// CHECK: ('locreloff', 0)
// CHECK: ('nlocrel', 0)
// CHECK: ('_indirect_symbols', [
// CHECK: ])
// CHECK: ),
// CHECK: ])

View File

@ -0,0 +1,137 @@
// RUN: llvm-mc -triple i386-apple-darwin9 %s -filetype=obj -o - | macho-dump | FileCheck %s
.byte 0
// There should be 3 padding bytes here.
.data
.align 2
foo:
.org 8
bar:
.byte 0
.const
baz:
// CHECK: ('cputype', 7)
// CHECK: ('cpusubtype', 3)
// CHECK: ('filetype', 1)
// CHECK: ('num_load_commands', 1)
// CHECK: ('load_commands_size', 364)
// CHECK: ('flag', 0)
// CHECK: ('load_commands', [
// CHECK: # Load Command 0
// CHECK: (('command', 1)
// CHECK: ('size', 260)
// CHECK: ('segment_name', '\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('vm_addr', 0)
// CHECK: ('vm_size', 13)
// CHECK: ('file_offset', 392)
// CHECK: ('file_size', 13)
// CHECK: ('maxprot', 7)
// CHECK: ('initprot', 7)
// CHECK: ('num_sections', 3)
// CHECK: ('flags', 0)
// CHECK: ('sections', [
// CHECK: # Section 0
// CHECK: (('section_name', '__text\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('address', 0)
// CHECK: ('size', 1)
// CHECK: ('offset', 392)
// CHECK: ('alignment', 0)
// CHECK: ('reloc_offset', 0)
// CHECK: ('num_reloc', 0)
// CHECK: ('flags', 0x80000000)
// CHECK: ('reserved1', 0)
// CHECK: ('reserved2', 0)
// CHECK: ),
// CHECK: # Section 1
// CHECK: (('section_name', '__data\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('segment_name', '__DATA\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('address', 4)
// CHECK: ('size', 9)
// CHECK: ('offset', 396)
// CHECK: ('alignment', 2)
// CHECK: ('reloc_offset', 0)
// CHECK: ('num_reloc', 0)
// CHECK: ('flags', 0x0)
// CHECK: ('reserved1', 0)
// CHECK: ('reserved2', 0)
// CHECK: ),
// CHECK: # Section 2
// CHECK: (('section_name', '__const\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('segment_name', '__TEXT\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00')
// CHECK: ('address', 13)
// CHECK: ('size', 0)
// CHECK: ('offset', 405)
// CHECK: ('alignment', 0)
// CHECK: ('reloc_offset', 0)
// CHECK: ('num_reloc', 0)
// CHECK: ('flags', 0x0)
// CHECK: ('reserved1', 0)
// CHECK: ('reserved2', 0)
// CHECK: ),
// CHECK: ])
// CHECK: ),
// CHECK: # Load Command 1
// CHECK: (('command', 2)
// CHECK: ('size', 24)
// CHECK: ('symoff', 408)
// CHECK: ('nsyms', 3)
// CHECK: ('stroff', 444)
// CHECK: ('strsize', 16)
// CHECK: ('_string_data', '\x00foo\x00bar\x00baz\x00\x00\x00\x00')
// CHECK: ('_symbols', [
// CHECK: # Symbol 0
// CHECK: (('n_strx', 1)
// CHECK: ('n_type', 0xe)
// CHECK: ('n_sect', 2)
// CHECK: ('n_desc', 0)
// CHECK: ('n_value', 4)
// CHECK: ('_string', 'foo')
// CHECK: ),
// CHECK: # Symbol 1
// CHECK: (('n_strx', 5)
// CHECK: ('n_type', 0xe)
// CHECK: ('n_sect', 2)
// CHECK: ('n_desc', 0)
// CHECK: ('n_value', 12)
// CHECK: ('_string', 'bar')
// CHECK: ),
// CHECK: # Symbol 2
// CHECK: (('n_strx', 9)
// CHECK: ('n_type', 0xe)
// CHECK: ('n_sect', 3)
// CHECK: ('n_desc', 0)
// CHECK: ('n_value', 13)
// CHECK: ('_string', 'baz')
// CHECK: ),
// CHECK: ])
// CHECK: ),
// CHECK: # Load Command 2
// CHECK: (('command', 11)
// CHECK: ('size', 80)
// CHECK: ('ilocalsym', 0)
// CHECK: ('nlocalsym', 3)
// CHECK: ('iextdefsym', 3)
// CHECK: ('nextdefsym', 0)
// CHECK: ('iundefsym', 3)
// CHECK: ('nundefsym', 0)
// CHECK: ('tocoff', 0)
// CHECK: ('ntoc', 0)
// CHECK: ('modtaboff', 0)
// CHECK: ('nmodtab', 0)
// CHECK: ('extrefsymoff', 0)
// CHECK: ('nextrefsyms', 0)
// CHECK: ('indirectsymoff', 0)
// CHECK: ('nindirectsyms', 0)
// CHECK: ('extreloff', 0)
// CHECK: ('nextrel', 0)
// CHECK: ('locreloff', 0)
// CHECK: ('nlocrel', 0)
// CHECK: ('_indirect_symbols', [
// CHECK: ])
// CHECK: ),
// CHECK: ])