mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-22 10:42:39 +01:00
[yaml2obj][ELF] Add support for program headers
This change adds basic support for program headers. I need to do some testing which requires generating program headers but I can't use ld.lld or clang to produce programs that have headers. I'd also like to test some strange things that those programs may never produce. Patch by Jake Ehrlich Differential Revision: https://reviews.llvm.org/D35276 llvm-svn: 308520
This commit is contained in:
parent
992aad1a5d
commit
5fac88383c
@ -37,12 +37,14 @@ namespace ELFYAML {
|
||||
// In the future, these would probably be better suited by C++11 enum
|
||||
// class's with appropriate fixed underlying type.
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint16_t, ELF_ET)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_PT)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_EM)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFCLASS)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFDATA)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_ELFOSABI)
|
||||
// Just use 64, since it can hold 32-bit values too.
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint64_t, ELF_EF)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_PF)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_SHT)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint32_t, ELF_REL)
|
||||
LLVM_YAML_STRONG_TYPEDEF(uint8_t, ELF_RSS)
|
||||
@ -71,6 +73,18 @@ struct FileHeader {
|
||||
llvm::yaml::Hex64 Entry;
|
||||
};
|
||||
|
||||
struct SectionName {
|
||||
StringRef Section;
|
||||
};
|
||||
|
||||
struct ProgramHeader {
|
||||
ELF_PT Type;
|
||||
ELF_PF Flags;
|
||||
llvm::yaml::Hex64 VAddr;
|
||||
llvm::yaml::Hex64 PAddr;
|
||||
std::vector<SectionName> Sections;
|
||||
};
|
||||
|
||||
struct Symbol {
|
||||
StringRef Name;
|
||||
ELF_STT Type;
|
||||
@ -183,6 +197,7 @@ struct MipsABIFlags : Section {
|
||||
|
||||
struct Object {
|
||||
FileHeader Header;
|
||||
std::vector<ProgramHeader> ProgramHeaders;
|
||||
std::vector<std::unique_ptr<Section>> Sections;
|
||||
// Although in reality the symbols reside in a section, it is a lot
|
||||
// cleaner and nicer if we read them from the YAML as a separate
|
||||
@ -194,10 +209,12 @@ struct Object {
|
||||
} // end namespace ELFYAML
|
||||
} // end namespace llvm
|
||||
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::ProgramHeader)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::ELFYAML::Section>)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Symbol)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::Relocation)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionOrType)
|
||||
LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::ELFYAML::SectionName)
|
||||
|
||||
namespace llvm {
|
||||
namespace yaml {
|
||||
@ -207,6 +224,10 @@ struct ScalarEnumerationTraits<ELFYAML::ELF_ET> {
|
||||
static void enumeration(IO &IO, ELFYAML::ELF_ET &Value);
|
||||
};
|
||||
|
||||
template <> struct ScalarEnumerationTraits<ELFYAML::ELF_PT> {
|
||||
static void enumeration(IO &IO, ELFYAML::ELF_PT &Value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScalarEnumerationTraits<ELFYAML::ELF_EM> {
|
||||
static void enumeration(IO &IO, ELFYAML::ELF_EM &Value);
|
||||
@ -232,6 +253,10 @@ struct ScalarBitSetTraits<ELFYAML::ELF_EF> {
|
||||
static void bitset(IO &IO, ELFYAML::ELF_EF &Value);
|
||||
};
|
||||
|
||||
template <> struct ScalarBitSetTraits<ELFYAML::ELF_PF> {
|
||||
static void bitset(IO &IO, ELFYAML::ELF_PF &Value);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct ScalarEnumerationTraits<ELFYAML::ELF_SHT> {
|
||||
static void enumeration(IO &IO, ELFYAML::ELF_SHT &Value);
|
||||
@ -302,6 +327,10 @@ struct MappingTraits<ELFYAML::FileHeader> {
|
||||
static void mapping(IO &IO, ELFYAML::FileHeader &FileHdr);
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<ELFYAML::ProgramHeader> {
|
||||
static void mapping(IO &IO, ELFYAML::ProgramHeader &FileHdr);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct MappingTraits<ELFYAML::Symbol> {
|
||||
static void mapping(IO &IO, ELFYAML::Symbol &Symbol);
|
||||
@ -331,6 +360,10 @@ template <> struct MappingTraits<ELFYAML::SectionOrType> {
|
||||
static void mapping(IO &IO, ELFYAML::SectionOrType §ionOrType);
|
||||
};
|
||||
|
||||
template <> struct MappingTraits<ELFYAML::SectionName> {
|
||||
static void mapping(IO &IO, ELFYAML::SectionName §ionName);
|
||||
};
|
||||
|
||||
} // end namespace yaml
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -39,6 +39,21 @@ void ScalarEnumerationTraits<ELFYAML::ELF_ET>::enumeration(
|
||||
IO.enumFallback<Hex16>(Value);
|
||||
}
|
||||
|
||||
void ScalarEnumerationTraits<ELFYAML::ELF_PT>::enumeration(
|
||||
IO &IO, ELFYAML::ELF_PT &Value) {
|
||||
#define ECase(X) IO.enumCase(Value, #X, ELF::X)
|
||||
ECase(PT_NULL);
|
||||
ECase(PT_LOAD);
|
||||
ECase(PT_DYNAMIC);
|
||||
ECase(PT_INTERP);
|
||||
ECase(PT_NOTE);
|
||||
ECase(PT_SHLIB);
|
||||
ECase(PT_PHDR);
|
||||
ECase(PT_TLS);
|
||||
#undef ECase
|
||||
IO.enumFallback<Hex32>(Value);
|
||||
}
|
||||
|
||||
void ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(
|
||||
IO &IO, ELFYAML::ELF_EM &Value) {
|
||||
#define ECase(X) IO.enumCase(Value, #X, ELF::X)
|
||||
@ -412,6 +427,14 @@ void ScalarEnumerationTraits<ELFYAML::ELF_SHT>::enumeration(
|
||||
#undef ECase
|
||||
}
|
||||
|
||||
void ScalarBitSetTraits<ELFYAML::ELF_PF>::bitset(IO &IO,
|
||||
ELFYAML::ELF_PF &Value) {
|
||||
#define BCase(X) IO.bitSetCase(Value, #X, ELF::X)
|
||||
BCase(PF_X);
|
||||
BCase(PF_W);
|
||||
BCase(PF_R);
|
||||
}
|
||||
|
||||
void ScalarBitSetTraits<ELFYAML::ELF_SHF>::bitset(IO &IO,
|
||||
ELFYAML::ELF_SHF &Value) {
|
||||
const auto *Object = static_cast<ELFYAML::Object *>(IO.getContext());
|
||||
@ -649,6 +672,15 @@ void MappingTraits<ELFYAML::FileHeader>::mapping(IO &IO,
|
||||
IO.mapOptional("Entry", FileHdr.Entry, Hex64(0));
|
||||
}
|
||||
|
||||
void MappingTraits<ELFYAML::ProgramHeader>::mapping(
|
||||
IO &IO, ELFYAML::ProgramHeader &Phdr) {
|
||||
IO.mapRequired("Type", Phdr.Type);
|
||||
IO.mapOptional("Flags", Phdr.Flags, ELFYAML::ELF_PF(0));
|
||||
IO.mapOptional("Sections", Phdr.Sections);
|
||||
IO.mapOptional("VAddr", Phdr.VAddr, Hex64(0));
|
||||
IO.mapOptional("PAddr", Phdr.PAddr, Hex64(0));
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
struct NormalizedOther {
|
||||
@ -720,6 +752,11 @@ void MappingTraits<ELFYAML::SectionOrType>::mapping(
|
||||
IO.mapRequired("SectionOrType", sectionOrType.sectionNameOrType);
|
||||
}
|
||||
|
||||
void MappingTraits<ELFYAML::SectionName>::mapping(
|
||||
IO &IO, ELFYAML::SectionName §ionName) {
|
||||
IO.mapRequired("Section", sectionName.Section);
|
||||
}
|
||||
|
||||
static void sectionMapping(IO &IO, ELFYAML::MipsABIFlags &Section) {
|
||||
commonSectionMapping(IO, Section);
|
||||
IO.mapOptional("Version", Section.Version, Hex16(0));
|
||||
@ -837,6 +874,7 @@ void MappingTraits<ELFYAML::Object>::mapping(IO &IO, ELFYAML::Object &Object) {
|
||||
IO.setContext(&Object);
|
||||
IO.mapTag("!ELF", true);
|
||||
IO.mapRequired("FileHeader", Object.Header);
|
||||
IO.mapOptional("ProgramHeaders", Object.ProgramHeaders);
|
||||
IO.mapOptional("Sections", Object.Sections);
|
||||
IO.mapOptional("Symbols", Object.Symbols);
|
||||
IO.setContext(nullptr);
|
||||
|
39
test/tools/yaml2obj/program-header-nobits.yaml
Normal file
39
test/tools/yaml2obj/program-header-nobits.yaml
Normal file
@ -0,0 +1,39 @@
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: llvm-readobj -program-headers %t | FileCheck %s
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Content: "00000000"
|
||||
- Name: .after
|
||||
Type: SHT_NOBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Size: 64
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
Flags: [ PF_R ]
|
||||
Sections:
|
||||
- Section: .data
|
||||
- Section: .after
|
||||
|
||||
#CHECK: ProgramHeaders [
|
||||
#CHECK-NEXT: ProgramHeader {
|
||||
#CHECK-NEXT: Type: PT_LOAD
|
||||
#CHECK-NEXT: Offset:
|
||||
#CHECK-NEXT: VirtualAddress:
|
||||
#CHECK-NEXT: PhysicalAddress:
|
||||
#CHECK-NEXT: FileSize: 4
|
||||
#CHECK-NEXT: MemSize: 68
|
||||
#CHECK-NEXT: Flags [
|
||||
#CHECK-NEXT: PF_R
|
||||
#CHECK-NEXT: ]
|
||||
#CHECK-NEXT: Alignment:
|
||||
#CHECK-NEXT: }
|
||||
#CHECK-NEXT:]
|
67
test/tools/yaml2obj/program-header.yaml
Normal file
67
test/tools/yaml2obj/program-header.yaml
Normal file
@ -0,0 +1,67 @@
|
||||
# RUN: yaml2obj %s -o %t
|
||||
# RUN: llvm-readobj -program-headers %t | FileCheck %s
|
||||
|
||||
!ELF
|
||||
FileHeader:
|
||||
Class: ELFCLASS64
|
||||
Data: ELFDATA2LSB
|
||||
Type: ET_EXEC
|
||||
Machine: EM_X86_64
|
||||
Sections:
|
||||
- Name: .text
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
AddressAlign: 0x0000000000001000
|
||||
Content: "00000000"
|
||||
- Name: .init
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC, SHF_EXECINSTR ]
|
||||
Content: "00000000"
|
||||
AddressAlign: 0x0000000000000010
|
||||
- Name: .data
|
||||
Type: SHT_PROGBITS
|
||||
Flags: [ SHF_ALLOC ]
|
||||
Content: "00000000"
|
||||
AddressAlign: 0x0000000000001000
|
||||
ProgramHeaders:
|
||||
- Type: PT_LOAD
|
||||
Flags: [ PF_X, PF_R ]
|
||||
VAddr: 0xAAAA1000
|
||||
PAddr: 0xFFFF1000
|
||||
Sections:
|
||||
- Section: .text
|
||||
- Section: .init
|
||||
- Type: PT_LOAD
|
||||
Flags: [ PF_R ]
|
||||
VAddr: 0xAAAA2000
|
||||
PAddr: 0xFFFF2000
|
||||
Sections:
|
||||
- Section: .data
|
||||
|
||||
#CHECK: ProgramHeaders [
|
||||
#CHECK-NEXT: ProgramHeader {
|
||||
#CHECK-NEXT: Type: PT_LOAD
|
||||
#CHECK-NEXT: Offset: 0x1000
|
||||
#CHECK-NEXT: VirtualAddress: 0xAAAA1000
|
||||
#CHECK-NEXT: PhysicalAddress: 0xFFFF1000
|
||||
#CHECK-NEXT: FileSize: 20
|
||||
#CHECK-NEXT: MemSize: 20
|
||||
#CHECK-NEXT: Flags [
|
||||
#CHECK-NEXT: PF_R
|
||||
#CHECK-NEXT: PF_X
|
||||
#CHECK-NEXT: ]
|
||||
#CHECK-NEXT: Alignment: 4096
|
||||
#CHECK-NEXT: }
|
||||
#CHECK-NEXT: ProgramHeader {
|
||||
#CHECK-NEXT: Type: PT_LOAD
|
||||
#CHECK-NEXT: Offset: 0x2000
|
||||
#CHECK-NEXT: VirtualAddress: 0xAAAA2000
|
||||
#CHECK-NEXT: PhysicalAddress: 0xFFFF2000
|
||||
#CHECK-NEXT: FileSize: 4
|
||||
#CHECK-NEXT: MemSize: 4
|
||||
#CHECK-NEXT: Flags [
|
||||
#CHECK-NEXT: PF_R
|
||||
#CHECK-NEXT: ]
|
||||
#CHECK-NEXT: Alignment: 4096
|
||||
#CHECK-NEXT: }
|
||||
#CHECK-NEXT:]
|
@ -99,6 +99,7 @@ namespace {
|
||||
template <class ELFT>
|
||||
class ELFState {
|
||||
typedef typename object::ELFFile<ELFT>::Elf_Ehdr Elf_Ehdr;
|
||||
typedef typename object::ELFFile<ELFT>::Elf_Phdr Elf_Phdr;
|
||||
typedef typename object::ELFFile<ELFT>::Elf_Shdr Elf_Shdr;
|
||||
typedef typename object::ELFFile<ELFT>::Elf_Sym Elf_Sym;
|
||||
typedef typename object::ELFFile<ELFT>::Elf_Rel Elf_Rel;
|
||||
@ -118,6 +119,7 @@ class ELFState {
|
||||
bool buildSymbolIndex(std::size_t &StartIndex,
|
||||
const std::vector<ELFYAML::Symbol> &Symbols);
|
||||
void initELFHeader(Elf_Ehdr &Header);
|
||||
void initProgramHeaders(std::vector<Elf_Phdr> &PHeaders);
|
||||
bool initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
|
||||
ContiguousBlobAccumulator &CBA);
|
||||
void initSymtabSectionHeader(Elf_Shdr &SHeader,
|
||||
@ -125,6 +127,8 @@ class ELFState {
|
||||
void initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
|
||||
StringTableBuilder &STB,
|
||||
ContiguousBlobAccumulator &CBA);
|
||||
void setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
|
||||
std::vector<Elf_Shdr> &SHeaders);
|
||||
void addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
|
||||
std::vector<Elf_Sym> &Syms, unsigned SymbolBinding);
|
||||
void writeSectionContent(Elf_Shdr &SHeader,
|
||||
@ -173,15 +177,31 @@ void ELFState<ELFT>::initELFHeader(Elf_Ehdr &Header) {
|
||||
Header.e_machine = Doc.Header.Machine;
|
||||
Header.e_version = EV_CURRENT;
|
||||
Header.e_entry = Doc.Header.Entry;
|
||||
Header.e_phoff = sizeof(Header);
|
||||
Header.e_flags = Doc.Header.Flags;
|
||||
Header.e_ehsize = sizeof(Elf_Ehdr);
|
||||
Header.e_phentsize = sizeof(Elf_Phdr);
|
||||
Header.e_phnum = Doc.ProgramHeaders.size();
|
||||
Header.e_shentsize = sizeof(Elf_Shdr);
|
||||
// Immediately following the ELF header.
|
||||
Header.e_shoff = sizeof(Header);
|
||||
// Immediately following the ELF header and program headers.
|
||||
Header.e_shoff =
|
||||
sizeof(Header) + sizeof(Elf_Phdr) * Doc.ProgramHeaders.size();
|
||||
Header.e_shnum = getSectionCount();
|
||||
Header.e_shstrndx = getDotShStrTabSecNo();
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFState<ELFT>::initProgramHeaders(std::vector<Elf_Phdr> &PHeaders) {
|
||||
for (const auto &YamlPhdr : Doc.ProgramHeaders) {
|
||||
Elf_Phdr Phdr;
|
||||
Phdr.p_type = YamlPhdr.Type;
|
||||
Phdr.p_flags = YamlPhdr.Flags;
|
||||
Phdr.p_vaddr = YamlPhdr.VAddr;
|
||||
Phdr.p_paddr = YamlPhdr.PAddr;
|
||||
PHeaders.push_back(Phdr);
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
bool ELFState<ELFT>::initSectionHeaders(std::vector<Elf_Shdr> &SHeaders,
|
||||
ContiguousBlobAccumulator &CBA) {
|
||||
@ -310,6 +330,67 @@ void ELFState<ELFT>::initStrtabSectionHeader(Elf_Shdr &SHeader, StringRef Name,
|
||||
SHeader.sh_addralign = 1;
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFState<ELFT>::setProgramHeaderLayout(std::vector<Elf_Phdr> &PHeaders,
|
||||
std::vector<Elf_Shdr> &SHeaders) {
|
||||
uint32_t PhdrIdx = 0;
|
||||
for (auto &YamlPhdr : Doc.ProgramHeaders) {
|
||||
auto &PHeader = PHeaders[PhdrIdx++];
|
||||
|
||||
if (YamlPhdr.Sections.size())
|
||||
PHeader.p_offset = UINT32_MAX;
|
||||
else
|
||||
PHeader.p_offset = 0;
|
||||
|
||||
// Find the minimum offset for the program header.
|
||||
for (auto SecName : YamlPhdr.Sections) {
|
||||
uint32_t Index = 0;
|
||||
SN2I.lookup(SecName.Section, Index);
|
||||
const auto &SHeader = SHeaders[Index];
|
||||
PHeader.p_offset = std::min(PHeader.p_offset, SHeader.sh_offset);
|
||||
}
|
||||
|
||||
// Find the maximum offset of the end of a section in order to set p_filesz.
|
||||
PHeader.p_filesz = 0;
|
||||
for (auto SecName : YamlPhdr.Sections) {
|
||||
uint32_t Index = 0;
|
||||
SN2I.lookup(SecName.Section, Index);
|
||||
const auto &SHeader = SHeaders[Index];
|
||||
uint64_t EndOfSection;
|
||||
if (SHeader.sh_type == llvm::ELF::SHT_NOBITS)
|
||||
EndOfSection = SHeader.sh_offset;
|
||||
else
|
||||
EndOfSection = SHeader.sh_offset + SHeader.sh_size;
|
||||
uint64_t EndOfSegment = PHeader.p_offset + PHeader.p_filesz;
|
||||
EndOfSegment = std::max(EndOfSegment, EndOfSection);
|
||||
PHeader.p_filesz = EndOfSegment - PHeader.p_offset;
|
||||
}
|
||||
|
||||
// Find the memory size by adding the size of sections at the end of the
|
||||
// segment. These should be empty (size of zero) and NOBITS sections.
|
||||
PHeader.p_memsz = PHeader.p_filesz;
|
||||
for (auto SecName : YamlPhdr.Sections) {
|
||||
uint32_t Index = 0;
|
||||
SN2I.lookup(SecName.Section, Index);
|
||||
const auto &SHeader = SHeaders[Index];
|
||||
if (SHeader.sh_offset == PHeader.p_offset + PHeader.p_filesz)
|
||||
PHeader.p_memsz += SHeader.sh_size;
|
||||
}
|
||||
|
||||
// Set the alignment of the segment to be the same as the maximum alignment
|
||||
// of the the sections with the same offset so that by default the segment
|
||||
// has a valid and sensible alignment.
|
||||
PHeader.p_align = 1;
|
||||
for (auto SecName : YamlPhdr.Sections) {
|
||||
uint32_t Index = 0;
|
||||
SN2I.lookup(SecName.Section, Index);
|
||||
const auto &SHeader = SHeaders[Index];
|
||||
if (SHeader.sh_offset == PHeader.p_offset)
|
||||
PHeader.p_align = std::max(PHeader.p_align, SHeader.sh_addralign);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <class ELFT>
|
||||
void ELFState<ELFT>::addSymbols(const std::vector<ELFYAML::Symbol> &Symbols,
|
||||
std::vector<Elf_Sym> &Syms,
|
||||
@ -508,12 +589,15 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) {
|
||||
State.initELFHeader(Header);
|
||||
|
||||
// TODO: Flesh out section header support.
|
||||
// TODO: Program headers.
|
||||
|
||||
std::vector<Elf_Phdr> PHeaders;
|
||||
State.initProgramHeaders(PHeaders);
|
||||
|
||||
// XXX: This offset is tightly coupled with the order that we write
|
||||
// things to `OS`.
|
||||
const size_t SectionContentBeginOffset =
|
||||
Header.e_ehsize + Header.e_shentsize * Header.e_shnum;
|
||||
const size_t SectionContentBeginOffset = Header.e_ehsize +
|
||||
Header.e_phentsize * Header.e_phnum +
|
||||
Header.e_shentsize * Header.e_shnum;
|
||||
ContiguousBlobAccumulator CBA(SectionContentBeginOffset);
|
||||
|
||||
// Doc might not contain .symtab, .strtab and .shstrtab sections,
|
||||
@ -543,7 +627,11 @@ int ELFState<ELFT>::writeELF(raw_ostream &OS, const ELFYAML::Object &Doc) {
|
||||
CBA);
|
||||
SHeaders.push_back(ShStrTabSHeader);
|
||||
|
||||
// Now we can decide segment offsets
|
||||
State.setProgramHeaderLayout(PHeaders, SHeaders);
|
||||
|
||||
OS.write((const char *)&Header, sizeof(Header));
|
||||
writeArrayData(OS, makeArrayRef(PHeaders));
|
||||
writeArrayData(OS, makeArrayRef(SHeaders));
|
||||
CBA.writeBlobToStream(OS);
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user