x86/efi: Use generic PE/COFF structures

Adapted x86 efi parser and mkreloc utility to use generic PE header
(efi/pe.h), instead of locally defined structures for each component.

Signed-off-by: Nikola Jelic <nikola.jelic@rt-rk.com>
Signed-off-by: Milan Djokic <milan.djokic@rt-rk.com>
Acked-by: Andrew Cooper <andrew.cooper3@citrix.com>
Acked-by: Daniel P. Smith <dpsmith@apertussolutions.com>
This commit is contained in:
Nikola Jelic authored and Andrew Cooper committed 2024-09-24 11:12:23 +01:00
1 parent 6a039b0500
commit f7f42accbb
3 files changed
+63 -166

No files matched your search

+2
View File
@@ -88,6 +88,8 @@ extra-y += xen.lds
hostprogs-y += boot/mkelf32
hostprogs-y += efi/mkreloc
$(obj)/efi/mkreloc: HOSTCFLAGS += -I$(srctree)/include
# Allows usercopy.c to include itself
$(obj)/usercopy.o: CFLAGS-y += -iquote .
+43 -94
View File
@@ -9,45 +9,7 @@
#include <sys/mman.h>
#include <unistd.h>
struct mz_hdr {
uint16_t signature;
#define MZ_SIGNATURE 0x5a4d
uint16_t last_page_size;
uint16_t page_count;
uint16_t relocation_count;
uint16_t header_paras;
uint16_t min_paras;
uint16_t max_paras;
uint16_t entry_ss;
uint16_t entry_sp;
uint16_t checksum;
uint16_t entry_ip;
uint16_t entry_cs;
uint16_t relocations;
uint16_t overlay;
uint8_t reserved[32];
uint32_t extended_header_base;
};
struct pe_hdr {
uint32_t signature;
#define PE_SIGNATURE 0x00004550
uint16_t cpu;
uint16_t section_count;
int32_t timestamp;
uint32_t symbols_file_offset;
uint32_t symbol_count;
uint16_t opt_hdr_size;
uint16_t flags;
struct {
uint16_t magic;
#define PE_MAGIC_EXE32 0x010b
#define PE_MAGIC_EXE32PLUS 0x020b
uint8_t linker_major, linker_minor;
uint32_t code_size, data_size, bss_size;
uint32_t entry_rva, code_rva, data_rva;
} opt_hdr;
};
#include <efi/pe.h>
#define PE_PAGE_SIZE 0x1000
@@ -55,22 +17,6 @@ struct pe_hdr {
#define PE_BASE_RELOC_HIGHLOW 3
#define PE_BASE_RELOC_DIR64 10
struct coff_section {
char name[8];
uint32_t size;
uint32_t rva;
uint32_t file_size;
uint32_t file_offset;
uint32_t relocation_file_offset;
uint32_t line_number_file_offset;
uint16_t relocation_count;
uint16_t line_number_count;
uint32_t flags;
#define COFF_SECTION_BSS 0x00000080U
#define COFF_SECTION_DISCARDABLE 0x02000000U
#define COFF_SECTION_WRITEABLE 0x80000000U
};
static void usage(const char *cmd, int rc)
{
fprintf(rc ? stderr : stdout,
@@ -80,7 +26,7 @@ static void usage(const char *cmd, int rc)
}
static unsigned int load(const char *name, int *handle,
struct coff_section **sections,
struct section_header **sections,
uint_fast64_t *image_base,
uint32_t *image_size,
unsigned int *width)
@@ -88,6 +34,7 @@ static unsigned int load(const char *name, int *handle,
int in = open(name, O_RDONLY);
struct mz_hdr mz_hdr;
struct pe_hdr pe_hdr;
struct pe32_opt_hdr pe32_opt_hdr;
uint32_t base;
if ( in < 0 ||
@@ -96,16 +43,18 @@ static unsigned int load(const char *name, int *handle,
perror(name);
exit(2);
}
if ( mz_hdr.signature != MZ_SIGNATURE ||
mz_hdr.relocations < sizeof(mz_hdr) ||
!mz_hdr.extended_header_base )
if ( mz_hdr.magic != MZ_MAGIC ||
mz_hdr.reloc_table_offset < sizeof(mz_hdr) ||
!mz_hdr.peaddr )
{
fprintf(stderr, "%s: Wrong DOS file format\n", name);
exit(2);
}
if ( lseek(in, mz_hdr.extended_header_base, SEEK_SET) < 0 ||
if ( lseek(in, mz_hdr.peaddr, SEEK_SET) < 0 ||
read(in, &pe_hdr, sizeof(pe_hdr)) != sizeof(pe_hdr) ||
read(in, &pe32_opt_hdr, sizeof(pe32_opt_hdr)) != sizeof(pe32_opt_hdr) ||
read(in, &base, sizeof(base)) != sizeof(base) ||
/*
* Luckily the image size field lives at the
@@ -117,35 +66,35 @@ static unsigned int load(const char *name, int *handle,
perror(name);
exit(3);
}
switch ( (pe_hdr.signature == PE_SIGNATURE &&
pe_hdr.opt_hdr_size > sizeof(pe_hdr.opt_hdr)) *
pe_hdr.opt_hdr.magic )
switch ( (pe_hdr.magic == PE_MAGIC &&
pe_hdr.opt_hdr_size > sizeof(pe32_opt_hdr)) *
pe32_opt_hdr.magic )
{
case PE_MAGIC_EXE32:
case PE_OPT_MAGIC_PE32:
*width = 32;
*image_base = base;
break;
case PE_MAGIC_EXE32PLUS:
case PE_OPT_MAGIC_PE32PLUS:
*width = 64;
*image_base = ((uint64_t)base << 32) | pe_hdr.opt_hdr.data_rva;
*image_base = ((uint64_t)base << 32) | pe32_opt_hdr.data_base;
break;
default:
fprintf(stderr, "%s: Wrong PE file format\n", name);
exit(3);
}
*sections = malloc(pe_hdr.section_count * sizeof(**sections));
*sections = malloc(pe_hdr.sections * sizeof(**sections));
if ( !*sections )
{
perror(NULL);
exit(4);
}
if ( lseek(in,
mz_hdr.extended_header_base + offsetof(struct pe_hdr, opt_hdr) +
pe_hdr.opt_hdr_size,
if ( lseek(in, mz_hdr.peaddr + sizeof(pe_hdr) + pe_hdr.opt_hdr_size,
SEEK_SET) < 0 ||
read(in, *sections, pe_hdr.section_count * sizeof(**sections)) !=
pe_hdr.section_count * sizeof(**sections) )
read(in, *sections, pe_hdr.sections * sizeof(**sections)) !=
pe_hdr.sections * sizeof(**sections) )
{
perror(name);
exit(4);
@@ -153,12 +102,12 @@ static unsigned int load(const char *name, int *handle,
*handle = in;
return pe_hdr.section_count;
return pe_hdr.sections;
}
static long page_size;
static const void *map_section(const struct coff_section *sec, int in,
static const void *map_section(const struct section_header *sec, int in,
const char *name)
{
const char *ptr;
@@ -166,10 +115,10 @@ static const void *map_section(const struct coff_section *sec, int in,
if ( !page_size )
page_size = sysconf(_SC_PAGESIZE);
offs = sec->file_offset & (page_size - 1);
offs = sec->data_addr & (page_size - 1);
ptr = mmap(0, offs + sec->file_size, PROT_READ, MAP_PRIVATE, in,
sec->file_offset - offs);
ptr = mmap(0, offs + sec->raw_data_size, PROT_READ, MAP_PRIVATE, in,
sec->data_addr - offs);
if ( ptr == MAP_FAILED )
{
perror(name);
@@ -179,15 +128,15 @@ static const void *map_section(const struct coff_section *sec, int in,
return ptr + offs;
}
static void unmap_section(const void *ptr, const struct coff_section *sec)
static void unmap_section(const void *ptr, const struct section_header *sec)
{
unsigned long offs = sec->file_offset & (page_size - 1);
unsigned long offs = sec->data_addr & (page_size - 1);
munmap((char *)ptr - offs, offs + sec->file_size);
munmap((char *)ptr - offs, offs + sec->raw_data_size);
}
static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
const struct coff_section *sec,
const struct section_header *sec,
int_fast64_t diff, unsigned int width,
uint_fast64_t base, uint_fast64_t end)
{
@@ -208,7 +157,7 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
while ( !(diff & (((int_fast64_t)1 << ((disp + 1) * CHAR_BIT)) - 1)) )
++disp;
for ( i = 0; i < sec->file_size; ++i )
for ( i = 0; i < sec->raw_data_size; ++i )
{
uint_fast32_t rva;
union {
@@ -222,7 +171,7 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
if ( ptr1[i] == ptr2[i] )
continue;
if ( i < disp || i + width - disp > sec->file_size )
if ( i < disp || i + width - disp > sec->raw_data_size )
{
fprintf(stderr,
"Bogus difference at %.8s:%08" PRIxFAST32 "\n",
@@ -250,11 +199,11 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
reloc_size += reloc_size & 2;
if ( reloc_size )
printf("\t.equ rva_%08" PRIxFAST32 "_relocs,"
" %#08" PRIxFAST32 "\n",
" %#08" PRIxFAST32 "\n",
cur_rva, reloc_size);
printf("\t.balign 4\n"
"\t.long %#08" PRIxFAST32 ","
" rva_%08" PRIxFAST32 "_relocs\n",
" rva_%08" PRIxFAST32 "_relocs\n",
rva, rva);
cur_rva = rva;
reloc_size = 8;
@@ -267,7 +216,7 @@ static void diff_sections(const unsigned char *ptr1, const unsigned char *ptr2,
exit(3);
}
if ( !(sec->flags & COFF_SECTION_WRITEABLE) )
if ( !(sec->flags & IMAGE_SCN_MEM_WRITE) )
fprintf(stderr,
"Warning: relocation to r/o section %.8s:%08" PRIxFAST32 "\n",
sec->name, i - disp);
@@ -285,7 +234,7 @@ int main(int argc, char *argv[])
unsigned int i, nsec, width1, width2;
uint_fast64_t base1, base2;
uint32_t size1, size2;
struct coff_section *sec1, *sec2;
struct section_header *sec1, *sec2;
if ( argc == 1 ||
!strcmp(argv[1], "-?") ||
@@ -328,16 +277,16 @@ int main(int argc, char *argv[])
if ( memcmp(sec1[i].name, sec2[i].name, sizeof(sec1[i].name)) ||
sec1[i].rva != sec2[i].rva ||
sec1[i].size != sec2[i].size ||
sec1[i].file_size != sec2[i].file_size ||
sec1[i].virtual_size != sec2[i].virtual_size ||
sec1[i].raw_data_size != sec2[i].raw_data_size ||
sec1[i].flags != sec2[i].flags )
{
fprintf(stderr, "Mismatched section %u parameters\n", i);
return 5;
}
if ( !sec1[i].size ||
(sec1[i].flags & (COFF_SECTION_DISCARDABLE|COFF_SECTION_BSS)) )
if ( !sec1[i].virtual_size ||
(sec1[i].flags & (IMAGE_SCN_MEM_DISCARDABLE | IMAGE_SCN_CNT_UNINITIALIZED_DATA)) )
continue;
/*
@@ -354,10 +303,10 @@ int main(int argc, char *argv[])
return 3;
}
if ( sec1[i].file_size > sec1[i].size )
if ( sec1[i].raw_data_size > sec1[i].virtual_size )
{
sec1[i].file_size = sec1[i].size;
sec2[i].file_size = sec2[i].size;
sec1[i].raw_data_size = sec1[i].virtual_size;
sec2[i].raw_data_size = sec2[i].virtual_size;
}
ptr1 = map_section(sec1 + i, in1, argv[1]);
ptr2 = map_section(sec2 + i, in2, argv[2]);
+18 -72
View File
@@ -20,30 +20,8 @@
* Lesser General Public License for more details.
*/
#include "efi.h"
struct DosFileHeader {
UINT8 Magic[2];
UINT16 LastSize;
UINT16 nBlocks;
UINT16 nReloc;
UINT16 HdrSize;
UINT16 MinAlloc;
UINT16 MaxAlloc;
UINT16 ss;
UINT16 sp;
UINT16 Checksum;
UINT16 ip;
UINT16 cs;
UINT16 RelocPos;
UINT16 nOverlay;
UINT16 reserved[4];
UINT16 OEMId;
UINT16 OEMInfo;
UINT16 reserved2[10];
UINT32 ExeHeader;
};
#include "efi/pe.h"
#if defined(__arm__) || defined (__aarch64__)
#define PE_HEADER_MACHINE 0xaa64
@@ -53,45 +31,17 @@ struct DosFileHeader {
#error "Unknown architecture"
#endif
struct PeFileHeader {
UINT16 Machine;
UINT16 NumberOfSections;
UINT32 TimeDateStamp;
UINT32 PointerToSymbolTable;
UINT32 NumberOfSymbols;
UINT16 SizeOfOptionalHeader;
UINT16 Characteristics;
};
struct PeHeader {
UINT8 Magic[4];
struct PeFileHeader FileHeader;
};
struct PeSectionHeader {
CHAR8 Name[8];
UINT32 VirtualSize;
UINT32 VirtualAddress;
UINT32 SizeOfRawData;
UINT32 PointerToRawData;
UINT32 PointerToRelocations;
UINT32 PointerToLinenumbers;
UINT16 NumberOfRelocations;
UINT16 NumberOfLinenumbers;
UINT32 Characteristics;
};
static bool __init pe_name_compare(const struct PeSectionHeader *sect,
static bool __init pe_name_compare(const struct section_header *sect,
const CHAR16 *name)
{
size_t i;
if ( sect->Name[0] != '.' )
if ( sect->name[0] != '.' )
return false;
for ( i = 1; i < sizeof(sect->Name); i++ )
for ( i = 1; i < sizeof(sect->name); i++ )
{
const char c = sect->Name[i];
const char c = sect->name[i];
if ( c != name[i - 1] )
return false;
@@ -105,33 +55,29 @@ static bool __init pe_name_compare(const struct PeSectionHeader *sect,
const void *__init pe_find_section(const void *image, const UINTN image_size,
const CHAR16 *section_name, UINTN *size_out)
{
const struct DosFileHeader *dos = image;
const struct PeHeader *pe;
const struct PeSectionHeader *sect;
const struct mz_hdr *mz = image;
const struct pe_hdr *pe;
const struct section_header *sect;
UINTN offset, i;
if ( image_size < sizeof(*dos) ||
dos->Magic[0] != 'M' ||
dos->Magic[1] != 'Z' )
if ( image_size < sizeof(*mz) ||
mz->magic != MZ_MAGIC )
return NULL;
offset = dos->ExeHeader;
offset = mz->peaddr;
pe = image + offset;
offset += sizeof(*pe);
if ( image_size < offset ||
pe->Magic[0] != 'P' ||
pe->Magic[1] != 'E' ||
pe->Magic[2] != '\0' ||
pe->Magic[3] != '\0' )
pe->magic != PE_MAGIC )
return NULL;
if ( pe->FileHeader.Machine != PE_HEADER_MACHINE )
if ( pe->machine != PE_HEADER_MACHINE )
return NULL;
offset += pe->FileHeader.SizeOfOptionalHeader;
offset += pe->opt_hdr_size;
for ( i = 0; i < pe->FileHeader.NumberOfSections; i++ )
for ( i = 0; i < pe->sections; i++ )
{
sect = image + offset;
if ( image_size < offset + sizeof(*sect) )
@@ -143,13 +89,13 @@ const void *__init pe_find_section(const void *image, const UINTN image_size,
continue;
}
if ( image_size < sect->VirtualSize + sect->VirtualAddress )
if ( image_size < sect->virtual_size + sect->rva )
blexit(L"PE invalid section size + address");
if ( size_out )
*size_out = sect->VirtualSize;
*size_out = sect->virtual_size;
return image + sect->VirtualAddress;
return image + sect->rva;
}
return NULL;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.