diff --git a/include/llvm/MC/MCAssembler.h b/include/llvm/MC/MCAssembler.h index ce9dca1ae12..0da729b3eeb 100644 --- a/include/llvm/MC/MCAssembler.h +++ b/include/llvm/MC/MCAssembler.h @@ -82,7 +82,7 @@ public: uint64_t getAddress() const; - unsigned getFileSize() const { + uint64_t getFileSize() const { assert(FileSize != ~UINT64_C(0) && "File size not set!"); return FileSize; } @@ -267,6 +267,9 @@ private: /// initialized. 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 /// initialized. uint64_t FileSize; @@ -305,13 +308,19 @@ public: // // 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!"); return Address; } 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!"); return FileSize; } @@ -414,7 +423,11 @@ private: /// LayoutSection - Assign offsets and sizes to the fragments in the section /// \arg SD, and update the section size. The section file offset should /// 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: /// Construct a new assembler instance. diff --git a/lib/MC/MCAssembler.cpp b/lib/MC/MCAssembler.cpp index 13c193275cb..26f6d5c9c7d 100644 --- a/lib/MC/MCAssembler.cpp +++ b/lib/MC/MCAssembler.cpp @@ -217,7 +217,7 @@ public: WriteString(Section.getSectionName(), 16); WriteString(Section.getSegmentName(), 16); Write32(SD.getAddress()); // address - Write32(SD.getFileSize()); // size + Write32(SD.getSize()); // size Write32(FileOffset); assert(isPowerOf2_32(SD.getAlignment()) && "Invalid alignment!"); @@ -507,11 +507,6 @@ public: if (NumSymbols) ComputeSymbolTable(Asm, StringTable, LocalSymbolData, ExternalSymbolData, UndefinedSymbolData); - - // Compute the file offsets for all the sections in advance, so that we can - // write things out in order. - SmallVector SectionFileOffsets; - SectionFileOffsets.resize(NumSections); // The section data starts after the header, the segment load command (and // section headers) and the symbol table. @@ -525,27 +520,22 @@ public: LoadCommandsSize += SymtabLoadCommandSize + DysymtabLoadCommandSize; } - uint64_t FileOffset = Header32Size + LoadCommandsSize; - uint64_t SectionDataStartOffset = FileOffset; + uint64_t SectionDataStart = Header32Size + LoadCommandsSize; + uint64_t SectionDataEnd = SectionDataStart; uint64_t SectionDataSize = 0; - unsigned Index = 0; - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it, ++Index) { - SectionFileOffsets[Index] = FileOffset; - FileOffset += it->getFileSize(); - SectionDataSize += it->getFileSize(); + if (!Asm.getSectionList().empty()) { + MCSectionData &SD = Asm.getSectionList().back(); + SectionDataSize = SD.getAddress() + SD.getSize(); + SectionDataEnd = SectionDataStart + SD.getAddress() + SD.getFileSize(); } // Write the prolog, starting with the header and load command... WriteHeader32(NumLoadCommands, LoadCommandsSize); - WriteSegmentLoadCommand32(NumSections, SectionDataStartOffset, - SectionDataSize); + WriteSegmentLoadCommand32(NumSections, SectionDataStart, SectionDataSize); // ... and then the section headers. - Index = 0; - for (MCAssembler::iterator it = Asm.begin(), - ie = Asm.end(); it != ie; ++it, ++Index) - WriteSection32(*it, SectionFileOffsets[Index]); + for (MCAssembler::iterator it = Asm.begin(), ie = Asm.end(); it != ie; ++it) + WriteSection32(*it, SectionDataStart + it->getAddress()); // Write the symbol table load command, if used. if (NumSymbols) { @@ -563,11 +553,10 @@ public: // If used, the indirect symbols are written after the section data. if (NumIndirectSymbols) - IndirectSymbolOffset = SectionDataStartOffset + SectionDataSize; + IndirectSymbolOffset = SectionDataEnd; // The symbol table is written after the indirect symbol data. - uint64_t SymbolTableOffset = - SectionDataStartOffset + SectionDataSize + IndirectSymbolSize; + uint64_t SymbolTableOffset = SectionDataEnd + IndirectSymbolSize; // The string table is written after symbol table. uint64_t StringTableOffset = @@ -675,6 +664,7 @@ MCSectionData::MCSectionData(const MCSection &_Section, MCAssembler *A) : Section(_Section), Alignment(1), Address(~UINT64_C(0)), + Size(~UINT64_C(0)), FileSize(~UINT64_C(0)) { if (A) @@ -701,26 +691,24 @@ MCAssembler::MCAssembler(raw_ostream &_OS) : OS(_OS) {} MCAssembler::~MCAssembler() { } -void MCAssembler::LayoutSection(MCSectionData &SD) { - uint64_t Offset = 0; +void MCAssembler::LayoutSection(MCSectionData &SD, unsigned NextAlign) { + uint64_t Address = SD.getAddress(); for (MCSectionData::iterator it = SD.begin(), ie = SD.end(); it != ie; ++it) { MCFragment &F = *it; - F.setOffset(Offset); + F.setOffset(Address - SD.getAddress()); // Evaluate fragment size. switch (F.getKind()) { case MCFragment::FT_Align: { MCAlignFragment &AF = cast(F); - uint64_t AlignedOffset = RoundUpToAlignment(Offset, AF.getAlignment()); - uint64_t PaddingBytes = AlignedOffset - Offset; - - if (PaddingBytes > AF.getMaxBytesToEmit()) + uint64_t Size = RoundUpToAlignment(Address, AF.getAlignment()) - Address; + if (Size > AF.getMaxBytesToEmit()) AF.setFileSize(0); else - AF.setFileSize(PaddingBytes); + AF.setFileSize(Size); break; } @@ -735,22 +723,24 @@ void MCAssembler::LayoutSection(MCSectionData &SD) { if (!OF.getOffset().isAbsolute()) llvm_unreachable("FIXME: Not yet implemented!"); uint64_t OrgOffset = OF.getOffset().getConstant(); + uint64_t Offset = Address - SD.getAddress(); // FIXME: We need a way to communicate this error. if (OrgOffset < Offset) llvm_report_error("invalid .org offset '" + Twine(OrgOffset) + - "' (section offset '" + Twine(Offset) + "'"); + "' (at offset '" + Twine(Offset) + "'"); F.setFileSize(OrgOffset - Offset); break; } } - Offset += F.getFileSize(); + Address += F.getFileSize(); } - // FIXME: Pad section? - SD.setFileSize(Offset); + // Set the section sizes. + SD.setSize(Address - SD.getAddress()); + SD.setFileSize(RoundUpToAlignment(Address, NextAlign) - SD.getAddress()); } /// 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) 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()); } void MCAssembler::Finish() { // Layout the sections and fragments. uint64_t Address = 0; - for (iterator it = begin(), ie = end(); it != ie; ++it) { - it->setAddress(Address); - LayoutSection(*it); - Address += it->getFileSize(); + for (iterator it = begin(), ie = end(); it != ie;) { + MCSectionData &SD = *it; + + // 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. diff --git a/test/MC/MachO/section-align-1.s b/test/MC/MachO/section-align-1.s new file mode 100644 index 00000000000..6a5e247c938 --- /dev/null +++ b/test/MC/MachO/section-align-1.s @@ -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: ]) diff --git a/test/MC/MachO/section-align-2.s b/test/MC/MachO/section-align-2.s new file mode 100644 index 00000000000..e0704734a8e --- /dev/null +++ b/test/MC/MachO/section-align-2.s @@ -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: ])