grub-pe2elf.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576
  1. /* grub-pe2elf.c - tool to convert pe image to elf. */
  2. /*
  3. * GRUB -- GRand Unified Bootloader
  4. * Copyright (C) 2008,2009 Free Software Foundation, Inc.
  5. *
  6. * GRUB is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * GRUB is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with GRUB. If not, see <http://www.gnu.org/licenses/>.
  18. */
  19. #include <config.h>
  20. #include <grub/types.h>
  21. #include <grub/util/misc.h>
  22. #include <grub/elf.h>
  23. #include <grub/efi/pe32.h>
  24. #include <grub/misc.h>
  25. #include <stdio.h>
  26. #include <unistd.h>
  27. #include <string.h>
  28. #include <stdlib.h>
  29. #include <getopt.h>
  30. /* Please don't internationalise this file. It's pointless. */
  31. /*
  32. * Section layout
  33. *
  34. * null
  35. * .text
  36. * .rdata
  37. * .data
  38. * .bss
  39. * .modname
  40. * .moddeps
  41. * .symtab
  42. * .strtab
  43. * relocation sections
  44. */
  45. #if GRUB_TARGET_WORDSIZE == 64
  46. typedef Elf64_Rela elf_reloc_t;
  47. #define GRUB_PE32_MACHINE GRUB_PE32_MACHINE_X86_64
  48. #else
  49. typedef Elf32_Rel elf_reloc_t;
  50. #define GRUB_PE32_MACHINE GRUB_PE32_MACHINE_I386
  51. #endif
  52. #define STRTAB_BLOCK 256
  53. static char *strtab;
  54. static int strtab_max, strtab_len;
  55. static Elf_Ehdr ehdr;
  56. static Elf_Shdr *shdr;
  57. static int num_sections, first_reloc_section, reloc_sections_end, symtab_section, strtab_section;
  58. static grub_uint32_t offset, image_base;
  59. static int
  60. insert_string (const char *name)
  61. {
  62. int len, result;
  63. if (*name == '_')
  64. name++;
  65. len = strlen (name);
  66. if (strtab_len + len >= strtab_max)
  67. {
  68. strtab_max += STRTAB_BLOCK;
  69. strtab = xrealloc (strtab, strtab_max);
  70. }
  71. strcpy (strtab + strtab_len, name);
  72. result = strtab_len;
  73. strtab_len += len + 1;
  74. return result;
  75. }
  76. static int *
  77. write_section_data (FILE* fp, const char *name, char *image,
  78. struct grub_pe32_coff_header *pe_chdr,
  79. struct grub_pe32_section_table *pe_shdr)
  80. {
  81. int *section_map;
  82. int i;
  83. grub_uint32_t last_category = 0;
  84. grub_uint32_t idx, idx_reloc;
  85. char *pe_strtab = (image + pe_chdr->symtab_offset
  86. + pe_chdr->num_symbols * sizeof (struct grub_pe32_symbol));
  87. section_map = xmalloc ((2 * pe_chdr->num_sections + 5) * sizeof (int));
  88. section_map[0] = 0;
  89. shdr = xmalloc ((2 * pe_chdr->num_sections + 5) * sizeof (shdr[0]));
  90. idx = 1;
  91. idx_reloc = pe_chdr->num_sections + 1;
  92. for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++)
  93. {
  94. grub_uint32_t category;
  95. const char *shname = pe_shdr->name;
  96. grub_size_t secsize;
  97. if (shname[0] == '/' && grub_isdigit (shname[1]))
  98. {
  99. char t[sizeof (pe_shdr->name) + 1];
  100. memcpy (t, shname, sizeof (pe_shdr->name));
  101. t[sizeof (pe_shdr->name)] = 0;
  102. shname = pe_strtab + atoi (t + 1);
  103. }
  104. secsize = pe_shdr->raw_data_size;
  105. shdr[idx].sh_type = SHT_PROGBITS;
  106. if (! strcmp (shname, ".text"))
  107. {
  108. category = 0;
  109. shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR;
  110. }
  111. else if (! strncmp (shname, ".rdata", 6))
  112. {
  113. category = 1;
  114. shdr[idx].sh_flags = SHF_ALLOC;
  115. }
  116. else if (! strcmp (shname, ".data"))
  117. {
  118. category = 2;
  119. shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE;
  120. }
  121. else if (! strcmp (shname, ".bss"))
  122. {
  123. category = 3;
  124. shdr[idx].sh_type = SHT_NOBITS;
  125. shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE;
  126. if (secsize < pe_shdr->virtual_size)
  127. secsize = pe_shdr->virtual_size;
  128. }
  129. else if (strcmp (shname, ".modname") == 0 || strcmp (shname, ".moddeps") == 0
  130. || strcmp (shname, ".module_license") == 0)
  131. category = 4;
  132. else
  133. {
  134. section_map[i + 1] = -1;
  135. continue;
  136. }
  137. if (category < last_category)
  138. grub_util_error ("out of order sections");
  139. section_map[i + 1] = idx;
  140. if (pe_shdr->virtual_size
  141. && pe_shdr->virtual_size < secsize)
  142. secsize = pe_shdr->virtual_size;
  143. shdr[idx].sh_size = secsize;
  144. shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >>
  145. GRUB_PE32_SCN_ALIGN_SHIFT) &
  146. GRUB_PE32_SCN_ALIGN_MASK) - 1);
  147. shdr[idx].sh_addr = pe_shdr->virtual_address + image_base;
  148. if (shdr[idx].sh_type != SHT_NOBITS)
  149. {
  150. shdr[idx].sh_offset = offset;
  151. grub_util_write_image_at (image + pe_shdr->raw_data_offset,
  152. pe_shdr->raw_data_size, offset, fp,
  153. shname);
  154. offset += secsize;
  155. }
  156. if (pe_shdr->relocations_offset)
  157. {
  158. char relname[5 + strlen (shname)];
  159. sprintf (relname, ".rel%s", shname);
  160. shdr[idx_reloc].sh_name = insert_string (relname);
  161. shdr[idx_reloc].sh_link = i;
  162. shdr[idx_reloc].sh_info = idx;
  163. shdr[idx].sh_name = shdr[idx_reloc].sh_name + 4;
  164. idx_reloc++;
  165. }
  166. else
  167. shdr[idx].sh_name = insert_string (shname);
  168. idx++;
  169. }
  170. idx_reloc -= pe_chdr->num_sections + 1;
  171. num_sections = idx + idx_reloc + 2;
  172. first_reloc_section = idx;
  173. reloc_sections_end = idx + idx_reloc;
  174. memmove (shdr + idx, shdr + pe_chdr->num_sections + 1,
  175. idx_reloc * sizeof (shdr[0]));
  176. memset (shdr + idx + idx_reloc, 0, 3 * sizeof (shdr[0]));
  177. memset (shdr, 0, sizeof (shdr[0]));
  178. symtab_section = idx + idx_reloc;
  179. strtab_section = idx + idx_reloc + 1;
  180. return section_map;
  181. }
  182. static void
  183. write_reloc_section (FILE* fp, const char *name, char *image,
  184. struct grub_pe32_coff_header *pe_chdr,
  185. struct grub_pe32_section_table *pe_shdr,
  186. Elf_Sym *symtab,
  187. int *symtab_map)
  188. {
  189. int i;
  190. for (i = first_reloc_section; i < reloc_sections_end; i++)
  191. {
  192. struct grub_pe32_section_table *pe_sec;
  193. struct grub_pe32_reloc *pe_rel;
  194. elf_reloc_t *rel;
  195. int num_rels, j, modified;
  196. pe_sec = pe_shdr + shdr[i].sh_link;
  197. pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset);
  198. rel = (elf_reloc_t *) xmalloc (pe_sec->num_relocations * sizeof (elf_reloc_t));
  199. num_rels = 0;
  200. modified = 0;
  201. for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++)
  202. {
  203. int type;
  204. grub_uint32_t ofs, *addr;
  205. if ((pe_rel->symtab_index >= pe_chdr->num_symbols) ||
  206. (symtab_map[pe_rel->symtab_index] == -1))
  207. grub_util_error ("invalid symbol");
  208. ofs = pe_rel->offset - pe_sec->virtual_address;
  209. addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs);
  210. switch (pe_rel->type)
  211. {
  212. #if GRUB_TARGET_WORDSIZE == 64
  213. case 1:
  214. type = R_X86_64_64;
  215. rel[num_rels].r_addend = *(grub_int64_t *)addr;
  216. *(grub_int64_t *)addr = 0;
  217. modified = 1;
  218. break;
  219. case 4:
  220. type = R_X86_64_PC32;
  221. rel[num_rels].r_addend = *(grub_int32_t *)addr;
  222. *addr = 0;
  223. modified = 1;
  224. break;
  225. case 14:
  226. type = R_X86_64_PC64;
  227. rel[num_rels].r_addend = *(grub_uint64_t *)addr - 8;
  228. *(grub_uint64_t *)addr = 0;
  229. modified = 1;
  230. break;
  231. #else
  232. case GRUB_PE32_REL_I386_DIR32:
  233. type = R_386_32;
  234. break;
  235. case GRUB_PE32_REL_I386_REL32:
  236. type = R_386_PC32;
  237. break;
  238. #endif
  239. default:
  240. grub_util_error ("unknown pe relocation type %d", pe_rel->type);
  241. }
  242. if (type ==
  243. #if GRUB_TARGET_WORDSIZE == 64
  244. R_386_PC32
  245. #else
  246. R_X86_64_PC32
  247. #endif
  248. )
  249. {
  250. unsigned char code;
  251. code = image[pe_sec->raw_data_offset + ofs - 1];
  252. #if GRUB_TARGET_WORDSIZE == 32
  253. if (((code != 0xe8) && (code != 0xe9)) || (*addr))
  254. grub_util_error ("invalid relocation (%x %x)", code, *addr);
  255. #endif
  256. if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx
  257. && symtab[symtab_map[pe_rel->symtab_index]].st_shndx
  258. == shdr[i].sh_info)
  259. {
  260. modified = 1;
  261. *addr += (symtab[symtab_map[pe_rel->symtab_index]].st_value
  262. - ofs - 4);
  263. continue;
  264. }
  265. else
  266. {
  267. #if GRUB_TARGET_WORDSIZE == 64
  268. rel[num_rels].r_addend -= 4;
  269. #else
  270. modified = 1;
  271. *addr = -4;
  272. #endif
  273. }
  274. }
  275. rel[num_rels].r_offset = ofs;
  276. rel[num_rels].r_info = ELF_R_INFO (symtab_map[pe_rel->symtab_index],
  277. type);
  278. num_rels++;
  279. }
  280. if (modified)
  281. grub_util_write_image_at (image + pe_sec->raw_data_offset,
  282. shdr[shdr[i].sh_info].sh_size,
  283. shdr[shdr[i].sh_info].sh_offset,
  284. fp, name);
  285. #if GRUB_TARGET_WORDSIZE == 64
  286. shdr[i].sh_type = SHT_RELA;
  287. #else
  288. shdr[i].sh_type = SHT_REL;
  289. #endif
  290. shdr[i].sh_offset = offset;
  291. shdr[i].sh_link = symtab_section;
  292. shdr[i].sh_addralign = 4;
  293. shdr[i].sh_entsize = sizeof (elf_reloc_t);
  294. shdr[i].sh_size = num_rels * sizeof (elf_reloc_t);
  295. grub_util_write_image_at (rel, shdr[i].sh_size, offset, fp, name);
  296. offset += shdr[i].sh_size;
  297. free (rel);
  298. }
  299. }
  300. static void
  301. write_symbol_table (FILE* fp, const char *name, char *image,
  302. struct grub_pe32_coff_header *pe_chdr,
  303. struct grub_pe32_section_table *pe_shdr,
  304. int *section_map)
  305. {
  306. struct grub_pe32_symbol *pe_symtab;
  307. char *pe_strtab;
  308. Elf_Sym *symtab;
  309. int *symtab_map, num_syms;
  310. int i;
  311. pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset);
  312. pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols);
  313. symtab = (Elf_Sym *) xmalloc ((pe_chdr->num_symbols + 1) *
  314. sizeof (Elf_Sym));
  315. memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf_Sym));
  316. num_syms = 1;
  317. symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int));
  318. for (i = 0; i < (int) pe_chdr->num_symbols;
  319. i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1)
  320. {
  321. int bind, type;
  322. symtab_map[i] = -1;
  323. if ((pe_symtab->section > pe_chdr->num_sections) ||
  324. (section_map[pe_symtab->section] == -1))
  325. continue;
  326. if (! pe_symtab->section)
  327. type = STT_NOTYPE;
  328. else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION)
  329. type = STT_FUNC;
  330. else
  331. type = STT_OBJECT;
  332. if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL)
  333. bind = STB_GLOBAL;
  334. else
  335. bind = STB_LOCAL;
  336. if ((pe_symtab->type != GRUB_PE32_DT_FUNCTION) && (pe_symtab->num_aux))
  337. {
  338. if (! pe_symtab->value)
  339. type = STT_SECTION;
  340. symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name;
  341. }
  342. else
  343. {
  344. char short_name[9];
  345. char *symname;
  346. if (pe_symtab->long_name[0])
  347. {
  348. strncpy (short_name, pe_symtab->short_name, 8);
  349. short_name[8] = 0;
  350. symname = short_name;
  351. }
  352. else
  353. symname = pe_strtab + pe_symtab->long_name[1];
  354. if ((strcmp (symname, "_grub_mod_init")) &&
  355. (strcmp (symname, "_grub_mod_fini")) &&
  356. (strcmp (symname, "grub_mod_init")) &&
  357. (strcmp (symname, "grub_mod_fini")) &&
  358. (bind == STB_LOCAL))
  359. continue;
  360. symtab[num_syms].st_name = insert_string (symname);
  361. }
  362. symtab[num_syms].st_shndx = section_map[pe_symtab->section];
  363. symtab[num_syms].st_value = pe_symtab->value;
  364. symtab[num_syms].st_info = ELF_ST_INFO (bind, type);
  365. symtab_map[i] = num_syms;
  366. num_syms++;
  367. }
  368. write_reloc_section (fp, name, image, pe_chdr, pe_shdr,
  369. symtab, symtab_map);
  370. shdr[symtab_section].sh_name = insert_string (".symtab");
  371. shdr[symtab_section].sh_type = SHT_SYMTAB;
  372. shdr[symtab_section].sh_offset = offset;
  373. shdr[symtab_section].sh_size = num_syms * sizeof (Elf_Sym);
  374. shdr[symtab_section].sh_entsize = sizeof (Elf_Sym);
  375. shdr[symtab_section].sh_link = strtab_section;
  376. shdr[symtab_section].sh_addralign = 4;
  377. grub_util_write_image_at (symtab, shdr[symtab_section].sh_size,
  378. offset, fp, name);
  379. offset += shdr[symtab_section].sh_size;
  380. free (symtab);
  381. free (symtab_map);
  382. }
  383. static void
  384. write_string_table (FILE *fp, const char *name)
  385. {
  386. shdr[strtab_section].sh_name = insert_string (".strtab");
  387. shdr[strtab_section].sh_type = SHT_STRTAB;
  388. shdr[strtab_section].sh_offset = offset;
  389. shdr[strtab_section].sh_size = strtab_len;
  390. shdr[strtab_section].sh_addralign = 1;
  391. grub_util_write_image_at (strtab, strtab_len, offset, fp,
  392. name);
  393. offset += strtab_len;
  394. free (strtab);
  395. }
  396. static void
  397. write_section_header (FILE *fp, const char *name)
  398. {
  399. ehdr.e_ident[EI_MAG0] = ELFMAG0;
  400. ehdr.e_ident[EI_MAG1] = ELFMAG1;
  401. ehdr.e_ident[EI_MAG2] = ELFMAG2;
  402. ehdr.e_ident[EI_MAG3] = ELFMAG3;
  403. ehdr.e_ident[EI_VERSION] = EV_CURRENT;
  404. ehdr.e_version = EV_CURRENT;
  405. ehdr.e_type = ET_REL;
  406. #if GRUB_TARGET_WORDSIZE == 64
  407. ehdr.e_ident[EI_CLASS] = ELFCLASS64;
  408. ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
  409. ehdr.e_machine = EM_X86_64;
  410. #else
  411. ehdr.e_ident[EI_CLASS] = ELFCLASS32;
  412. ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
  413. ehdr.e_machine = EM_386;
  414. #endif
  415. ehdr.e_ehsize = sizeof (ehdr);
  416. ehdr.e_shentsize = sizeof (Elf_Shdr);
  417. ehdr.e_shstrndx = strtab_section;
  418. ehdr.e_shoff = offset;
  419. ehdr.e_shnum = num_sections;
  420. grub_util_write_image_at (shdr, sizeof (Elf_Shdr) * num_sections,
  421. offset, fp, name);
  422. grub_util_write_image_at (&ehdr, sizeof (Elf_Ehdr), 0, fp, name);
  423. }
  424. static void
  425. convert_pe (FILE* fp, const char *name, char *image)
  426. {
  427. struct grub_pe32_coff_header *pe_chdr;
  428. struct grub_pe32_section_table *pe_shdr;
  429. int *section_map;
  430. if (image[0] == 'M' && image[1] == 'Z')
  431. pe_chdr = (struct grub_pe32_coff_header *) (image + (grub_le_to_cpu32 (((grub_uint32_t *)image)[0xf]) + 4));
  432. else
  433. pe_chdr = (struct grub_pe32_coff_header *) image;
  434. if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE)
  435. grub_util_error ("invalid coff image (%x != %x)",
  436. grub_le_to_cpu16 (pe_chdr->machine), GRUB_PE32_MACHINE);
  437. strtab = xmalloc (STRTAB_BLOCK);
  438. strtab_max = STRTAB_BLOCK;
  439. strtab[0] = 0;
  440. strtab_len = 1;
  441. offset = sizeof (ehdr);
  442. if (pe_chdr->optional_header_size)
  443. {
  444. #if GRUB_TARGET_WORDSIZE == 64
  445. struct grub_pe64_optional_header *o;
  446. #else
  447. struct grub_pe32_optional_header *o;
  448. #endif
  449. o = (void *) (pe_chdr + 1);
  450. image_base = o->image_base;
  451. }
  452. pe_shdr = (struct grub_pe32_section_table *) ((char *) (pe_chdr + 1) + pe_chdr->optional_header_size);
  453. section_map = write_section_data (fp, name, image, pe_chdr, pe_shdr);
  454. write_symbol_table (fp, name, image, pe_chdr, pe_shdr, section_map);
  455. free (section_map);
  456. write_string_table (fp, name);
  457. write_section_header (fp, name);
  458. }
  459. int
  460. main (int argc, char *argv[])
  461. {
  462. char *image;
  463. FILE* fp;
  464. char *in, *out;
  465. /* Obtain PATH. */
  466. if (1 >= argc)
  467. {
  468. fprintf (stderr, "Filename not specified.\n");
  469. return 1;
  470. }
  471. in = argv[1];
  472. if (argc > 2)
  473. out = argv[2];
  474. else
  475. out = in;
  476. image = grub_util_read_image (in);
  477. fp = grub_util_fopen (out, "wb");
  478. if (! fp)
  479. grub_util_error ("cannot open %s", out);
  480. convert_pe (fp, out, image);
  481. fclose (fp);
  482. return 0;
  483. }