grub-pe2elf.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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 <stdio.h>
  25. #include <unistd.h>
  26. #include <string.h>
  27. #include <stdlib.h>
  28. #include <getopt.h>
  29. #include "progname.h"
  30. static struct option options[] = {
  31. {"help", no_argument, 0, 'h'},
  32. {"version", no_argument, 0, 'V'},
  33. {"verbose", no_argument, 0, 'v'},
  34. {0, 0, 0, 0}
  35. };
  36. static void
  37. usage (int status)
  38. {
  39. if (status)
  40. fprintf (stderr, "Try `%s --help' for more information.\n", program_name);
  41. else
  42. printf ("\
  43. Usage: %s [OPTIONS] input [output]\n\
  44. \n\
  45. Tool to convert pe image to elf.\n\
  46. \nOptions:\n\
  47. -h, --help display this message and exit\n\
  48. -V, --version print version information and exit\n\
  49. -v, --verbose print verbose messages\n\
  50. \n\
  51. Report bugs to <%s>.\n", program_name, PACKAGE_BUGREPORT);
  52. exit (status);
  53. }
  54. /*
  55. * Section layout
  56. *
  57. * null
  58. * .text
  59. * .rdata
  60. * .data
  61. * .bss
  62. * .modname
  63. * .moddeps
  64. * .symtab
  65. * .strtab
  66. * relocation sections
  67. */
  68. #define TEXT_SECTION 1
  69. #define RDATA_SECTION 2
  70. #define DATA_SECTION 3
  71. #define BSS_SECTION 4
  72. #define MODNAME_SECTION 5
  73. #define MODDEPS_SECTION 6
  74. #define SYMTAB_SECTION 7
  75. #define STRTAB_SECTION 8
  76. #define REL_SECTION 9
  77. #define MAX_SECTIONS 12
  78. #define STRTAB_BLOCK 256
  79. static char *strtab;
  80. static int strtab_max, strtab_len;
  81. Elf32_Ehdr ehdr;
  82. Elf32_Shdr shdr[MAX_SECTIONS];
  83. int num_sections;
  84. grub_uint32_t offset;
  85. static int
  86. insert_string (char *name)
  87. {
  88. int len, result;
  89. if (*name == '_')
  90. name++;
  91. len = strlen (name);
  92. if (strtab_len + len >= strtab_max)
  93. {
  94. strtab_max += STRTAB_BLOCK;
  95. strtab = xrealloc (strtab, strtab_max);
  96. }
  97. strcpy (strtab + strtab_len, name);
  98. result = strtab_len;
  99. strtab_len += len + 1;
  100. return result;
  101. }
  102. static int *
  103. write_section_data (FILE* fp, char *image,
  104. struct grub_pe32_coff_header *pe_chdr,
  105. struct grub_pe32_section_table *pe_shdr)
  106. {
  107. int *section_map;
  108. int i;
  109. section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int));
  110. section_map[0] = 0;
  111. for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++)
  112. {
  113. grub_uint32_t idx;
  114. if (! strcmp (pe_shdr->name, ".text"))
  115. {
  116. idx = TEXT_SECTION;
  117. shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR;
  118. }
  119. else if (! strcmp (pe_shdr->name, ".rdata"))
  120. {
  121. idx = RDATA_SECTION;
  122. shdr[idx].sh_flags = SHF_ALLOC;
  123. }
  124. else if (! strcmp (pe_shdr->name, ".data"))
  125. {
  126. idx = DATA_SECTION;
  127. shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE;
  128. }
  129. else if (! strcmp (pe_shdr->name, ".bss"))
  130. {
  131. idx = BSS_SECTION;
  132. shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE;
  133. }
  134. else if (! strcmp (pe_shdr->name, ".modname"))
  135. idx = MODNAME_SECTION;
  136. else if (! strcmp (pe_shdr->name, ".moddeps"))
  137. idx = MODDEPS_SECTION;
  138. else
  139. {
  140. section_map[i + 1] = -1;
  141. continue;
  142. }
  143. section_map[i + 1] = idx;
  144. shdr[idx].sh_type = (idx == BSS_SECTION) ? SHT_NOBITS : SHT_PROGBITS;
  145. shdr[idx].sh_size = pe_shdr->raw_data_size;
  146. shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >>
  147. GRUB_PE32_SCN_ALIGN_SHIFT) &
  148. GRUB_PE32_SCN_ALIGN_MASK) - 1);
  149. if (idx != BSS_SECTION)
  150. {
  151. shdr[idx].sh_offset = offset;
  152. grub_util_write_image_at (image + pe_shdr->raw_data_offset,
  153. pe_shdr->raw_data_size, offset, fp);
  154. offset += pe_shdr->raw_data_size;
  155. }
  156. if (pe_shdr->relocations_offset)
  157. {
  158. char name[5 + strlen (pe_shdr->name)];
  159. if (num_sections >= MAX_SECTIONS)
  160. grub_util_error ("too many sections");
  161. sprintf (name, ".rel%s", pe_shdr->name);
  162. shdr[num_sections].sh_name = insert_string (name);
  163. shdr[num_sections].sh_link = i;
  164. shdr[num_sections].sh_info = idx;
  165. shdr[idx].sh_name = shdr[num_sections].sh_name + 4;
  166. num_sections++;
  167. }
  168. else
  169. shdr[idx].sh_name = insert_string (pe_shdr->name);
  170. }
  171. return section_map;
  172. }
  173. static void
  174. write_reloc_section (FILE* fp, char *image,
  175. struct grub_pe32_coff_header *pe_chdr,
  176. struct grub_pe32_section_table *pe_shdr,
  177. Elf32_Sym *symtab,
  178. int *symtab_map)
  179. {
  180. int i;
  181. for (i = REL_SECTION; i < num_sections; i++)
  182. {
  183. struct grub_pe32_section_table *pe_sec;
  184. struct grub_pe32_reloc *pe_rel;
  185. Elf32_Rel *rel;
  186. int num_rels, j, modified;
  187. pe_sec = pe_shdr + shdr[i].sh_link;
  188. pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset);
  189. rel = (Elf32_Rel *) xmalloc (pe_sec->num_relocations * sizeof (Elf32_Rel));
  190. num_rels = 0;
  191. modified = 0;
  192. for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++)
  193. {
  194. int type;
  195. grub_uint32_t ofs, *addr;
  196. if ((pe_rel->symtab_index >= pe_chdr->num_symbols) ||
  197. (symtab_map[pe_rel->symtab_index] == -1))
  198. grub_util_error ("invalid symbol");
  199. if (pe_rel->type == GRUB_PE32_REL_I386_DIR32)
  200. type = R_386_32;
  201. else if (pe_rel->type == GRUB_PE32_REL_I386_REL32)
  202. type = R_386_PC32;
  203. else
  204. grub_util_error ("unknown pe relocation type %d\n", pe_rel->type);
  205. ofs = pe_rel->offset - pe_sec->virtual_address;
  206. addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs);
  207. if (type == R_386_PC32)
  208. {
  209. unsigned char code;
  210. code = image[pe_sec->raw_data_offset + ofs - 1];
  211. if (((code != 0xe8) && (code != 0xe9)) || (*addr))
  212. grub_util_error ("invalid relocation (%x %x)", code, *addr);
  213. modified = 1;
  214. if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx)
  215. {
  216. if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx
  217. != shdr[i].sh_info)
  218. grub_util_error ("cross section call is not allowed");
  219. *addr = (symtab[symtab_map[pe_rel->symtab_index]].st_value
  220. - ofs - 4);
  221. continue;
  222. }
  223. else
  224. *addr = -4;
  225. }
  226. rel[num_rels].r_offset = ofs;
  227. rel[num_rels].r_info = ELF32_R_INFO (symtab_map[pe_rel->symtab_index],
  228. type);
  229. num_rels++;
  230. }
  231. if (modified)
  232. grub_util_write_image_at (image + pe_sec->raw_data_offset,
  233. shdr[shdr[i].sh_info].sh_size,
  234. shdr[shdr[i].sh_info].sh_offset,
  235. fp);
  236. shdr[i].sh_type = SHT_REL;
  237. shdr[i].sh_offset = offset;
  238. shdr[i].sh_link = SYMTAB_SECTION;
  239. shdr[i].sh_addralign = 4;
  240. shdr[i].sh_entsize = sizeof (Elf32_Rel);
  241. shdr[i].sh_size = num_rels * sizeof (Elf32_Rel);
  242. grub_util_write_image_at (rel, shdr[i].sh_size, offset, fp);
  243. offset += shdr[i].sh_size;
  244. free (rel);
  245. }
  246. }
  247. static void
  248. write_symbol_table (FILE* fp, char *image,
  249. struct grub_pe32_coff_header *pe_chdr,
  250. struct grub_pe32_section_table *pe_shdr,
  251. int *section_map)
  252. {
  253. struct grub_pe32_symbol *pe_symtab;
  254. char *pe_strtab;
  255. Elf32_Sym *symtab;
  256. int *symtab_map, num_syms;
  257. int i;
  258. pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset);
  259. pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols);
  260. symtab = (Elf32_Sym *) xmalloc ((pe_chdr->num_symbols + 1) *
  261. sizeof (Elf32_Sym));
  262. memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf32_Sym));
  263. num_syms = 1;
  264. symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int));
  265. for (i = 0; i < (int) pe_chdr->num_symbols;
  266. i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1)
  267. {
  268. int bind, type;
  269. symtab_map[i] = -1;
  270. if ((pe_symtab->section > pe_chdr->num_sections) ||
  271. (section_map[pe_symtab->section] == -1))
  272. continue;
  273. if (! pe_symtab->section)
  274. type = STT_NOTYPE;
  275. else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION)
  276. type = STT_FUNC;
  277. else
  278. type = STT_OBJECT;
  279. if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL)
  280. bind = STB_GLOBAL;
  281. else
  282. bind = STB_LOCAL;
  283. if ((type != STT_FUNC) && (pe_symtab->num_aux))
  284. {
  285. if (! pe_symtab->value)
  286. type = STT_SECTION;
  287. symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name;
  288. }
  289. else
  290. {
  291. char short_name[9];
  292. char *name;
  293. if (pe_symtab->long_name[0])
  294. {
  295. strncpy (short_name, pe_symtab->short_name, 8);
  296. short_name[8] = 0;
  297. name = short_name;
  298. }
  299. else
  300. name = pe_strtab + pe_symtab->long_name[1];
  301. if ((strcmp (name, "_grub_mod_init")) &&
  302. (strcmp (name, "_grub_mod_fini")) &&
  303. (bind == STB_LOCAL))
  304. continue;
  305. symtab[num_syms].st_name = insert_string (name);
  306. }
  307. symtab[num_syms].st_shndx = section_map[pe_symtab->section];
  308. symtab[num_syms].st_value = pe_symtab->value;
  309. symtab[num_syms].st_info = ELF32_ST_INFO (bind, type);
  310. symtab_map[i] = num_syms;
  311. num_syms++;
  312. }
  313. write_reloc_section (fp, image, pe_chdr, pe_shdr, symtab, symtab_map);
  314. shdr[SYMTAB_SECTION].sh_name = insert_string (".symtab");
  315. shdr[SYMTAB_SECTION].sh_type = SHT_SYMTAB;
  316. shdr[SYMTAB_SECTION].sh_offset = offset;
  317. shdr[SYMTAB_SECTION].sh_size = num_syms * sizeof (Elf32_Sym);
  318. shdr[SYMTAB_SECTION].sh_entsize = sizeof (Elf32_Sym);
  319. shdr[SYMTAB_SECTION].sh_link = STRTAB_SECTION;
  320. shdr[SYMTAB_SECTION].sh_addralign = 4;
  321. grub_util_write_image_at (symtab, shdr[SYMTAB_SECTION].sh_size,
  322. offset, fp);
  323. offset += shdr[SYMTAB_SECTION].sh_size;
  324. free (symtab);
  325. free (symtab_map);
  326. }
  327. static void
  328. write_string_table (FILE* fp)
  329. {
  330. shdr[STRTAB_SECTION].sh_name = insert_string (".strtab");
  331. shdr[STRTAB_SECTION].sh_type = SHT_STRTAB;
  332. shdr[STRTAB_SECTION].sh_offset = offset;
  333. shdr[STRTAB_SECTION].sh_size = strtab_len;
  334. shdr[STRTAB_SECTION].sh_addralign = 1;
  335. grub_util_write_image_at (strtab, strtab_len, offset, fp);
  336. offset += strtab_len;
  337. free (strtab);
  338. }
  339. static void
  340. write_section_header (FILE* fp)
  341. {
  342. ehdr.e_ident[EI_MAG0] = ELFMAG0;
  343. ehdr.e_ident[EI_MAG1] = ELFMAG1;
  344. ehdr.e_ident[EI_MAG2] = ELFMAG2;
  345. ehdr.e_ident[EI_MAG3] = ELFMAG3;
  346. ehdr.e_ident[EI_VERSION] = EV_CURRENT;
  347. ehdr.e_version = EV_CURRENT;
  348. ehdr.e_type = ET_REL;
  349. ehdr.e_ident[EI_CLASS] = ELFCLASS32;
  350. ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
  351. ehdr.e_machine = EM_386;
  352. ehdr.e_ehsize = sizeof (ehdr);
  353. ehdr.e_shentsize = sizeof (Elf32_Shdr);
  354. ehdr.e_shstrndx = STRTAB_SECTION;
  355. ehdr.e_shoff = offset;
  356. ehdr.e_shnum = num_sections;
  357. grub_util_write_image_at (&shdr, sizeof (Elf32_Shdr) * num_sections,
  358. offset, fp);
  359. grub_util_write_image_at (&ehdr, sizeof (Elf32_Ehdr), 0, fp);
  360. }
  361. static void
  362. convert_pe (FILE* fp, char *image)
  363. {
  364. struct grub_pe32_coff_header *pe_chdr;
  365. struct grub_pe32_section_table *pe_shdr;
  366. int *section_map;
  367. pe_chdr = (struct grub_pe32_coff_header *) image;
  368. if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386)
  369. grub_util_error ("invalid coff image");
  370. strtab = xmalloc (STRTAB_BLOCK);
  371. strtab_max = STRTAB_BLOCK;
  372. strtab[0] = 0;
  373. strtab_len = 1;
  374. offset = sizeof (ehdr);
  375. pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1);
  376. num_sections = REL_SECTION;
  377. section_map = write_section_data (fp, image, pe_chdr, pe_shdr);
  378. write_symbol_table (fp, image, pe_chdr, pe_shdr, section_map);
  379. free (section_map);
  380. write_string_table (fp);
  381. write_section_header (fp);
  382. }
  383. int
  384. main (int argc, char *argv[])
  385. {
  386. char *image;
  387. FILE* fp;
  388. set_program_name (argv[0]);
  389. /* Check for options. */
  390. while (1)
  391. {
  392. int c = getopt_long (argc, argv, "hVv", options, 0);
  393. if (c == -1)
  394. break;
  395. else
  396. switch (c)
  397. {
  398. case 'h':
  399. usage (0);
  400. break;
  401. case 'V':
  402. printf ("%s (%s) %s\n", program_name, PACKAGE_NAME, PACKAGE_VERSION);
  403. return 0;
  404. case 'v':
  405. verbosity++;
  406. break;
  407. default:
  408. usage (1);
  409. break;
  410. }
  411. }
  412. /* Obtain PATH. */
  413. if (optind >= argc)
  414. {
  415. fprintf (stderr, "Filename not specified.\n");
  416. usage (1);
  417. }
  418. image = grub_util_read_image (argv[optind]);
  419. if (optind + 1 < argc)
  420. optind++;
  421. fp = fopen (argv[optind], "wb");
  422. if (! fp)
  423. grub_util_error ("cannot open %s", argv[optind]);
  424. convert_pe (fp, image);
  425. fclose (fp);
  426. return 0;
  427. }