2 * Copyright (C) 2011 Intel Corporation; author Matt Fleming
4 * Wrap the ELF shared library in a PE32 (32bit) or PE32+ (64bit) suit.
6 * Syslinux plays some games with the ELF sections that are not easily
7 * converted to a PE32 executable. For instance, Syslinux requires
8 * that a symbol hash table be present (GNU hash or SysV) so that
9 * symbols in ELF modules can be resolved at runtime but the EFI
10 * firmware loader doesn't like that and refuses to load the file.
12 * We pretend that we have an EFI executable with a single .text
13 * section so that the EFI loader will load it and jump to the entry
14 * point. Once the Syslinux ELF shared object has control we can do
17 #include <linux/elf.h>
18 #include <sys/types.h>
27 #if __SIZEOF_POINTER__ == 4
28 typedef Elf32_Ehdr Elf_Ehdr
;
29 typedef Elf32_Addr Elf_Addr
;
30 #elif __SIZEOF_POINTER__ == 8
31 typedef Elf64_Ehdr Elf_Ehdr
;
32 typedef Elf64_Addr Elf_Addr
;
34 #error "unsupported architecture"
38 * 'so_size' is the file size of the ELF shared object.
39 * 'data_size' is the size of initialised data in the shared object.
40 * 'class' dictates how the header is written
41 * For 32bit machines (class == ELFCLASS32), the optional
42 * header includes PE32 header fields
43 * For 64bit machines (class == ELFCLASS64), the optional
44 * header includes PE32+header fields
46 static void write_header(FILE *f
, __uint32_t entry
, size_t data_size
,
47 __uint32_t so_size
, __uint8_t
class)
49 struct optional_hdr o_hdr
;
50 struct optional_hdr_pe32p o_hdr_pe32p
;
51 struct section t_sec
, r_sec
;
52 struct extra_hdr e_hdr
;
53 struct extra_hdr_pe32p e_hdr_pe32p
;
54 struct coff_hdr c_hdr
;
56 struct coff_reloc c_rel
;
57 __uint32_t total_sz
= so_size
;
60 __uint32_t reloc_start
, reloc_end
;
62 memset(&hdr
, 0, sizeof(hdr
));
63 hdr
.msdos_signature
= MSDOS_SIGNATURE
;
66 * The relocs table pointer needs to be >= 0x40 for PE files. It
67 * informs things like file(1) that we are not an MS-DOS
70 hdr
.relocs_ptr
= 0x40;
72 hdr
.pe_hdr
= OFFSETOF(struct header
, pe_signature
);
73 hdr
.pe_signature
= PE_SIGNATURE
;
74 fwrite(&hdr
, sizeof(hdr
), 1, f
);
76 memset(&c_hdr
, 0, sizeof(c_hdr
));
77 c_hdr
.nr_sections
= 2;
79 if (class == ELFCLASS32
) {
80 hdr_sz
= sizeof(o_hdr
) + sizeof(t_sec
) + sizeof(e_hdr
) +
81 sizeof(r_sec
) + sizeof(c_hdr
) + sizeof(hdr
) + sizeof(c_rel
)
85 c_hdr
.arch
= IMAGE_FILE_MACHINE_I386
;
86 c_hdr
.characteristics
= IMAGE_FILE_32BIT_MACHINE
|
87 IMAGE_FILE_DEBUG_STRIPPED
| IMAGE_FILE_EXECUTABLE_IMAGE
|
88 IMAGE_FILE_LINE_NUMBERS_STRIPPED
;
89 c_hdr
.optional_hdr_sz
= sizeof(o_hdr
) + sizeof(e_hdr
);
90 fwrite(&c_hdr
, sizeof(c_hdr
), 1, f
);
91 memset(&o_hdr
, 0, sizeof(o_hdr
));
92 o_hdr
.format
= PE32_FORMAT
;
93 o_hdr
.major_linker_version
= 0x02;
94 o_hdr
.minor_linker_version
= 0x14;
95 o_hdr
.code_sz
= total_sz
;
96 o_hdr
.entry_point
= entry
;
97 o_hdr
.initialized_data_sz
= data_size
;
98 fwrite(&o_hdr
, sizeof(o_hdr
), 1, f
);
99 memset(&e_hdr
, 0, sizeof(e_hdr
));
100 e_hdr
.section_align
= 4096;
101 e_hdr
.file_align
= 512;
102 e_hdr
.image_sz
= total_sz
;
103 e_hdr
.headers_sz
= 512;
104 e_hdr
.subsystem
= IMAGE_SUBSYSTEM_EFI_APPLICATION
;
105 e_hdr
.rva_and_sizes_nr
= 1;
106 fwrite(&e_hdr
, sizeof(e_hdr
), 1, f
);
108 else if (class == ELFCLASS64
) {
109 hdr_sz
= sizeof(o_hdr_pe32p
) + sizeof(t_sec
) + sizeof(e_hdr_pe32p
) +
110 sizeof(r_sec
) + sizeof(c_hdr
) + sizeof(hdr
) + sizeof(c_rel
)
114 c_hdr
.arch
= IMAGE_FILE_MACHINE_X86_64
;
115 c_hdr
.characteristics
= IMAGE_FILE_DEBUG_STRIPPED
| IMAGE_FILE_EXECUTABLE_IMAGE
|
116 IMAGE_FILE_LINE_NUMBERS_STRIPPED
;
117 c_hdr
.optional_hdr_sz
= sizeof(o_hdr_pe32p
) + sizeof(e_hdr_pe32p
);
118 fwrite(&c_hdr
, sizeof(c_hdr
), 1, f
);
119 memset(&o_hdr_pe32p
, 0, sizeof(o_hdr_pe32p
));
120 o_hdr_pe32p
.format
= PE32P_FORMAT
;
121 o_hdr_pe32p
.major_linker_version
= 0x02;
122 o_hdr_pe32p
.minor_linker_version
= 0x14;
123 o_hdr_pe32p
.code_sz
= total_sz
;
124 o_hdr_pe32p
.entry_point
= entry
;
125 o_hdr
.initialized_data_sz
= data_size
;
126 fwrite(&o_hdr_pe32p
, sizeof(o_hdr_pe32p
), 1, f
);
127 memset(&e_hdr_pe32p
, 0, sizeof(e_hdr
));
128 e_hdr_pe32p
.section_align
= 4096;
129 e_hdr_pe32p
.file_align
= 512;
130 e_hdr_pe32p
.image_sz
= total_sz
;
131 e_hdr_pe32p
.headers_sz
= 512;
132 e_hdr_pe32p
.subsystem
= IMAGE_SUBSYSTEM_EFI_APPLICATION
;
133 e_hdr_pe32p
.rva_and_sizes_nr
= 1;
134 fwrite(&e_hdr_pe32p
, sizeof(e_hdr_pe32p
), 1, f
);
137 memset(&t_sec
, 0, sizeof(t_sec
));
138 strcpy((char *)t_sec
.name
, ".text");
139 t_sec
.virtual_sz
= total_sz
;
140 t_sec
.raw_data_sz
= total_sz
;
141 t_sec
.characteristics
= IMAGE_SCN_CNT_CODE
|
142 IMAGE_SCN_ALIGN_16BYTES
| IMAGE_SCN_MEM_EXECUTE
|
144 fwrite(&t_sec
, sizeof(t_sec
), 1, f
);
147 * Write our dummy relocation and reloc section.
149 memset(&r_sec
, 0, sizeof(r_sec
));
150 strcpy((char *)r_sec
.name
, ".reloc");
151 r_sec
.virtual_sz
= sizeof(c_rel
);
152 r_sec
.virtual_address
= ftell(f
) + sizeof(r_sec
);
153 r_sec
.raw_data_sz
= r_sec
.virtual_sz
;
154 r_sec
.raw_data
= r_sec
.virtual_address
;
155 r_sec
.characteristics
= IMAGE_SCN_CNT_INITIALIZED_DATA
|
156 IMAGE_SCN_ALIGN_1BYTES
| IMAGE_SCN_MEM_DISCARDABLE
|
158 fwrite(&r_sec
, sizeof(r_sec
), 1, f
);
160 memset(&c_rel
, 0, sizeof(c_rel
));
161 c_rel
.virtual_address
= ftell(f
) + sizeof(c_rel
);
162 c_rel
.symtab_index
= 10;
163 fwrite(&c_rel
, sizeof(c_rel
), 1, f
);
164 fwrite(&dummy
, sizeof(dummy
), 1, f
);
168 static void usage(char *progname
)
170 fprintf(stderr
, "usage: %s <ELF shared object> <output file>\n",
174 int main(int argc
, char **argv
)
182 __uint16_t shnum
, shentsize
, shstrndx
;
193 f_in
= fopen(argv
[1], "r");
199 if (stat(argv
[1], &st
) != 0) {
204 f_out
= fopen(argv
[2], "w");
211 * Parse the ELF header and find the entry point.
213 fread((void *)&e32_hdr
, sizeof(e32_hdr
), 1, f_in
);
214 if (e32_hdr
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
215 id
= e32_hdr
.e_ident
;
217 entry
= e32_hdr
.e_entry
;
218 shoff
= e32_hdr
.e_shoff
;
219 shnum
= e32_hdr
.e_shnum
;
220 shstrndx
= e32_hdr
.e_shstrndx
;
221 shentsize
= e32_hdr
.e_shentsize
;
223 else if (e32_hdr
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
224 /* read the header again for x86_64
225 * note that the elf header entry point is 64bit whereas
226 * the entry point in PE/COFF format is 32bit!*/
229 fread((void *)&e64_hdr
, sizeof(e64_hdr
), 1, f_in
);
230 id
= e64_hdr
.e_ident
;
231 entry
= e64_hdr
.e_entry
;
232 shoff
= e64_hdr
.e_shoff
;
233 shnum
= e64_hdr
.e_shnum
;
234 shstrndx
= e64_hdr
.e_shstrndx
;
235 shentsize
= e64_hdr
.e_shentsize
;
237 fprintf(stderr
, "Unsupported architecture\n");
241 if (id
[EI_MAG0
] != ELFMAG0
||
242 id
[EI_MAG1
] != ELFMAG1
||
243 id
[EI_MAG2
] != ELFMAG2
||
244 id
[EI_MAG3
] != ELFMAG3
) {
245 fprintf(stderr
, "Input file not ELF shared object\n");
249 if (!shoff
|| !shnum
|| (shstrndx
== SHN_UNDEF
)) {
250 fprintf(stderr
, "Cannot find section table\n");
255 * Find the beginning of the .bss section. Everything preceding
256 * it is copied verbatim to the output file.
258 if (e32_hdr
.e_ident
[EI_CLASS
] == ELFCLASS32
) {
259 const char *shstrtab
, *name
;
264 fseek(f_in
, shoff
, SEEK_SET
);
266 /* First find the strtab section */
267 fseek(f_in
, shstrndx
* shentsize
, SEEK_CUR
);
268 fread(&shdr
, sizeof(shdr
), 1, f_in
);
270 strtab
= malloc(shdr
.sh_size
);
272 fprintf(stderr
, "Failed to malloc strtab\n");
276 fseek(f_in
, shdr
.sh_offset
, SEEK_SET
);
277 fread(strtab
, shdr
.sh_size
, 1, f_in
);
279 /* Now search for the .bss section */
280 fseek(f_in
, shoff
, SEEK_SET
);
281 for (i
= 0; i
< shnum
; i
++) {
282 rv
= fread(&shdr
, sizeof(shdr
), 1, f_in
);
284 fprintf(stderr
, "Failed to read section table\n");
288 name
= strtab
+ shdr
.sh_name
;
289 if (!strcmp(name
, ".bss"))
294 fprintf(stderr
, "Failed to find .bss section\n");
298 datasz
= shdr
.sh_offset
;
300 else if (e32_hdr
.e_ident
[EI_CLASS
] == ELFCLASS64
) {
301 const char *shstrtab
, *name
;
306 fseek(f_in
, shoff
, SEEK_SET
);
308 /* First find the strtab section */
309 fseek(f_in
, shstrndx
* shentsize
, SEEK_CUR
);
310 fread(&shdr
, sizeof(shdr
), 1, f_in
);
312 strtab
= malloc(shdr
.sh_size
);
314 fprintf(stderr
, "Failed to malloc strtab\n");
318 fseek(f_in
, shdr
.sh_offset
, SEEK_SET
);
319 fread(strtab
, shdr
.sh_size
, 1, f_in
);
321 /* Now search for the .bss section */
322 fseek(f_in
, shoff
, SEEK_SET
);
323 for (i
= 0; i
< shnum
; i
++) {
324 rv
= fread(&shdr
, sizeof(shdr
), 1, f_in
);
326 fprintf(stderr
, "Failed to read section table\n");
330 name
= strtab
+ shdr
.sh_name
;
331 if (!strcmp(name
, ".bss"))
336 fprintf(stderr
, "Failed to find .bss section\n");
340 datasz
= shdr
.sh_offset
;
343 buf
= malloc(datasz
);
349 write_header(f_out
, entry
, datasz
, st
.st_size
, class);
351 /* Write out the entire ELF shared object */
353 rv
= fread(buf
, datasz
, 1, f_in
);
354 if (!rv
&& ferror(f_in
)) {
355 fprintf(stderr
, "Failed to read all bytes from input\n");
359 fwrite(buf
, datasz
, rv
, f_out
);