1 /* grub-pe2elf.c - tool to convert pe image to elf. */
3 * GRUB -- GRand Unified Bootloader
4 * Copyright (C) 2008,2009 Free Software Foundation, Inc.
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.
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.
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/>.
21 #include <grub/types.h>
22 #include <grub/util/misc.h>
24 #include <grub/efi/pe32.h>
34 static struct option options
[] = {
35 {"help", no_argument
, 0, 'h'},
36 {"version", no_argument
, 0, 'V'},
37 {"verbose", no_argument
, 0, 'v'},
45 fprintf (stderr
, "Try `%s --help' for more information.\n", program_name
);
48 Usage: %s [OPTIONS] input [output]\n\
50 Tool to convert pe image to elf.\n\
52 -h, --help display this message and exit\n\
53 -V, --version print version information and exit\n\
54 -v, --verbose print verbose messages\n\
56 Report bugs to <%s>.\n", program_name
, PACKAGE_BUGREPORT
);
76 #define TEXT_SECTION 1
77 #define RDATA_SECTION 2
78 #define DATA_SECTION 3
80 #define MODNAME_SECTION 5
81 #define MODDEPS_SECTION 6
82 #define MODLICENSE_SECTION 7
83 #define SYMTAB_SECTION 8
84 #define STRTAB_SECTION 9
86 #define REL_SECTION 10
87 #define MAX_SECTIONS 16
89 #define STRTAB_BLOCK 256
92 static int strtab_max
, strtab_len
;
95 Elf32_Shdr shdr
[MAX_SECTIONS
];
100 insert_string (const char *name
)
108 if (strtab_len
+ len
>= strtab_max
)
110 strtab_max
+= STRTAB_BLOCK
;
111 strtab
= xrealloc (strtab
, strtab_max
);
114 strcpy (strtab
+ strtab_len
, name
);
116 strtab_len
+= len
+ 1;
122 write_section_data (FILE* fp
, char *image
,
123 struct grub_pe32_coff_header
*pe_chdr
,
124 struct grub_pe32_section_table
*pe_shdr
)
128 char *pe_strtab
= (image
+ pe_chdr
->symtab_offset
129 + pe_chdr
->num_symbols
* sizeof (struct grub_pe32_symbol
));
131 section_map
= xmalloc ((pe_chdr
->num_sections
+ 1) * sizeof (int));
134 for (i
= 0; i
< pe_chdr
->num_sections
; i
++, pe_shdr
++)
137 const char *name
= pe_shdr
->name
;
139 if (name
[0] == '/' && isdigit (name
[1]))
141 char t
[sizeof (pe_shdr
->name
) + 1];
142 memcpy (t
, name
, sizeof (pe_shdr
->name
));
143 t
[sizeof (pe_shdr
->name
)] = 0;
144 name
= pe_strtab
+ atoi (t
+ 1);
147 if (! strcmp (name
, ".text"))
150 shdr
[idx
].sh_flags
= SHF_ALLOC
| SHF_EXECINSTR
;
152 else if (! strcmp (name
, ".rdata"))
155 shdr
[idx
].sh_flags
= SHF_ALLOC
;
157 else if (! strcmp (name
, ".data"))
160 shdr
[idx
].sh_flags
= SHF_ALLOC
| SHF_WRITE
;
162 else if (! strcmp (name
, ".bss"))
165 shdr
[idx
].sh_flags
= SHF_ALLOC
| SHF_WRITE
;
167 else if (! strcmp (name
, ".modname"))
168 idx
= MODNAME_SECTION
;
169 else if (! strcmp (name
, ".moddeps"))
170 idx
= MODDEPS_SECTION
;
171 else if (strcmp (name
, ".module_license") == 0)
172 idx
= MODLICENSE_SECTION
;
175 section_map
[i
+ 1] = -1;
179 section_map
[i
+ 1] = idx
;
181 shdr
[idx
].sh_type
= (idx
== BSS_SECTION
) ? SHT_NOBITS
: SHT_PROGBITS
;
182 shdr
[idx
].sh_size
= pe_shdr
->raw_data_size
;
183 shdr
[idx
].sh_addralign
= 1 << (((pe_shdr
->characteristics
>>
184 GRUB_PE32_SCN_ALIGN_SHIFT
) &
185 GRUB_PE32_SCN_ALIGN_MASK
) - 1);
187 if (idx
!= BSS_SECTION
)
189 shdr
[idx
].sh_offset
= offset
;
190 grub_util_write_image_at (image
+ pe_shdr
->raw_data_offset
,
191 pe_shdr
->raw_data_size
, offset
, fp
);
193 offset
+= pe_shdr
->raw_data_size
;
196 if (pe_shdr
->relocations_offset
)
198 char relname
[5 + strlen (name
)];
200 if (num_sections
>= MAX_SECTIONS
)
201 grub_util_error ("too many sections");
203 sprintf (relname
, ".rel%s", name
);
205 shdr
[num_sections
].sh_name
= insert_string (relname
);
206 shdr
[num_sections
].sh_link
= i
;
207 shdr
[num_sections
].sh_info
= idx
;
209 shdr
[idx
].sh_name
= shdr
[num_sections
].sh_name
+ 4;
214 shdr
[idx
].sh_name
= insert_string (name
);
221 write_reloc_section (FILE* fp
, char *image
,
222 struct grub_pe32_coff_header
*pe_chdr
,
223 struct grub_pe32_section_table
*pe_shdr
,
229 for (i
= REL_SECTION
; i
< num_sections
; i
++)
231 struct grub_pe32_section_table
*pe_sec
;
232 struct grub_pe32_reloc
*pe_rel
;
234 int num_rels
, j
, modified
;
236 pe_sec
= pe_shdr
+ shdr
[i
].sh_link
;
237 pe_rel
= (struct grub_pe32_reloc
*) (image
+ pe_sec
->relocations_offset
);
238 rel
= (Elf32_Rel
*) xmalloc (pe_sec
->num_relocations
* sizeof (Elf32_Rel
));
242 for (j
= 0; j
< pe_sec
->num_relocations
; j
++, pe_rel
++)
245 grub_uint32_t ofs
, *addr
;
247 if ((pe_rel
->symtab_index
>= pe_chdr
->num_symbols
) ||
248 (symtab_map
[pe_rel
->symtab_index
] == -1))
249 grub_util_error ("invalid symbol");
251 if (pe_rel
->type
== GRUB_PE32_REL_I386_DIR32
)
253 else if (pe_rel
->type
== GRUB_PE32_REL_I386_REL32
)
256 grub_util_error ("unknown pe relocation type %d\n", pe_rel
->type
);
258 ofs
= pe_rel
->offset
- pe_sec
->virtual_address
;
259 addr
= (grub_uint32_t
*)(image
+ pe_sec
->raw_data_offset
+ ofs
);
260 if (type
== R_386_PC32
)
264 code
= image
[pe_sec
->raw_data_offset
+ ofs
- 1];
266 if (((code
!= 0xe8) && (code
!= 0xe9)) || (*addr
))
267 grub_util_error ("invalid relocation (%x %x)", code
, *addr
);
270 if (symtab
[symtab_map
[pe_rel
->symtab_index
]].st_shndx
)
272 if (symtab
[symtab_map
[pe_rel
->symtab_index
]].st_shndx
274 grub_util_error ("cross section call is not allowed");
276 *addr
= (symtab
[symtab_map
[pe_rel
->symtab_index
]].st_value
285 rel
[num_rels
].r_offset
= ofs
;
286 rel
[num_rels
].r_info
= ELF32_R_INFO (symtab_map
[pe_rel
->symtab_index
],
292 grub_util_write_image_at (image
+ pe_sec
->raw_data_offset
,
293 shdr
[shdr
[i
].sh_info
].sh_size
,
294 shdr
[shdr
[i
].sh_info
].sh_offset
,
297 shdr
[i
].sh_type
= SHT_REL
;
298 shdr
[i
].sh_offset
= offset
;
299 shdr
[i
].sh_link
= SYMTAB_SECTION
;
300 shdr
[i
].sh_addralign
= 4;
301 shdr
[i
].sh_entsize
= sizeof (Elf32_Rel
);
302 shdr
[i
].sh_size
= num_rels
* sizeof (Elf32_Rel
);
304 grub_util_write_image_at (rel
, shdr
[i
].sh_size
, offset
, fp
);
305 offset
+= shdr
[i
].sh_size
;
311 write_symbol_table (FILE* fp
, char *image
,
312 struct grub_pe32_coff_header
*pe_chdr
,
313 struct grub_pe32_section_table
*pe_shdr
,
316 struct grub_pe32_symbol
*pe_symtab
;
319 int *symtab_map
, num_syms
;
322 pe_symtab
= (struct grub_pe32_symbol
*) (image
+ pe_chdr
->symtab_offset
);
323 pe_strtab
= (char *) (pe_symtab
+ pe_chdr
->num_symbols
);
325 symtab
= (Elf32_Sym
*) xmalloc ((pe_chdr
->num_symbols
+ 1) *
327 memset (symtab
, 0, (pe_chdr
->num_symbols
+ 1) * sizeof (Elf32_Sym
));
330 symtab_map
= (int *) xmalloc (pe_chdr
->num_symbols
* sizeof (int));
332 for (i
= 0; i
< (int) pe_chdr
->num_symbols
;
333 i
+= pe_symtab
->num_aux
+ 1, pe_symtab
+= pe_symtab
->num_aux
+ 1)
338 if ((pe_symtab
->section
> pe_chdr
->num_sections
) ||
339 (section_map
[pe_symtab
->section
] == -1))
342 if (! pe_symtab
->section
)
344 else if (pe_symtab
->type
== GRUB_PE32_DT_FUNCTION
)
349 if (pe_symtab
->storage_class
== GRUB_PE32_SYM_CLASS_EXTERNAL
)
354 if ((pe_symtab
->type
!= GRUB_PE32_DT_FUNCTION
) && (pe_symtab
->num_aux
))
356 if (! pe_symtab
->value
)
359 symtab
[num_syms
].st_name
= shdr
[section_map
[pe_symtab
->section
]].sh_name
;
366 if (pe_symtab
->long_name
[0])
368 strncpy (short_name
, pe_symtab
->short_name
, 8);
373 name
= pe_strtab
+ pe_symtab
->long_name
[1];
375 if ((strcmp (name
, "_grub_mod_init")) &&
376 (strcmp (name
, "_grub_mod_fini")) &&
380 symtab
[num_syms
].st_name
= insert_string (name
);
383 symtab
[num_syms
].st_shndx
= section_map
[pe_symtab
->section
];
384 symtab
[num_syms
].st_value
= pe_symtab
->value
;
385 symtab
[num_syms
].st_info
= ELF32_ST_INFO (bind
, type
);
387 symtab_map
[i
] = num_syms
;
391 write_reloc_section (fp
, image
, pe_chdr
, pe_shdr
, symtab
, symtab_map
);
393 shdr
[SYMTAB_SECTION
].sh_name
= insert_string (".symtab");
394 shdr
[SYMTAB_SECTION
].sh_type
= SHT_SYMTAB
;
395 shdr
[SYMTAB_SECTION
].sh_offset
= offset
;
396 shdr
[SYMTAB_SECTION
].sh_size
= num_syms
* sizeof (Elf32_Sym
);
397 shdr
[SYMTAB_SECTION
].sh_entsize
= sizeof (Elf32_Sym
);
398 shdr
[SYMTAB_SECTION
].sh_link
= STRTAB_SECTION
;
399 shdr
[SYMTAB_SECTION
].sh_addralign
= 4;
401 grub_util_write_image_at (symtab
, shdr
[SYMTAB_SECTION
].sh_size
,
403 offset
+= shdr
[SYMTAB_SECTION
].sh_size
;
410 write_string_table (FILE* fp
)
412 shdr
[STRTAB_SECTION
].sh_name
= insert_string (".strtab");
413 shdr
[STRTAB_SECTION
].sh_type
= SHT_STRTAB
;
414 shdr
[STRTAB_SECTION
].sh_offset
= offset
;
415 shdr
[STRTAB_SECTION
].sh_size
= strtab_len
;
416 shdr
[STRTAB_SECTION
].sh_addralign
= 1;
417 grub_util_write_image_at (strtab
, strtab_len
, offset
, fp
);
418 offset
+= strtab_len
;
424 write_section_header (FILE* fp
)
426 ehdr
.e_ident
[EI_MAG0
] = ELFMAG0
;
427 ehdr
.e_ident
[EI_MAG1
] = ELFMAG1
;
428 ehdr
.e_ident
[EI_MAG2
] = ELFMAG2
;
429 ehdr
.e_ident
[EI_MAG3
] = ELFMAG3
;
430 ehdr
.e_ident
[EI_VERSION
] = EV_CURRENT
;
431 ehdr
.e_version
= EV_CURRENT
;
432 ehdr
.e_type
= ET_REL
;
434 ehdr
.e_ident
[EI_CLASS
] = ELFCLASS32
;
435 ehdr
.e_ident
[EI_DATA
] = ELFDATA2LSB
;
436 ehdr
.e_machine
= EM_386
;
438 ehdr
.e_ehsize
= sizeof (ehdr
);
439 ehdr
.e_shentsize
= sizeof (Elf32_Shdr
);
440 ehdr
.e_shstrndx
= STRTAB_SECTION
;
442 ehdr
.e_shoff
= offset
;
443 ehdr
.e_shnum
= num_sections
;
444 grub_util_write_image_at (&shdr
, sizeof (Elf32_Shdr
) * num_sections
,
447 grub_util_write_image_at (&ehdr
, sizeof (Elf32_Ehdr
), 0, fp
);
451 convert_pe (FILE* fp
, char *image
)
453 struct grub_pe32_coff_header
*pe_chdr
;
454 struct grub_pe32_section_table
*pe_shdr
;
457 pe_chdr
= (struct grub_pe32_coff_header
*) image
;
458 if (grub_le_to_cpu16 (pe_chdr
->machine
) != GRUB_PE32_MACHINE_I386
)
459 grub_util_error ("invalid coff image");
461 strtab
= xmalloc (STRTAB_BLOCK
);
462 strtab_max
= STRTAB_BLOCK
;
466 offset
= sizeof (ehdr
);
467 pe_shdr
= (struct grub_pe32_section_table
*) (pe_chdr
+ 1);
468 num_sections
= REL_SECTION
;
470 section_map
= write_section_data (fp
, image
, pe_chdr
, pe_shdr
);
472 write_symbol_table (fp
, image
, pe_chdr
, pe_shdr
, section_map
);
475 write_string_table (fp
);
477 write_section_header (fp
);
481 main (int argc
, char *argv
[])
486 set_program_name (argv
[0]);
488 /* Check for options. */
491 int c
= getopt_long (argc
, argv
, "hVv", options
, 0);
503 printf ("%s (%s) %s\n", program_name
, PACKAGE_NAME
, PACKAGE_VERSION
);
519 fprintf (stderr
, "Filename not specified.\n");
523 image
= grub_util_read_image (argv
[optind
]);
525 if (optind
+ 1 < argc
)
528 fp
= fopen (argv
[optind
], "wb");
530 grub_util_error ("cannot open %s", argv
[optind
]);
532 convert_pe (fp
, image
);