35 #pragma warning(disable : 4996)
56 #if defined(__has_include) && __has_include(<gsl/narrow>)
58 using gsl::narrow_cast;
61 #define narrow_cast static_cast
78 dos_header_{0}, coff_header_{0}, optional_header_{0}, win_header_{0},
97 bool load(
const std::string& file_name)
100 stream.open(file_name, std::ios::in | std::ios::binary);
115 bool load(std::istream& stream)
123 if (dos_header_->load(stream)) {
135 if (coff_header_->load(stream)) {
138 static const std::vector<uint16_t> machines = {
151 if (std::find(machines.begin(), machines.end(),
152 coff_header_->get_machine()) == machines.end()) {
169 static const std::vector<uint16_t> machines = {
170 CEVA_MACHINE_XC4210_LIB,
171 CEVA_MACHINE_XC4210_OBJ,
173 if (std::find(machines.begin(), machines.end(),
174 coff_header_->get_machine()) != machines.end()) {
185 if (!coff_header_->load(stream)) {
191 static const std::vector<uint16_t> target_ids = {
192 TMS470, TMS320C5400, TMS320C6000, TMS320C5500,
193 TMS320C2800, MSP430, TMS320C5500plus,
195 if (std::find(target_ids.begin(), target_ids.end(),
196 coff_header_->get_target_id()) != target_ids.end()) {
205 if (!coff_header_->load(stream)) {
211 if (coff_header_->get_optional_header_size()) {
213 std::streampos pos = stream.tellg();
215 if (!optional_header_->load(stream)) {
220 delete optional_header_;
223 if (!optional_header_->load(stream)) {
239 if (!optional_header_->load(stream)) {
250 optional_header_->get_magic() == OH_MAGIC_PE32ROM) {
255 if (!win_header_->load(stream)) {
256 delete optional_header_;
257 optional_header_ = 0;
263 directories_.load(stream);
273 std::streampos pos = stream.tellg();
274 if (!load_strings(stream, coff_header_)) {
279 if (!load_symbols(stream, coff_header_)) {
285 if (!load_section_headers(stream)) {
290 if (!directories_.load_data(stream)) {
310 bool save(
const std::string& file_name)
312 std::ofstream stream;
313 stream.open(file_name, std::ios::out | std::ios::binary);
328 bool save(std::ostream& stream)
331 std::stringstream tmp_stream(std::ios::in | std::ios::out |
336 if (!save_to_stream(tmp_stream)) {
340 return compute_win_header_checksum(tmp_stream, stream);
343 return save_to_stream(stream);
357 architecture_ = architecture;
366 coff_header_->set_machine(CEVA_MACHINE_XC4210_OBJ);
371 coff_header_->set_target_id(TMS320C2800);
394 if (optional_header_) {
395 delete optional_header_;
405 optional_header_->set_magic(magic);
414 coff_header_->set_optional_header_size(narrow_cast<uint16_t>(
415 optional_header_->get_sizeof() + win_header_->get_sizeof() +
455 return optional_header_;
497 sec->set_index(narrow_cast<uint32_t>(sections_.size()));
499 sections_.push_back(sec);
528 new directory(narrow_cast<uint32_t>(directories_.size()));
529 d->set_virtual_address(rva_and_size.virtual_address);
530 d->set_size(rva_and_size.size);
531 directories_.push_back(d);
543 if (optional_header_ &&
558 switch (coff_header_->get_target_id()) {
584 clean_unused_spaces();
585 populate_data_pages();
589 populate_data_pages();
590 apply_file_alignment();
591 populate_data_pages();
610 if (optional_header_) {
611 delete optional_header_;
612 optional_header_ = 0;
620 clean_unused_spaces();
624 directories_.clean();
631 void create_win_header()
637 win_header_ =
new win_header_impl<win_header_pe_plus>;
640 optional_header_->get_magic() == OH_MAGIC_PE32ROM) {
641 win_header_ =
new win_header_impl<win_header_pe>;
646 bool load_section_headers(std::istream& stream)
648 std::streampos pos = stream.tellg();
649 for (
int i = 0; i < coff_header_->get_sections_count(); ++i) {
650 std::unique_ptr<section> sec;
651 switch (architecture_) {
654 sec = std::make_unique<section_impl>(
this,
this,
this);
657 sec = std::make_unique<section_impl_ti>(
this,
this,
this);
660 sec = std::make_unique<section_impl>(
this,
this,
this);
663 if (!(sec->load(stream, i * sec->get_sizeof() + pos))) {
667 sections_.push_back(sec.release());
674 bool save_to_stream(std::ostream& stream)
680 coff_header_->set_sections_count(
681 narrow_cast<uint16_t>(sections_.size()));
682 if (symbols_.size() > 0) {
683 coff_header_->set_symbols_count(
684 symbols_.back().get_index() +
685 symbols_.back().get_aux_symbols_number() + 1);
688 coff_header_->set_symbols_count(0);
690 coff_header_->set_optional_header_size(0);
691 if (optional_header_) {
692 coff_header_->set_optional_header_size(
693 coff_header_->get_optional_header_size() +
694 narrow_cast<uint16_t>(optional_header_->get_sizeof()));
697 win_header_->set_number_of_rva_and_sizes(
698 narrow_cast<uint32_t>(directories_.size()));
699 coff_header_->set_optional_header_size(narrow_cast<uint16_t>(
700 coff_header_->get_optional_header_size() +
701 win_header_->get_sizeof() + directories_.get_sizeof()));
705 dos_header_->save(stream);
708 coff_header_->save(stream);
710 if (optional_header_) {
711 optional_header_->save(stream);
716 win_header_->save(stream);
717 directories_.save(stream);
722 for (
auto sec : sections_) {
723 sec->save_header(stream);
726 for (
auto dp : data_pages_) {
730 sec = sections_[dp.index];
731 sec->save_data(stream);
733 case DATA_PAGE_RELOCATIONS:
734 sec = sections_[dp.index];
735 sec->save_relocations(stream);
737 case DATA_PAGE_LINE_NUMBERS:
738 sec = sections_[dp.index];
739 sec->save_line_numbers(stream);
741 case DATA_PAGE_DIRECTORY:
742 directories_[dp.index]->save_data(stream);
744 case DATA_PAGE_UNUSED:
745 stream.write(unused_spaces_[dp.index].data,
746 unused_spaces_[dp.index].size);
751 save_symbols(stream);
753 save_strings(stream);
759 bool compute_win_header_checksum(std::istream& src, std::ostream& dst)
761 if (!dos_header_ || !coff_header_ || !optional_header_ ||
767 src.seekg(0, std::ios::end);
768 uint32_t file_size = narrow_cast<uint32_t>(src.tellg());
772 uint32_t chk_offset =
773 dos_header_->get_pe_sign_location() + 4 +
774 narrow_cast<uint32_t>(coff_header_->get_sizeof()) +
775 narrow_cast<uint32_t>(optional_header_->get_sizeof()) +
780 for (uint32_t i = 0; i < file_size; i += 2) {
781 char bytes[2] = {0, 0};
783 dst.write(bytes, src.gcount());
784 uint16_t word = *(
reinterpret_cast<uint16_t*
>(bytes));
785 if ((i >= chk_offset) && (i < chk_offset + 4)) {
789 chk = (chk >> 16) + (chk & 0xffff);
791 chk = (uint16_t)(((chk >> 16) + chk) & 0xffff);
795 dst.seekp(chk_offset);
796 dst.write(
reinterpret_cast<char*
>(&chk), 4);
801 void populate_data_pages()
804 for (
auto sec : sections_) {
805 if (sec->get_data_offset() > 0 || sec->get_data()) {
806 data_pages_.push_back(
807 data_page{DATA_PAGE_RAW, sec->get_data_offset(),
808 sec->get_data_size(), sec->get_index()});
810 if (sec->get_reloc_offset() > 0 || sec->get_reloc_count() > 0) {
811 data_pages_.push_back(data_page{
812 DATA_PAGE_RELOCATIONS, sec->get_reloc_offset(),
813 sec->get_relocations_filesize(), sec->get_index()});
816 (sec->get_line_num_count() > 0)) {
817 data_pages_.push_back(data_page{
818 DATA_PAGE_LINE_NUMBERS, sec->get_line_num_offset(),
819 sec->get_line_numbers_filesize(), sec->get_index()});
822 for (
auto d : directories_) {
823 if (d->get_data_filesize() > 0) {
824 data_pages_.push_back(data_page{DATA_PAGE_DIRECTORY,
825 d->get_virtual_address(),
826 d->get_size(), d->get_index()});
830 for (uint32_t i = 0; i < unused_spaces_.size(); i++) {
831 data_pages_.push_back(data_page{DATA_PAGE_UNUSED,
832 unused_spaces_[i].offset,
833 unused_spaces_[i].size, i});
836 std::sort(data_pages_.begin(), data_pages_.end(),
837 [](
const data_page& a,
const data_page& b) {
838 if (a.offset != b.offset) {
839 return a.offset < b.offset;
841 if (a.type != b.type) {
842 return a.type < b.type;
844 return a.index < b.index;
849 uint32_t get_header_end_offset()
853 offset = dos_header_->get_pe_sign_location();
857 offset += narrow_cast<uint32_t>(coff_header_->get_sizeof());
859 if (optional_header_) {
860 offset += narrow_cast<uint32_t>(optional_header_->get_sizeof());
863 offset += narrow_cast<uint32_t>(win_header_->get_sizeof());
865 offset += directories_.get_sizeof();
866 for (
auto sec : sections_) {
867 offset += narrow_cast<uint32_t>(sec->get_sizeof());
873 void compute_offsets()
875 uint32_t offset = get_header_end_offset();
877 for (
auto dp : data_pages_) {
878 auto sec = sections_[dp.index];
881 if (sec->get_data()) {
882 sec->set_data_offset(offset);
883 offset += sec->get_data_size();
885 else if (sec->get_data_offset() != 0) {
886 sec->set_data_offset(offset);
889 case DATA_PAGE_RELOCATIONS:
890 if (sec->get_reloc_count() > 0) {
891 sec->set_reloc_offset(offset);
894 sec->set_reloc_offset(0);
896 offset += sec->get_relocations_filesize();
898 case DATA_PAGE_LINE_NUMBERS:
899 if (sec->get_line_num_count() > 0) {
900 sec->set_line_num_offset(offset);
903 sec->set_line_num_offset(0);
905 offset += sec->get_line_numbers_filesize();
907 case DATA_PAGE_DIRECTORY:
908 if (directories_[dp.index]->get_data_filesize() > 0) {
909 if (directories_[dp.index]->get_virtual_address() != 0) {
910 directories_[dp.index]->set_virtual_address(offset);
912 offset += directories_[dp.index]->get_data_filesize();
915 case DATA_PAGE_UNUSED:
916 offset += unused_spaces_[dp.index].size;
921 if (symbols_.size() == 0) {
924 coff_header_->set_symbol_table_offset(offset);
928 void apply_file_alignment()
933 uint32_t file_alignment = win_header_->get_file_alignment();
934 uint32_t previous_offset = get_header_end_offset();
935 uint32_t previous_size = previous_offset;
936 const data_page* previous_dp =
nullptr;
937 for (
auto dp = data_pages_.begin(); dp != data_pages_.end(); dp++) {
938 if ((previous_size % file_alignment) != 0) {
940 file_alignment - (previous_size % file_alignment);
941 if (previous_dp && previous_dp->type == DATA_PAGE_RAW) {
943 char* padding =
new char[size];
945 std::memset(padding, 0, size);
946 sections_[previous_dp->index]->append_data(padding,
952 add_unused_space(previous_offset, size);
956 previous_size = dp->size;
957 if (dp->offset > 0) {
958 previous_offset = dp->offset + dp->size;
964 void clean_unused_spaces()
966 for (
auto us : unused_spaces_) {
969 unused_spaces_.clear();
974 add_unused_space(uint32_t offset, uint32_t size, uint8_t padding_byte = 0)
977 us.data =
new char[size];
979 std::memset(us.data, padding_byte, size);
982 unused_spaces_.push_back(us);
991 DATA_PAGE_RELOCATIONS,
992 DATA_PAGE_LINE_NUMBERS,
1016 dos_header* dos_header_;
1017 coff_header* coff_header_;
1018 optional_header* optional_header_;
1019 win_header* win_header_;
1020 directories directories_;
1022 std::vector<unused_space> unused_spaces_;
1023 std::vector<data_page> data_pages_;
1029 #pragma warning(pop)
Class for accessing the strings table.
Class for accessing the symbol table.
The COFFI library's main class.
bool load(const std::string &file_name)
Initializes the coffi object by loading data from COFF binary file.
coffi(const coffi &)=delete
Discards the copy constructor.
section * add_section(const std::string &name)
Add a COFF section.
bool is_PE32_plus()
PE32+ format check.
win_header * get_win_header()
Returns the Windows NT header.
optional_header * get_optional_header()
Returns the optional COFF header.
const win_header * get_win_header() const
Returns the Windows NT header.
coff_header * get_header()
Returns the COFF header.
const optional_header * get_optional_header() const
Returns the optional COFF header.
bool save(const std::string &file_name)
Creates a file in COFF binary format.
sections & get_sections()
Returns a list of the COFF sections.
const coff_header * get_header() const
Returns the COFF header.
coffi_architecture_t get_architecture() const
Returns the coffi object architecture.
bool save(std::ostream &stream)
Creates a file in COFF binary format.
const sections & get_sections() const
Returns a list of the COFF sections.
int get_addressable_unit() const
Returns the character type size in bytes.
directory * add_directory(const image_data_directory &rva_and_size)
Add a PE data directory.
void create(coffi_architecture_t architecture)
Cleans and/or initializes the coffi object.
bool load(std::istream &stream)
Initializes the coffi object by loading data from COFF binary file.
const dos_header * get_msdos_header() const
Returns the MS-DOS header.
const directories & get_directories() const
Returns a list of the PE data directories.
dos_header * get_msdos_header()
Returns the MS-DOS header.
void create_optional_header(uint16_t magic=OH_MAGIC_PE32)
Initializes an optional header for the coffi object.
void layout()
Performs the layout of the file.
directories & get_directories()
Returns a list of the PE data directories.
List of image data directories.
Class for accessing an image data directory.
Class for accessing a COFF section, for the Texas Instruments format.
Class for accessing a COFF section, for the PE format.
Interface class for accessing a COFF section, for all the COFF architectures.
Interface that gives the headers and sections.
COFFI library classes for the PE data directories.
COFFI library classes for the COFF sections.
COFFI library classes for the COFF strings and string table.
COFFI library classes for the COFF symbols and symbol table.
COFFI library basic structures and types.
#define OH_MAGIC_PE32
PE32 format.
#define IMAGE_FILE_MACHINE_EBC
EFI byte code.
#define IMAGE_FILE_MACHINE_ARMNT
ARMv7( or higher ) Thumb mode only.
#define IMAGE_FILE_MACHINE_I386
Intel 386 or later processors and compatible processors.
#define IMAGE_FILE_MACHINE_MIPSFPU
MIPS with FPU.
#define OH_MAGIC_PE32PLUS
PE32+ format.
#define IMAGE_FILE_MACHINE_SH4
Hitachi SH4.
#define IMAGE_FILE_MACHINE_POWERPC
Power PC little endian.
#define IMAGE_FILE_MACHINE_THUMB
ARM or Thumb( "interworking" )
#define IMAGE_FILE_MACHINE_MIPSFPU16
MIPS16 with FPU.
#define IMAGE_FILE_MACHINE_ARM
ARM little endian.
#define IMAGE_FILE_MACHINE_SH3
Hitachi SH3.
#define IMAGE_FILE_MACHINE_MIPS16
MIPS16.
#define IMAGE_FILE_MACHINE_SH3DSP
Hitachi SH3 DSP.
#define IMAGE_FILE_MACHINE_AM33
Matsushita AM33.
#define IMAGE_FILE_MACHINE_AMD64
x64
#define IMAGE_FILE_MACHINE_IA64
Intel Itanium processor family.
#define IMAGE_FILE_MACHINE_ARM64
ARMv8 in 64 - bit mode.
#define IMAGE_FILE_MACHINE_SH5
Hitachi SH5.
#define IMAGE_FILE_MACHINE_POWERPCFP
Power PC with floating point support.
#define IMAGE_FILE_MACHINE_WCEMIPSV2
MIPS little - endian WCE v2.
#define IMAGE_FILE_MACHINE_R4000
MIPS little endian.
#define IMAGE_FILE_MACHINE_M32R
Mitsubishi M32R little endian.
coffi_architecture_t
Architectures supported by COFFI.
@ COFFI_ARCHITECTURE_PE
Windows portable executable (PE or PE+)
@ COFFI_ARCHITECTURE_NONE
Architecture unknown, or file not initialized.
@ COFFI_ARCHITECTURE_CEVA
CEVA Inc.
@ COFFI_ARCHITECTURE_TI
Texas Instruments.