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>
25 #include <grub/misc.h>
35 /* Please don't internationalise this file. It's pointless. */
37 static struct option options
[] = {
38 {"help", no_argument
, 0, 'h'},
39 {"version", no_argument
, 0, 'V'},
40 {"verbose", no_argument
, 0, 'v'},
44 static void __attribute__ ((noreturn
))
48 fprintf (stderr
, "Try `%s --help' for more information.\n", program_name
);
51 Usage: %s [OPTIONS] input [output]\n\
53 Tool to convert pe image to elf.\n\
55 -h, --help display this message and exit\n\
56 -V, --version print version information and exit\n\
57 -v, --verbose print verbose messages\n\
59 Report bugs to <%s>.\n", program_name
, PACKAGE_BUGREPORT
);
79 #define TEXT_SECTION 1
80 #define RDATA_SECTION 2
81 #define DATA_SECTION 3
83 #define MODNAME_SECTION 5
84 #define MODDEPS_SECTION 6
85 #define MODLICENSE_SECTION 7
86 #define SYMTAB_SECTION 8
87 #define STRTAB_SECTION 9
89 #define REL_SECTION 10
91 /* 10 normal section + up to 4 relocation (.text, .rdata, .data, .symtab). */
92 #define MAX_SECTIONS 16
94 #define STRTAB_BLOCK 256
97 static int strtab_max
, strtab_len
;
99 static Elf32_Ehdr ehdr
;
100 static Elf32_Shdr shdr
[MAX_SECTIONS
];
101 static int num_sections
;
102 static grub_uint32_t offset
;
105 insert_string (const char *name
)
113 if (strtab_len
+ len
>= strtab_max
)
115 strtab_max
+= STRTAB_BLOCK
;
116 strtab
= xrealloc (strtab
, strtab_max
);
119 strcpy (strtab
+ strtab_len
, name
);
121 strtab_len
+= len
+ 1;
127 write_section_data (FILE* fp
, const char *name
, char *image
,
128 struct grub_pe32_coff_header
*pe_chdr
,
129 struct grub_pe32_section_table
*pe_shdr
)
133 char *pe_strtab
= (image
+ pe_chdr
->symtab_offset
134 + pe_chdr
->num_symbols
* sizeof (struct grub_pe32_symbol
));
136 section_map
= xmalloc ((pe_chdr
->num_sections
+ 1) * sizeof (int));
139 for (i
= 0; i
< pe_chdr
->num_sections
; i
++, pe_shdr
++)
142 const char *shname
= pe_shdr
->name
;
144 if (shname
[0] == '/' && grub_isdigit (shname
[1]))
146 char t
[sizeof (pe_shdr
->name
) + 1];
147 memcpy (t
, shname
, sizeof (pe_shdr
->name
));
148 t
[sizeof (pe_shdr
->name
)] = 0;
149 shname
= pe_strtab
+ atoi (t
+ 1);
152 if (! strcmp (shname
, ".text"))
155 shdr
[idx
].sh_flags
= SHF_ALLOC
| SHF_EXECINSTR
;
157 else if (! strcmp (shname
, ".rdata"))
160 shdr
[idx
].sh_flags
= SHF_ALLOC
;
162 else if (! strcmp (shname
, ".data"))
165 shdr
[idx
].sh_flags
= SHF_ALLOC
| SHF_WRITE
;
167 else if (! strcmp (shname
, ".bss"))
170 shdr
[idx
].sh_flags
= SHF_ALLOC
| SHF_WRITE
;
172 else if (! strcmp (shname
, ".modname"))
173 idx
= MODNAME_SECTION
;
174 else if (! strcmp (shname
, ".moddeps"))
175 idx
= MODDEPS_SECTION
;
176 else if (strcmp (shname
, ".module_license") == 0)
177 idx
= MODLICENSE_SECTION
;
180 section_map
[i
+ 1] = -1;
184 section_map
[i
+ 1] = idx
;
186 shdr
[idx
].sh_type
= (idx
== BSS_SECTION
) ? SHT_NOBITS
: SHT_PROGBITS
;
187 shdr
[idx
].sh_size
= pe_shdr
->raw_data_size
;
188 shdr
[idx
].sh_addralign
= 1 << (((pe_shdr
->characteristics
>>
189 GRUB_PE32_SCN_ALIGN_SHIFT
) &
190 GRUB_PE32_SCN_ALIGN_MASK
) - 1);
192 if (idx
!= BSS_SECTION
)
194 shdr
[idx
].sh_offset
= offset
;
195 grub_util_write_image_at (image
+ pe_shdr
->raw_data_offset
,
196 pe_shdr
->raw_data_size
, offset
, fp
,
199 offset
+= pe_shdr
->raw_data_size
;
202 if (pe_shdr
->relocations_offset
)
204 char relname
[5 + strlen (shname
)];
206 if (num_sections
>= MAX_SECTIONS
)
207 grub_util_error ("too many sections");
209 sprintf (relname
, ".rel%s", shname
);
211 shdr
[num_sections
].sh_name
= insert_string (relname
);
212 shdr
[num_sections
].sh_link
= i
;
213 shdr
[num_sections
].sh_info
= idx
;
215 shdr
[idx
].sh_name
= shdr
[num_sections
].sh_name
+ 4;
220 shdr
[idx
].sh_name
= insert_string (shname
);
227 write_reloc_section (FILE* fp
, const char *name
, char *image
,
228 struct grub_pe32_coff_header
*pe_chdr
,
229 struct grub_pe32_section_table
*pe_shdr
,
235 for (i
= REL_SECTION
; i
< num_sections
; i
++)
237 struct grub_pe32_section_table
*pe_sec
;
238 struct grub_pe32_reloc
*pe_rel
;
240 int num_rels
, j
, modified
;
242 pe_sec
= pe_shdr
+ shdr
[i
].sh_link
;
243 pe_rel
= (struct grub_pe32_reloc
*) (image
+ pe_sec
->relocations_offset
);
244 rel
= (Elf32_Rel
*) xmalloc (pe_sec
->num_relocations
* sizeof (Elf32_Rel
));
248 for (j
= 0; j
< pe_sec
->num_relocations
; j
++, pe_rel
++)
251 grub_uint32_t ofs
, *addr
;
253 if ((pe_rel
->symtab_index
>= pe_chdr
->num_symbols
) ||
254 (symtab_map
[pe_rel
->symtab_index
] == -1))
255 grub_util_error ("invalid symbol");
257 if (pe_rel
->type
== GRUB_PE32_REL_I386_DIR32
)
259 else if (pe_rel
->type
== GRUB_PE32_REL_I386_REL32
)
262 grub_util_error ("unknown pe relocation type %d\n", pe_rel
->type
);
264 ofs
= pe_rel
->offset
- pe_sec
->virtual_address
;
265 addr
= (grub_uint32_t
*)(image
+ pe_sec
->raw_data_offset
+ ofs
);
266 if (type
== R_386_PC32
)
270 code
= image
[pe_sec
->raw_data_offset
+ ofs
- 1];
272 if (((code
!= 0xe8) && (code
!= 0xe9)) || (*addr
))
273 grub_util_error ("invalid relocation (%x %x)", code
, *addr
);
276 if (symtab
[symtab_map
[pe_rel
->symtab_index
]].st_shndx
)
278 if (symtab
[symtab_map
[pe_rel
->symtab_index
]].st_shndx
280 grub_util_error ("cross section call is not allowed");
282 *addr
= (symtab
[symtab_map
[pe_rel
->symtab_index
]].st_value
291 rel
[num_rels
].r_offset
= ofs
;
292 rel
[num_rels
].r_info
= ELF32_R_INFO (symtab_map
[pe_rel
->symtab_index
],
298 grub_util_write_image_at (image
+ pe_sec
->raw_data_offset
,
299 shdr
[shdr
[i
].sh_info
].sh_size
,
300 shdr
[shdr
[i
].sh_info
].sh_offset
,
303 shdr
[i
].sh_type
= SHT_REL
;
304 shdr
[i
].sh_offset
= offset
;
305 shdr
[i
].sh_link
= SYMTAB_SECTION
;
306 shdr
[i
].sh_addralign
= 4;
307 shdr
[i
].sh_entsize
= sizeof (Elf32_Rel
);
308 shdr
[i
].sh_size
= num_rels
* sizeof (Elf32_Rel
);
310 grub_util_write_image_at (rel
, shdr
[i
].sh_size
, offset
, fp
, name
);
311 offset
+= shdr
[i
].sh_size
;
317 write_symbol_table (FILE* fp
, const char *name
, char *image
,
318 struct grub_pe32_coff_header
*pe_chdr
,
319 struct grub_pe32_section_table
*pe_shdr
,
322 struct grub_pe32_symbol
*pe_symtab
;
325 int *symtab_map
, num_syms
;
328 pe_symtab
= (struct grub_pe32_symbol
*) (image
+ pe_chdr
->symtab_offset
);
329 pe_strtab
= (char *) (pe_symtab
+ pe_chdr
->num_symbols
);
331 symtab
= (Elf32_Sym
*) xmalloc ((pe_chdr
->num_symbols
+ 1) *
333 memset (symtab
, 0, (pe_chdr
->num_symbols
+ 1) * sizeof (Elf32_Sym
));
336 symtab_map
= (int *) xmalloc (pe_chdr
->num_symbols
* sizeof (int));
338 for (i
= 0; i
< (int) pe_chdr
->num_symbols
;
339 i
+= pe_symtab
->num_aux
+ 1, pe_symtab
+= pe_symtab
->num_aux
+ 1)
344 if ((pe_symtab
->section
> pe_chdr
->num_sections
) ||
345 (section_map
[pe_symtab
->section
] == -1))
348 if (! pe_symtab
->section
)
350 else if (pe_symtab
->type
== GRUB_PE32_DT_FUNCTION
)
355 if (pe_symtab
->storage_class
== GRUB_PE32_SYM_CLASS_EXTERNAL
)
360 if ((pe_symtab
->type
!= GRUB_PE32_DT_FUNCTION
) && (pe_symtab
->num_aux
))
362 if (! pe_symtab
->value
)
365 symtab
[num_syms
].st_name
= shdr
[section_map
[pe_symtab
->section
]].sh_name
;
372 if (pe_symtab
->long_name
[0])
374 strncpy (short_name
, pe_symtab
->short_name
, 8);
376 symname
= short_name
;
379 symname
= pe_strtab
+ pe_symtab
->long_name
[1];
381 if ((strcmp (symname
, "_grub_mod_init")) &&
382 (strcmp (symname
, "_grub_mod_fini")) &&
386 symtab
[num_syms
].st_name
= insert_string (symname
);
389 symtab
[num_syms
].st_shndx
= section_map
[pe_symtab
->section
];
390 symtab
[num_syms
].st_value
= pe_symtab
->value
;
391 symtab
[num_syms
].st_info
= ELF32_ST_INFO (bind
, type
);
393 symtab_map
[i
] = num_syms
;
397 write_reloc_section (fp
, name
, image
, pe_chdr
, pe_shdr
,
400 shdr
[SYMTAB_SECTION
].sh_name
= insert_string (".symtab");
401 shdr
[SYMTAB_SECTION
].sh_type
= SHT_SYMTAB
;
402 shdr
[SYMTAB_SECTION
].sh_offset
= offset
;
403 shdr
[SYMTAB_SECTION
].sh_size
= num_syms
* sizeof (Elf32_Sym
);
404 shdr
[SYMTAB_SECTION
].sh_entsize
= sizeof (Elf32_Sym
);
405 shdr
[SYMTAB_SECTION
].sh_link
= STRTAB_SECTION
;
406 shdr
[SYMTAB_SECTION
].sh_addralign
= 4;
408 grub_util_write_image_at (symtab
, shdr
[SYMTAB_SECTION
].sh_size
,
410 offset
+= shdr
[SYMTAB_SECTION
].sh_size
;
417 write_string_table (FILE *fp
, const char *name
)
419 shdr
[STRTAB_SECTION
].sh_name
= insert_string (".strtab");
420 shdr
[STRTAB_SECTION
].sh_type
= SHT_STRTAB
;
421 shdr
[STRTAB_SECTION
].sh_offset
= offset
;
422 shdr
[STRTAB_SECTION
].sh_size
= strtab_len
;
423 shdr
[STRTAB_SECTION
].sh_addralign
= 1;
424 grub_util_write_image_at (strtab
, strtab_len
, offset
, fp
,
426 offset
+= strtab_len
;
432 write_section_header (FILE *fp
, const char *name
)
434 ehdr
.e_ident
[EI_MAG0
] = ELFMAG0
;
435 ehdr
.e_ident
[EI_MAG1
] = ELFMAG1
;
436 ehdr
.e_ident
[EI_MAG2
] = ELFMAG2
;
437 ehdr
.e_ident
[EI_MAG3
] = ELFMAG3
;
438 ehdr
.e_ident
[EI_VERSION
] = EV_CURRENT
;
439 ehdr
.e_version
= EV_CURRENT
;
440 ehdr
.e_type
= ET_REL
;
442 ehdr
.e_ident
[EI_CLASS
] = ELFCLASS32
;
443 ehdr
.e_ident
[EI_DATA
] = ELFDATA2LSB
;
444 ehdr
.e_machine
= EM_386
;
446 ehdr
.e_ehsize
= sizeof (ehdr
);
447 ehdr
.e_shentsize
= sizeof (Elf32_Shdr
);
448 ehdr
.e_shstrndx
= STRTAB_SECTION
;
450 ehdr
.e_shoff
= offset
;
451 ehdr
.e_shnum
= num_sections
;
452 grub_util_write_image_at (&shdr
, sizeof (Elf32_Shdr
) * num_sections
,
455 grub_util_write_image_at (&ehdr
, sizeof (Elf32_Ehdr
), 0, fp
, name
);
459 convert_pe (FILE* fp
, const char *name
, char *image
)
461 struct grub_pe32_coff_header
*pe_chdr
;
462 struct grub_pe32_section_table
*pe_shdr
;
465 pe_chdr
= (struct grub_pe32_coff_header
*) image
;
466 if (grub_le_to_cpu16 (pe_chdr
->machine
) != GRUB_PE32_MACHINE_I386
)
467 grub_util_error ("invalid coff image");
469 strtab
= xmalloc (STRTAB_BLOCK
);
470 strtab_max
= STRTAB_BLOCK
;
474 offset
= sizeof (ehdr
);
475 pe_shdr
= (struct grub_pe32_section_table
*) (pe_chdr
+ 1);
476 num_sections
= REL_SECTION
;
478 section_map
= write_section_data (fp
, name
, image
, pe_chdr
, pe_shdr
);
480 write_symbol_table (fp
, name
, image
, pe_chdr
, pe_shdr
, section_map
);
483 write_string_table (fp
, name
);
485 write_section_header (fp
, name
);
489 main (int argc
, char *argv
[])
494 set_program_name (argv
[0]);
496 /* Check for options. */
499 int c
= getopt_long (argc
, argv
, "hVv", options
, 0);
511 printf ("%s (%s) %s\n", program_name
, PACKAGE_NAME
, PACKAGE_VERSION
);
527 fprintf (stderr
, "Filename not specified.\n");
531 image
= grub_util_read_image (argv
[optind
]);
533 if (optind
+ 1 < argc
)
536 fp
= fopen (argv
[optind
], "wb");
538 grub_util_error ("cannot open %s", argv
[optind
]);
540 convert_pe (fp
, argv
[optind
], image
);