Make linux optional as all other configs.
[syslinux-debian/hramrach.git] / efi / wrapper.c
blob04c895f6efbcb5a317bf9dccfcf5d09e01e95a92
1 /*
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
15 * whatever we want.
17 #include <linux/elf.h>
18 #include <sys/types.h>
19 #include <sys/stat.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
25 #include "wrapper.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;
33 #else
34 #error "unsupported architecture"
35 #endif
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;
55 struct header hdr;
56 struct coff_reloc c_rel;
57 __uint32_t total_sz = so_size;
58 __uint32_t dummy = 0;
59 __uint32_t hdr_sz;
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
68 * executable.
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;
78 c_hdr.nr_syms = 1;
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)
82 + sizeof(dummy);
83 total_sz += hdr_sz;
84 entry += hdr_sz;
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)
111 + sizeof(dummy);
112 total_sz += hdr_sz;
113 entry += hdr_sz;
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 |
143 IMAGE_SCN_MEM_READ;
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 |
157 IMAGE_SCN_MEM_READ;
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",
171 progname);
174 int main(int argc, char **argv)
176 struct stat st;
177 Elf32_Ehdr e32_hdr;
178 Elf64_Ehdr e64_hdr;
179 __uint32_t entry;
180 __uint8_t class;
181 __uint64_t shoff;
182 __uint16_t shnum, shentsize, shstrndx;
183 unsigned char *id;
184 FILE *f_in, *f_out;
185 void *buf;
186 size_t datasz, rv;
188 if (argc < 3) {
189 usage(argv[0]);
190 exit(0);
193 f_in = fopen(argv[1], "r");
194 if (!f_in) {
195 perror("fopen");
196 exit(EXIT_FAILURE);
199 if (stat(argv[1], &st) != 0) {
200 perror("stat");
201 exit(EXIT_FAILURE);
204 f_out = fopen(argv[2], "w");
205 if (!f_out) {
206 perror("fopen");
207 exit(EXIT_FAILURE);
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;
216 class = ELFCLASS32;
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!*/
227 class = ELFCLASS64;
228 rewind(f_in);
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;
236 } else {
237 fprintf(stderr, "Unsupported architecture\n");
238 exit(EXIT_FAILURE);
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");
246 exit(EXIT_FAILURE);
249 if (!shoff || !shnum || (shstrndx == SHN_UNDEF)) {
250 fprintf(stderr, "Cannot find section table\n");
251 exit(EXIT_FAILURE);
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;
260 Elf32_Shdr shdr;
261 int i;
262 void *strtab;
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);
271 if (!strtab) {
272 fprintf(stderr, "Failed to malloc strtab\n");
273 exit(EXIT_FAILURE);
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);
283 if (!rv) {
284 fprintf(stderr, "Failed to read section table\n");
285 exit(EXIT_FAILURE);
288 name = strtab + shdr.sh_name;
289 if (!strcmp(name, ".bss"))
290 break;
293 if (i == shnum) {
294 fprintf(stderr, "Failed to find .bss section\n");
295 exit(EXIT_FAILURE);
298 datasz = shdr.sh_offset;
300 else if (e32_hdr.e_ident[EI_CLASS] == ELFCLASS64) {
301 const char *shstrtab, *name;
302 Elf64_Shdr shdr;
303 int i;
304 void *strtab;
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);
313 if (!strtab) {
314 fprintf(stderr, "Failed to malloc strtab\n");
315 exit(EXIT_FAILURE);
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);
325 if (!rv) {
326 fprintf(stderr, "Failed to read section table\n");
327 exit(EXIT_FAILURE);
330 name = strtab + shdr.sh_name;
331 if (!strcmp(name, ".bss"))
332 break;
335 if (i == shnum) {
336 fprintf(stderr, "Failed to find .bss section\n");
337 exit(EXIT_FAILURE);
340 datasz = shdr.sh_offset;
343 buf = malloc(datasz);
344 if (!buf) {
345 perror("malloc");
346 exit(EXIT_FAILURE);
349 write_header(f_out, entry, datasz, st.st_size, class);
351 /* Write out the entire ELF shared object */
352 rewind(f_in);
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");
356 exit(EXIT_FAILURE);
359 fwrite(buf, datasz, rv, f_out);
360 return 0;