* [PATCH] New tool to convert pe image to elf @ 2008-07-22 21:56 Bean 2008-07-22 22:05 ` Christian Franke 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-07-22 21:56 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 473 bytes --] Hi, This patch add a new tool grub-pe2elf, which can be used to convert pe image created by cygwin. It's written using grub environment, no external library or tool is required. For example, to convert pe module hello.mod to elf: grub-pe2elf hello.mod The relocation issue is fixed, I also remove the underscore from variable names, so that they're the same as linux version. The converted elf module can be used interchangeable with those generated in linux. -- Bean [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: pe2elf.diff --] [-- Type: text/x-diff; name=pe2elf.diff, Size: 16447 bytes --] diff --git a/conf/common.rmk b/conf/common.rmk index b403b04..c0087f5 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -99,6 +99,11 @@ bin_UTILITIES += grub-editenv grub_editenv_SOURCES = util/grub-editenv.c util/envblk.c util/misc.c kern/misc.c kern/err.c CLEANFILES += grub-editenv +# for grub-pe2elf +bin_UTILITIES += grub-pe2elf +grub_pe2elf_SOURCES = util/grub-pe2elf.c util/misc.c +CLEANFILES += grub-pe2elf + # For update-grub update-grub: util/update-grub.in config.status ./config.status --file=$@:$< diff --git a/include/grub/dl.h b/include/grub/dl.h index b630c6f..2eadacc 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -41,10 +41,10 @@ static void \ grub_mod_fini (void) #define GRUB_MOD_NAME(name) \ -__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n") #define GRUB_MOD_DEP(name) \ -__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n") struct grub_dl_segment { diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index c36d859..4b57ade 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -194,6 +194,18 @@ struct grub_pe32_section_table #define GRUB_PE32_SCN_MEM_READ 0x40000000 #define GRUB_PE32_SCN_MEM_WRITE 0x80000000 +#define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 +#define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +#define GRUB_PE32_SCN_ALIGN_4BYTES 0x00300000 +#define GRUB_PE32_SCN_ALIGN_8BYTES 0x00400000 +#define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 +#define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 +#define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 + +#define GRUB_PE32_SCN_ALIGN_SHIFT 20 +#define GRUB_PE32_SCN_ALIGN_MASK 7 + + struct grub_pe32_header { /* This should be filled in with GRUB_PE32_MSDOS_STUB. */ @@ -221,4 +233,35 @@ struct grub_pe32_fixup_block #define GRUB_PE32_REL_BASED_ABSOLUTE 0 #define GRUB_PE32_REL_BASED_HIGHLOW 3 +struct grub_pe32_symbol +{ + union + { + char short_name[8]; + grub_uint32_t long_name[2]; + }; + + grub_uint32_t value; + grub_uint16_t section; + grub_uint16_t type; + grub_uint8_t storage_class; + grub_uint8_t num_aux; +} __attribute__ ((packed)); + +#define GRUB_PE32_SYM_CLASS_EXTERNAL 2 +#define GRUB_PE32_SYM_CLASS_STATIC 3 +#define GRUB_PE32_SYM_CLASS_FILE 0x67 + +#define GRUB_PE32_DT_FUNCTION 0x20 + +struct grub_pe32_reloc +{ + grub_uint32_t offset; + grub_uint32_t symtab_index; + grub_uint16_t type; +} __attribute__ ((packed)); + +#define GRUB_PE32_REL_I386_DIR32 0x6 +#define GRUB_PE32_REL_I386_REL32 0x14 + #endif /* ! GRUB_EFI_PE32_HEADER */ diff --git a/include/grub/symbol.h b/include/grub/symbol.h index aa0ea5a..e951490 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -28,8 +28,14 @@ # define EXT_C(sym) sym #endif +#ifndef __CYGWIN__ #define FUNCTION(x) .globl EXT_C(x) ; .type EXT_C(x), "function" ; EXT_C(x): #define VARIABLE(x) .globl EXT_C(x) ; .type EXT_C(x), "object" ; EXT_C(x): +#else +/* .type not supported for non-ELF targets. XXX: Check this in configure? */ +#define FUNCTION(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 32; .endef; EXT_C(x): +#define VARIABLE(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 0; .endef; EXT_C(x): +#endif /* Mark an exported symbol. */ #ifndef GRUB_SYMBOL_GENERATOR diff --git a/kern/dl.c b/kern/dl.c index c0d9f1d..d606ece 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -454,7 +454,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) const char *name = (char *) e + s->sh_offset; const char *max = name + s->sh_size; - while (name < max) + while ((name < max) && (*name)) { grub_dl_t m; grub_dl_dep_t dep; diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c new file mode 100755 index 0000000..988903e --- /dev/null +++ b/util/grub-pe2elf.c @@ -0,0 +1,453 @@ +/* grub-pe2elf.c - tool to convert pe image to elf. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/util/misc.h> +#include <grub/elf.h> +#include <grub/efi/pe32.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n"); + else + printf ("\ +Usage: grub-editenv [OPTIONS] input [output]\n\ +\n\ +Tool to convert pe image to elf.\n\ +\nOptions:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +/* + * We generate the following sections for elf + * + * null + * .text + * .rel.text + * .rdata + * .data + * .bss + * .modname + * .moddeps + * .symtab + * .strtab + */ + +#define TEXT_SECTION 1 +#define RDATA_SECTION 2 +#define DATA_SECTION 3 +#define BSS_SECTION 4 +#define MODNAME_SECTION 5 +#define MODDEPS_SECTION 6 +#define SYMTAB_SECTION 7 +#define STRTAB_SECTION 8 + +#define REL_SECTION 9 +#define MAX_SECTIONS 12 + +#define STRTAB_BLOCK 256 + +static char *strtab; +static int strtab_max, strtab_len; + +static int +insert_string (char *name) +{ + int len, result; + + if (*name == '_') + name++; + + len = strlen (name); + if (strtab_len + len >= strtab_max) + { + strtab_max += STRTAB_BLOCK; + strtab = xrealloc (strtab, strtab_max); + } + + strcpy (strtab + strtab_len, name); + result = strtab_len; + strtab_len += len + 1; + + return result; +} + +static void +convert_pe (FILE* fp, char *image) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + struct grub_pe32_symbol *pe_symtab; + char *pe_strtab; + int num_sections; + + Elf32_Ehdr ehdr; + Elf32_Shdr shdr[MAX_SECTIONS]; + Elf32_Sym *symtab; + int num_syms; + + int *section_map, *symtab_map; + grub_uint32_t offset; + int i; + + pe_chdr = (struct grub_pe32_coff_header *) image; + if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386) + grub_util_error ("Invalid coff image"); + + memset (&ehdr, 0, sizeof (ehdr)); + memset (&shdr, 0, sizeof (shdr)); + + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_version = EV_CURRENT; + ehdr.e_type = ET_REL; + + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_386; + + ehdr.e_ehsize = sizeof (ehdr); + ehdr.e_shentsize = sizeof (Elf32_Shdr); + ehdr.e_shstrndx = STRTAB_SECTION; + + strtab = xmalloc (STRTAB_BLOCK); + strtab_max = STRTAB_BLOCK; + strtab[0] = 0; + strtab_len = 1; + + offset = sizeof (ehdr); + + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + + section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int)); + section_map[0] = 0; + + num_sections = REL_SECTION; + + for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) + { + grub_uint32_t idx; + + if (! strcmp (pe_shdr->name, ".text")) + { + idx = TEXT_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + } + else if (! strcmp (pe_shdr->name, ".rdata")) + { + idx = RDATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC; + } + else if (! strcmp (pe_shdr->name, ".data")) + { + idx = DATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".bss")) + { + idx = BSS_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".modname")) + idx = MODNAME_SECTION; + else if (! strcmp (pe_shdr->name, ".moddeps")) + idx = MODDEPS_SECTION; + else + { + section_map[i + 1] = -1; + continue; + } + + section_map[i + 1] = idx; + + shdr[idx].sh_type = (idx == BSS_SECTION) ? SHT_NOBITS : SHT_PROGBITS; + shdr[idx].sh_size = pe_shdr->raw_data_size; + shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + + if (idx != BSS_SECTION) + { + shdr[idx].sh_offset = offset; + grub_util_write_image_at (image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size, offset, fp); + + offset += pe_shdr->raw_data_size; + } + + if (pe_shdr->relocations_offset) + { + char name[5 + strlen (pe_shdr->name)]; + + if (num_sections >= MAX_SECTIONS) + grub_util_error ("Too many sections"); + + sprintf (name, ".rel%s", pe_shdr->name); + + shdr[num_sections].sh_name = insert_string (name); + shdr[num_sections].sh_link = i; + shdr[num_sections].sh_info = idx; + + shdr[idx].sh_name = shdr[num_sections].sh_name + 4; + + num_sections++; + } + else + shdr[idx].sh_name = insert_string (pe_shdr->name); + } + + pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset); + pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols); + + symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int)); + symtab = (Elf32_Sym *) xmalloc ((pe_chdr->num_symbols + 1) * + sizeof (Elf32_Sym)); + memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf32_Sym)); + num_syms = 1; + + for (i = 0; i < (int) pe_chdr->num_symbols; + i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1) + { + int bind, type; + + symtab_map[i] = -1; + if ((pe_symtab->section > pe_chdr->num_sections) || + (section_map[pe_symtab->section] == -1)) + continue; + + if (! pe_symtab->section) + type = STT_NOTYPE; + else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION) + type = STT_FUNC; + else + type = STT_OBJECT; + + if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL) + bind = STB_GLOBAL; + else + bind = STB_LOCAL; + + if ((type != STT_FUNC) && (pe_symtab->num_aux)) + { + type = STT_SECTION; + + symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name; + } + else + { + char *name; + + name = ((pe_symtab->long_name[0]) ? pe_symtab->short_name : + pe_strtab + pe_symtab->long_name[1]); + + if ((strcmp (name, "_grub_mod_init")) && + (strcmp (name, "_grub_mod_fini")) && + (bind == STB_LOCAL)) + continue; + + symtab[num_syms].st_name = insert_string (name); + } + + symtab[num_syms].st_shndx = section_map[pe_symtab->section]; + symtab[num_syms].st_value = pe_symtab->value; + symtab[num_syms].st_info = ELF32_ST_INFO (bind, type); + + symtab_map[i] = num_syms; + num_syms++; + } + + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + + for (i = REL_SECTION; i < num_sections; i++) + { + struct grub_pe32_section_table *pe_sec; + struct grub_pe32_reloc *pe_rel; + Elf32_Rel *rel; + grub_uint32_t size; + int j, modified; + + modified = 0; + + pe_sec = pe_shdr + shdr[i].sh_link; + pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset); + size = pe_sec->num_relocations * sizeof (Elf32_Rel); + rel = (Elf32_Rel *) xmalloc (size); + + for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++) + { + int type; + + if ((pe_rel->symtab_index >= pe_chdr->num_symbols) || + (symtab_map[pe_rel->symtab_index] == -1)) + grub_util_error ("Invalid symbol"); + + if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) + type = R_386_32; + else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) + type = R_386_PC32; + else + grub_util_error ("Unknown pe relocation type %d\n", pe_rel->type); + + pe_rel->offset -= pe_sec->virtual_address; + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx == 0) + { + *(grub_uint32_t *)(image + pe_sec->raw_data_offset + + pe_rel->offset) = (grub_uint32_t) -4; + modified = 1; + } + + rel[j].r_offset = pe_rel->offset; + rel[j].r_info = ELF32_R_INFO (symtab_map[pe_rel->symtab_index], + type); + } + + if (modified) + grub_util_write_image_at (image + pe_sec->raw_data_offset, + shdr[shdr[i].sh_info].sh_size, + shdr[shdr[i].sh_info].sh_offset, + fp); + + shdr[i].sh_type = SHT_REL; + shdr[i].sh_offset = offset; + shdr[i].sh_link = SYMTAB_SECTION; + shdr[i].sh_addralign = 4; + shdr[i].sh_entsize = sizeof (Elf32_Rel); + shdr[i].sh_size = size; + + grub_util_write_image_at (rel, size, offset, fp); + offset += size; + free (rel); + } + + shdr[SYMTAB_SECTION].sh_name = insert_string (".symtab"); + shdr[SYMTAB_SECTION].sh_type = SHT_SYMTAB; + shdr[SYMTAB_SECTION].sh_offset = offset; + shdr[SYMTAB_SECTION].sh_size = num_syms * sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_entsize = sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_link = STRTAB_SECTION; + shdr[SYMTAB_SECTION].sh_addralign = 4; + + grub_util_write_image_at (symtab, shdr[SYMTAB_SECTION].sh_size, + offset, fp); + offset += shdr[SYMTAB_SECTION].sh_size; + free (symtab); + + shdr[STRTAB_SECTION].sh_name = insert_string (".strtab"); + shdr[STRTAB_SECTION].sh_type = SHT_STRTAB; + shdr[STRTAB_SECTION].sh_offset = offset; + shdr[STRTAB_SECTION].sh_size = strtab_len; + shdr[STRTAB_SECTION].sh_addralign = 1; + grub_util_write_image_at (strtab, strtab_len, offset, fp); + offset += strtab_len; + free (strtab); + + ehdr.e_shoff = offset; + ehdr.e_shnum = num_sections; + grub_util_write_image_at (&shdr, sizeof (Elf32_Shdr) * num_sections, + offset, fp); + + grub_util_write_image_at (&ehdr, sizeof (Elf32_Ehdr), 0, fp); + + free (section_map); + free (symtab_map); +} + +int +main (int argc, char *argv[]) +{ + char *image; + FILE* fp; + + progname = "grub-pe2elf"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain PATH. */ + if (optind >= argc) + { + fprintf (stderr, "Filename not specified.\n"); + usage (1); + } + + image = grub_util_read_image (argv[optind]); + + if (optind + 1 < argc) + optind++; + + fp = fopen (argv[optind], "wb"); + if (! fp) + grub_util_error ("cannot open %s", argv[optind]); + + convert_pe (fp, image); + + fclose (fp); + + return 0; +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-22 21:56 [PATCH] New tool to convert pe image to elf Bean @ 2008-07-22 22:05 ` Christian Franke 2008-07-23 5:54 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Christian Franke @ 2008-07-22 22:05 UTC (permalink / raw) To: The development of GRUB 2 Bean wrote: > This patch add a new tool grub-pe2elf, which can be used to convert pe > image created by cygwin. It's written using grub environment, no > external library or tool is required. For example, to convert pe > module hello.mod to elf: > > grub-pe2elf hello.mod > > The relocation issue is fixed, I also remove the underscore from > variable names, so that they're the same as linux version. The > converted elf module can be used interchangeable with those generated > in linux. > > Cool! Will test this soon. Christian ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-22 22:05 ` Christian Franke @ 2008-07-23 5:54 ` Bean 2008-07-23 20:28 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-07-23 5:54 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 2675 bytes --] Hi, I change the structure of grub-pe2elf, now it uses sub function to do various task instead of one huge trunk. I also include the build script by Christian Franke, as it's needed to compile successfully in cygwin. I make some adjustment: 1, use grub-pe2elf to generate module file instead of objdump 2, remove the "_" patch for gensymlist.sh.in, it's not needed anymore as grub-pe2elf have removed the underscope, but the genkernsyms.sh.in patch is still needed. With this patch, grub2 works OOTB in cygwin. Changelog: 2008-07-23 Bean <bean123ch@gmail.com> * common.rmk (bin_UTILITIES): Add grub-pe2elf. (grub_pe2elf_SOURCES): New macro. (CLEANFILES): Add grub-pe2elf. * include/grub/efi/pe32.h (GRUB_PE32_SCN_ALIGN_1BYTES): New constant. (GRUB_PE32_SCN_ALIGN_2BYTES): Likewise. (GRUB_PE32_SCN_ALIGN_4BYTES): Likewise. (GRUB_PE32_SCN_ALIGN_8BYTES): Likewise. (GRUB_PE32_SCN_ALIGN_16BYTES): Likewise. (GRUB_PE32_SCN_ALIGN_32BYTES): Likewise. (GRUB_PE32_SCN_ALIGN_64BYTES): Likewise. (GRUB_PE32_SCN_ALIGN_SHIFT): Likewise. (GRUB_PE32_SCN_ALIGN_MASK): Likewise. (GRUB_PE32_SYM_CLASS_EXTERNAL): Likewise. (GRUB_PE32_SYM_CLASS_STATIC): Likewise. (GRUB_PE32_SYM_CLASS_FILE): Likewise. (GRUB_PE32_DT_FUNCTION): Likewise. (GRUB_PE32_REL_I386_DIR32): Likewise. (GRUB_PE32_REL_I386_REL32): Likewise. (grub_pe32_symbol): New structure. (grub_pe32_reloc): Likewise. * util/grub-pe2elf.c: New file. * configure.ac: Set TARGET_OBJ2ELF if host os is cygwin. * genmk.rb: Use TARGET_OBJ2ELF to convert native object format to elf. The following patches are from Christian Franke. * include/grub/dl.h: Remove .previous, gas supports this only for ELF format. * include/grub/symbol.h [__CYGWIN__] (#define FUNCTION/VARIABLE): Remove .type, gas supports this only for ELF format. * kern/dl.c (grub_dl_resolve_dependencies): Add check for trailing nullbytes in symbol table. This fixes an infinite loop if table is zero filled. * Makefile.in: Add autoconf replacements TARGET_IMG_LDSCRIPT, TARGET_IMG_LDFLAGS and EXEEXT. * aclocal.m4 (grub_PROG_OBJCOPY_ABSOLUTE): Replace -Wl,-N by TARGET_IMG_LDFLAGS_AC. (grub_CHECK_STACK_ARG_PROBE): New function. * conf/i386-pc.rmk: Replace -Wl,-N by TARGET_IMG_LDFLAGS. * conf/i386-pc-cygwin-ld-img.sc: New linker script. * configure.ac: Add check for linker script "conf/${target}-img-ld.c" to set TARGET_IMG_LD* accordingly. Add check for Cygwin to set TARGET_MOD_OBJCOPY accordingly. Add call to grub_CHECK_STACK_ARG_PROBE. Use TARGET_IMG_LDFLAGS to check start, bss_start, end symbols. * genkernsyms.sh.in: Handle HAVE_ASM_USCORE case. * genmk.rb: Add EXEEXT to CLEANFILES. -- Bean [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: pe2elf_2.diff --] [-- Type: text/x-diff; name=pe2elf_2.diff, Size: 24112 bytes --] diff --git a/Makefile.in b/Makefile.in index 6f9474c..ccb5497 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,7 +68,11 @@ TARGET_CFLAGS = @TARGET_CFLAGS@ TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -I. -Iinclude -I$(srcdir)/include \ -Wall -W TARGET_LDFLAGS = @TARGET_LDFLAGS@ +TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ +TARGET_IMG_LDFLAGS = @TARGET_IMG_LDFLAGS@ +TARGET_OBJ2ELF = @TARGET_OBJ2ELF@ MODULE_LDFLAGS = @MODULE_LDFLAGS@ +EXEEXT = @EXEEXT@ OBJCOPY = @OBJCOPY@ STRIP = @STRIP@ NM = @NM@ diff --git a/aclocal.m4 b/aclocal.m4 index b7cc0a2..ee6c4db 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -73,7 +73,7 @@ else fi grub_cv_prog_objcopy_absolute=yes for link_addr in 2000 8000 7C00; do - if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} ${LDFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : + if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib ${TARGET_IMG_LDFLAGS_AC} -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : else AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr]) fi @@ -398,3 +398,19 @@ else AC_MSG_RESULT([no]) [fi] ]) + +dnl Check if the C compiler supports `-mstack-arg-probe' (Cygwin). +AC_DEFUN(grub_CHECK_STACK_ARG_PROBE,[ +[# Smashing stack arg probe. +sap_possible=yes] +AC_MSG_CHECKING([whether `$CC' accepts `-mstack-arg-probe']) +AC_LANG_CONFTEST([[void foo (void) { volatile char a[8]; a[3]; }]]) +[if eval "$ac_compile -S -mstack-arg-probe -o conftest.s" 2> /dev/null; then] + AC_MSG_RESULT([yes]) + [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? + rm -f conftest.s +else + sap_possible=no] + AC_MSG_RESULT([no]) +[fi] +]) diff --git a/conf/common.rmk b/conf/common.rmk index b403b04..c0087f5 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -99,6 +99,11 @@ bin_UTILITIES += grub-editenv grub_editenv_SOURCES = util/grub-editenv.c util/envblk.c util/misc.c kern/misc.c kern/err.c CLEANFILES += grub-editenv +# for grub-pe2elf +bin_UTILITIES += grub-pe2elf +grub_pe2elf_SOURCES = util/grub-pe2elf.c util/misc.c +CLEANFILES += grub-pe2elf + # For update-grub update-grub: util/update-grub.in config.status ./config.status --file=$@:$< diff --git a/conf/i386-pc-cygwin-img-ld.sc b/conf/i386-pc-cygwin-img-ld.sc new file mode 100644 index 0000000..a41cac7 --- /dev/null +++ b/conf/i386-pc-cygwin-img-ld.sc @@ -0,0 +1,53 @@ +/* Linker script to create grub .img files on Cygwin. */ + +SECTIONS +{ + .text : + { + start = . ; + *(.text) + etext = . ; + } + .data : + { + __data_start__ = . ; + *(.data) + __data_end__ = . ; + } + .rdata : + { + __rdata_start__ = . ; + *(.rdata) + __rdata_end__ = . ; + } + .pdata : + { + *(.pdata) + edata = . ; + } + .bss : + { + __bss_start__ = . ; + *(.bss) + __common_start__ = . ; + *(COMMON) + __bss_end__ = . ; + } + .edata : + { + *(.edata) + end = . ; + } + .stab : + { + *(.stab) + } + .stabstr : + { + *(.stabstr) + } +} + +ASSERT("__rdata_end__"=="edata", ".pdata not empty") +ASSERT("__bss_end__" =="end" , ".edata not empty") + diff --git a/configure.ac b/configure.ac index 1d8bd08..bac5c9b 100644 --- a/configure.ac +++ b/configure.ac @@ -188,6 +188,30 @@ AC_CHECK_FUNCS(posix_memalign memalign) # Check for target programs. # + +# Use linker script if present, otherwise use builtin -N script. +AC_MSG_CHECKING([for option to link raw image]) +if test -f "${srcdir}/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc"; then + TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc" + TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}" + TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc" +else + TARGET_IMG_LDSCRIPT= + TARGET_IMG_LDFLAGS='-Wl,-N' + TARGET_IMG_LDFLAGS_AC='-Wl,-N' +fi +AC_SUBST(TARGET_IMG_LDSCRIPT) +AC_SUBST(TARGET_IMG_LDFLAGS) +AC_MSG_RESULT([$TARGET_IMG_LDFLAGS_AC]) + +# For platforms where ELF is not the default link format. +AC_MSG_CHECKING([for command to convert module to ELF format]) +if test "$host_os" = cygwin; then + TARGET_OBJ2ELF='grub-pe2elf.exe' +fi +AC_SUBST(TARGET_OBJ2ELF) +AC_MSG_RESULT([$TARGET_OBJ2ELF]) + # For cross-compiling. if test "x$target" != "x$host"; then # XXX this depends on the implementation of autoconf! @@ -278,6 +302,12 @@ grub_CHECK_STACK_PROTECTOR if test "x$ssp_possible" = xyes; then TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" fi +grub_CHECK_STACK_ARG_PROBE +# Cygwin's GCC uses alloca() to probe the stackframe on static +# stack allocations above some threshold. +if test x"$sap_possible" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe" +fi AC_SUBST(TARGET_CFLAGS) AC_SUBST(TARGET_CPPFLAGS) @@ -296,9 +326,14 @@ grub_PROG_OBJCOPY_ABSOLUTE grub_PROG_LD_BUILD_ID_NONE grub_ASM_USCORE if test "x$target_cpu" = xi386; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then + # Check symbols provided by linker script. + CFLAGS="$TARGET_CFLAGS -nostdlib $TARGET_IMG_LDFLAGS_AC -Wl,-Ttext,8000,--defsym,___main=0x8100" + fi grub_CHECK_START_SYMBOL grub_CHECK_BSS_START_SYMBOL grub_CHECK_END_SYMBOL + CFLAGS="$TARGET_CFLAGS" grub_I386_ASM_PREFIX_REQUIREMENT grub_I386_ASM_ADDR32 grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK diff --git a/genkernsyms.sh.in b/genkernsyms.sh.in index a5e1271..0df0bbf 100644 --- a/genkernsyms.sh.in +++ b/genkernsyms.sh.in @@ -16,9 +16,12 @@ : ${srcdir=@srcdir@} : ${CC=@CC@} +u= +grep "^#define HAVE_ASM_USCORE" config.h >/dev/null 2>&1 && u="_" + $CC -DGRUB_SYMBOL_GENERATOR=1 -E -I. -Iinclude -I"$srcdir/include" $* \ | grep -v '^#' \ | sed -n \ - -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}' \ - -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}' \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/'"$u"'\1 kernel/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/'"$u"'\1 kernel/;p;}' \ | sort -u diff --git a/genmk.rb b/genmk.rb index 56dee5c..71e9a4b 100644 --- a/genmk.rb +++ b/genmk.rb @@ -112,10 +112,11 @@ endif MOSTLYCLEANFILES += #{deps_str} UNDSYMFILES += #{undsym} -#{@name}: #{pre_obj} #{mod_obj} +#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) -rm -f $@ - $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ $^ - $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} #{mod_obj} + if [ ! -z $(TARGET_OBJ2ELF) ]; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@ #{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str} -rm -f $@ @@ -194,7 +195,7 @@ class Utility deps = objs.collect {|obj| obj.suffix('d')} deps_str = deps.join(' '); - "CLEANFILES += #{@name} #{objs_str} + "CLEANFILES += #{@name}$(EXEEXT) #{objs_str} MOSTLYCLEANFILES += #{deps_str} #{@name}: $(#{prefix}_DEPENDENCIES) #{objs_str} diff --git a/include/grub/dl.h b/include/grub/dl.h index b630c6f..bdde089 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -41,10 +41,10 @@ static void \ grub_mod_fini (void) #define GRUB_MOD_NAME(name) \ -__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .modname\n.string \"" #name "\"\n") #define GRUB_MOD_DEP(name) \ -__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .moddeps\n.string \"" #name "\"\n") struct grub_dl_segment { diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index c36d859..4b57ade 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -194,6 +194,18 @@ struct grub_pe32_section_table #define GRUB_PE32_SCN_MEM_READ 0x40000000 #define GRUB_PE32_SCN_MEM_WRITE 0x80000000 +#define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 +#define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +#define GRUB_PE32_SCN_ALIGN_4BYTES 0x00300000 +#define GRUB_PE32_SCN_ALIGN_8BYTES 0x00400000 +#define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 +#define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 +#define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 + +#define GRUB_PE32_SCN_ALIGN_SHIFT 20 +#define GRUB_PE32_SCN_ALIGN_MASK 7 + + struct grub_pe32_header { /* This should be filled in with GRUB_PE32_MSDOS_STUB. */ @@ -221,4 +233,35 @@ struct grub_pe32_fixup_block #define GRUB_PE32_REL_BASED_ABSOLUTE 0 #define GRUB_PE32_REL_BASED_HIGHLOW 3 +struct grub_pe32_symbol +{ + union + { + char short_name[8]; + grub_uint32_t long_name[2]; + }; + + grub_uint32_t value; + grub_uint16_t section; + grub_uint16_t type; + grub_uint8_t storage_class; + grub_uint8_t num_aux; +} __attribute__ ((packed)); + +#define GRUB_PE32_SYM_CLASS_EXTERNAL 2 +#define GRUB_PE32_SYM_CLASS_STATIC 3 +#define GRUB_PE32_SYM_CLASS_FILE 0x67 + +#define GRUB_PE32_DT_FUNCTION 0x20 + +struct grub_pe32_reloc +{ + grub_uint32_t offset; + grub_uint32_t symtab_index; + grub_uint16_t type; +} __attribute__ ((packed)); + +#define GRUB_PE32_REL_I386_DIR32 0x6 +#define GRUB_PE32_REL_I386_REL32 0x14 + #endif /* ! GRUB_EFI_PE32_HEADER */ diff --git a/include/grub/symbol.h b/include/grub/symbol.h index aa0ea5a..e951490 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -28,8 +28,14 @@ # define EXT_C(sym) sym #endif +#ifndef __CYGWIN__ #define FUNCTION(x) .globl EXT_C(x) ; .type EXT_C(x), "function" ; EXT_C(x): #define VARIABLE(x) .globl EXT_C(x) ; .type EXT_C(x), "object" ; EXT_C(x): +#else +/* .type not supported for non-ELF targets. XXX: Check this in configure? */ +#define FUNCTION(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 32; .endef; EXT_C(x): +#define VARIABLE(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 0; .endef; EXT_C(x): +#endif /* Mark an exported symbol. */ #ifndef GRUB_SYMBOL_GENERATOR diff --git a/kern/dl.c b/kern/dl.c index c0d9f1d..d606ece 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -454,7 +454,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) const char *name = (char *) e + s->sh_offset; const char *max = name + s->sh_size; - while (name < max) + while ((name < max) && (*name)) { grub_dl_t m; grub_dl_dep_t dep; diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c new file mode 100755 index 0000000..6ea145a --- /dev/null +++ b/util/grub-pe2elf.c @@ -0,0 +1,494 @@ +/* grub-pe2elf.c - tool to convert pe image to elf. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/util/misc.h> +#include <grub/elf.h> +#include <grub/efi/pe32.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n"); + else + printf ("\ +Usage: grub-editenv [OPTIONS] input [output]\n\ +\n\ +Tool to convert pe image to elf.\n\ +\nOptions:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +/* + * Section layout + * + * null + * .text + * .rdata + * .data + * .bss + * .modname + * .moddeps + * .symtab + * .strtab + * relocation sections + */ + +#define TEXT_SECTION 1 +#define RDATA_SECTION 2 +#define DATA_SECTION 3 +#define BSS_SECTION 4 +#define MODNAME_SECTION 5 +#define MODDEPS_SECTION 6 +#define SYMTAB_SECTION 7 +#define STRTAB_SECTION 8 + +#define REL_SECTION 9 +#define MAX_SECTIONS 12 + +#define STRTAB_BLOCK 256 + +static char *strtab; +static int strtab_max, strtab_len; + +Elf32_Ehdr ehdr; +Elf32_Shdr shdr[MAX_SECTIONS]; +int num_sections; +grub_uint32_t offset; + +static int +insert_string (char *name) +{ + int len, result; + + if (*name == '_') + name++; + + len = strlen (name); + if (strtab_len + len >= strtab_max) + { + strtab_max += STRTAB_BLOCK; + strtab = xrealloc (strtab, strtab_max); + } + + strcpy (strtab + strtab_len, name); + result = strtab_len; + strtab_len += len + 1; + + return result; +} + +static int * +write_section_data (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr) +{ + int *section_map; + int i; + + section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int)); + section_map[0] = 0; + + for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) + { + grub_uint32_t idx; + + if (! strcmp (pe_shdr->name, ".text")) + { + idx = TEXT_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + } + else if (! strcmp (pe_shdr->name, ".rdata")) + { + idx = RDATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC; + } + else if (! strcmp (pe_shdr->name, ".data")) + { + idx = DATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".bss")) + { + idx = BSS_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".modname")) + idx = MODNAME_SECTION; + else if (! strcmp (pe_shdr->name, ".moddeps")) + idx = MODDEPS_SECTION; + else + { + section_map[i + 1] = -1; + continue; + } + + section_map[i + 1] = idx; + + shdr[idx].sh_type = (idx == BSS_SECTION) ? SHT_NOBITS : SHT_PROGBITS; + shdr[idx].sh_size = pe_shdr->raw_data_size; + shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + + if (idx != BSS_SECTION) + { + shdr[idx].sh_offset = offset; + grub_util_write_image_at (image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size, offset, fp); + + offset += pe_shdr->raw_data_size; + } + + if (pe_shdr->relocations_offset) + { + char name[5 + strlen (pe_shdr->name)]; + + if (num_sections >= MAX_SECTIONS) + grub_util_error ("Too many sections"); + + sprintf (name, ".rel%s", pe_shdr->name); + + shdr[num_sections].sh_name = insert_string (name); + shdr[num_sections].sh_link = i; + shdr[num_sections].sh_info = idx; + + shdr[idx].sh_name = shdr[num_sections].sh_name + 4; + + num_sections++; + } + else + shdr[idx].sh_name = insert_string (pe_shdr->name); + } + + return section_map; +} + +static void +write_reloc_section (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + Elf32_Sym *symtab, + int *symtab_map) +{ + int i; + + for (i = REL_SECTION; i < num_sections; i++) + { + struct grub_pe32_section_table *pe_sec; + struct grub_pe32_reloc *pe_rel; + Elf32_Rel *rel; + grub_uint32_t size; + int j, modified; + + modified = 0; + + pe_sec = pe_shdr + shdr[i].sh_link; + pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset); + size = pe_sec->num_relocations * sizeof (Elf32_Rel); + rel = (Elf32_Rel *) xmalloc (size); + + for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++) + { + int type; + + if ((pe_rel->symtab_index >= pe_chdr->num_symbols) || + (symtab_map[pe_rel->symtab_index] == -1)) + grub_util_error ("Invalid symbol"); + + if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) + type = R_386_32; + else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) + type = R_386_PC32; + else + grub_util_error ("Unknown pe relocation type %d\n", pe_rel->type); + + pe_rel->offset -= pe_sec->virtual_address; + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx == 0) + { + *(grub_uint32_t *)(image + pe_sec->raw_data_offset + + pe_rel->offset) = (grub_uint32_t) -4; + modified = 1; + } + + rel[j].r_offset = pe_rel->offset; + rel[j].r_info = ELF32_R_INFO (symtab_map[pe_rel->symtab_index], + type); + } + + if (modified) + grub_util_write_image_at (image + pe_sec->raw_data_offset, + shdr[shdr[i].sh_info].sh_size, + shdr[shdr[i].sh_info].sh_offset, + fp); + + shdr[i].sh_type = SHT_REL; + shdr[i].sh_offset = offset; + shdr[i].sh_link = SYMTAB_SECTION; + shdr[i].sh_addralign = 4; + shdr[i].sh_entsize = sizeof (Elf32_Rel); + shdr[i].sh_size = size; + + grub_util_write_image_at (rel, size, offset, fp); + offset += size; + free (rel); + } +} + +static void +write_symbol_table (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + int *section_map) +{ + struct grub_pe32_symbol *pe_symtab; + char *pe_strtab; + Elf32_Sym *symtab; + int *symtab_map, num_syms; + int i; + + pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset); + pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols); + + symtab = (Elf32_Sym *) xmalloc ((pe_chdr->num_symbols + 1) * + sizeof (Elf32_Sym)); + memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf32_Sym)); + num_syms = 1; + + symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int)); + + for (i = 0; i < (int) pe_chdr->num_symbols; + i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1) + { + int bind, type; + + symtab_map[i] = -1; + if ((pe_symtab->section > pe_chdr->num_sections) || + (section_map[pe_symtab->section] == -1)) + continue; + + if (! pe_symtab->section) + type = STT_NOTYPE; + else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION) + type = STT_FUNC; + else + type = STT_OBJECT; + + if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL) + bind = STB_GLOBAL; + else + bind = STB_LOCAL; + + if ((type != STT_FUNC) && (pe_symtab->num_aux)) + { + type = STT_SECTION; + + symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name; + } + else + { + char *name; + + name = ((pe_symtab->long_name[0]) ? pe_symtab->short_name : + pe_strtab + pe_symtab->long_name[1]); + + if ((strcmp (name, "_grub_mod_init")) && + (strcmp (name, "_grub_mod_fini")) && + (bind == STB_LOCAL)) + continue; + + symtab[num_syms].st_name = insert_string (name); + } + + symtab[num_syms].st_shndx = section_map[pe_symtab->section]; + symtab[num_syms].st_value = pe_symtab->value; + symtab[num_syms].st_info = ELF32_ST_INFO (bind, type); + + symtab_map[i] = num_syms; + num_syms++; + } + + write_reloc_section (fp, image, pe_chdr, pe_shdr, symtab, symtab_map); + + shdr[SYMTAB_SECTION].sh_name = insert_string (".symtab"); + shdr[SYMTAB_SECTION].sh_type = SHT_SYMTAB; + shdr[SYMTAB_SECTION].sh_offset = offset; + shdr[SYMTAB_SECTION].sh_size = num_syms * sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_entsize = sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_link = STRTAB_SECTION; + shdr[SYMTAB_SECTION].sh_addralign = 4; + + grub_util_write_image_at (symtab, shdr[SYMTAB_SECTION].sh_size, + offset, fp); + offset += shdr[SYMTAB_SECTION].sh_size; + + free (symtab); + free (symtab_map); +} + +static void +write_string_table (FILE* fp) +{ + shdr[STRTAB_SECTION].sh_name = insert_string (".strtab"); + shdr[STRTAB_SECTION].sh_type = SHT_STRTAB; + shdr[STRTAB_SECTION].sh_offset = offset; + shdr[STRTAB_SECTION].sh_size = strtab_len; + shdr[STRTAB_SECTION].sh_addralign = 1; + grub_util_write_image_at (strtab, strtab_len, offset, fp); + offset += strtab_len; + + free (strtab); +} + +static void +write_section_header (FILE* fp) +{ + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_version = EV_CURRENT; + ehdr.e_type = ET_REL; + + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_386; + + ehdr.e_ehsize = sizeof (ehdr); + ehdr.e_shentsize = sizeof (Elf32_Shdr); + ehdr.e_shstrndx = STRTAB_SECTION; + + ehdr.e_shoff = offset; + ehdr.e_shnum = num_sections; + grub_util_write_image_at (&shdr, sizeof (Elf32_Shdr) * num_sections, + offset, fp); + + grub_util_write_image_at (&ehdr, sizeof (Elf32_Ehdr), 0, fp); +} + +static void +convert_pe (FILE* fp, char *image) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + int *section_map; + + pe_chdr = (struct grub_pe32_coff_header *) image; + if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386) + grub_util_error ("Invalid coff image"); + + strtab = xmalloc (STRTAB_BLOCK); + strtab_max = STRTAB_BLOCK; + strtab[0] = 0; + strtab_len = 1; + + offset = sizeof (ehdr); + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + num_sections = REL_SECTION; + + section_map = write_section_data (fp, image, pe_chdr, pe_shdr); + + write_symbol_table (fp, image, pe_chdr, pe_shdr, section_map); + free (section_map); + + write_string_table (fp); + + write_section_header (fp); +} + +int +main (int argc, char *argv[]) +{ + char *image; + FILE* fp; + + progname = "grub-pe2elf"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain PATH. */ + if (optind >= argc) + { + fprintf (stderr, "Filename not specified.\n"); + usage (1); + } + + image = grub_util_read_image (argv[optind]); + + if (optind + 1 < argc) + optind++; + + fp = fopen (argv[optind], "wb"); + if (! fp) + grub_util_error ("cannot open %s", argv[optind]); + + convert_pe (fp, image); + + fclose (fp); + + return 0; +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-23 5:54 ` Bean @ 2008-07-23 20:28 ` Bean 2008-07-23 21:13 ` Christian Franke 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-07-23 20:28 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 3235 bytes --] On Wed, Jul 23, 2008 at 1:54 PM, Bean <bean123ch@gmail.com> wrote: > Hi, > > I change the structure of grub-pe2elf, now it uses sub function to do > various task instead of one huge trunk. > > I also include the build script by Christian Franke, as it's needed to > compile successfully in cygwin. I make some adjustment: > > 1, use grub-pe2elf to generate module file instead of objdump > 2, remove the "_" patch for gensymlist.sh.in, it's not needed anymore > as grub-pe2elf have removed the underscope, but the genkernsyms.sh.in > patch is still needed. > > With this patch, grub2 works OOTB in cygwin. > > Changelog: > > 2008-07-23 Bean <bean123ch@gmail.com> > > * common.rmk (bin_UTILITIES): Add grub-pe2elf. > (grub_pe2elf_SOURCES): New macro. > (CLEANFILES): Add grub-pe2elf. > > * include/grub/efi/pe32.h (GRUB_PE32_SCN_ALIGN_1BYTES): New constant. > (GRUB_PE32_SCN_ALIGN_2BYTES): Likewise. > (GRUB_PE32_SCN_ALIGN_4BYTES): Likewise. > (GRUB_PE32_SCN_ALIGN_8BYTES): Likewise. > (GRUB_PE32_SCN_ALIGN_16BYTES): Likewise. > (GRUB_PE32_SCN_ALIGN_32BYTES): Likewise. > (GRUB_PE32_SCN_ALIGN_64BYTES): Likewise. > (GRUB_PE32_SCN_ALIGN_SHIFT): Likewise. > (GRUB_PE32_SCN_ALIGN_MASK): Likewise. > (GRUB_PE32_SYM_CLASS_EXTERNAL): Likewise. > (GRUB_PE32_SYM_CLASS_STATIC): Likewise. > (GRUB_PE32_SYM_CLASS_FILE): Likewise. > (GRUB_PE32_DT_FUNCTION): Likewise. > (GRUB_PE32_REL_I386_DIR32): Likewise. > (GRUB_PE32_REL_I386_REL32): Likewise. > (grub_pe32_symbol): New structure. > (grub_pe32_reloc): Likewise. > > * util/grub-pe2elf.c: New file. > > * configure.ac: Set TARGET_OBJ2ELF if host os is cygwin. > > * genmk.rb: Use TARGET_OBJ2ELF to convert native object format to elf. > > The following patches are from Christian Franke. > > * include/grub/dl.h: Remove .previous, gas supports this only > for ELF format. > > * include/grub/symbol.h [__CYGWIN__] (#define FUNCTION/VARIABLE): > Remove .type, gas supports this only for ELF format. > > * kern/dl.c (grub_dl_resolve_dependencies): Add check for trailing nullbytes > in symbol table. This fixes an infinite loop if table is zero filled. > > * Makefile.in: Add autoconf replacements TARGET_IMG_LDSCRIPT, > TARGET_IMG_LDFLAGS and EXEEXT. > > * aclocal.m4 (grub_PROG_OBJCOPY_ABSOLUTE): Replace -Wl,-N by > TARGET_IMG_LDFLAGS_AC. > (grub_CHECK_STACK_ARG_PROBE): New function. > > * conf/i386-pc.rmk: Replace -Wl,-N by TARGET_IMG_LDFLAGS. > > * conf/i386-pc-cygwin-ld-img.sc: New linker script. > > * configure.ac: Add check for linker script "conf/${target}-img-ld.c" > to set TARGET_IMG_LD* accordingly. > Add check for Cygwin to set TARGET_MOD_OBJCOPY accordingly. > Add call to grub_CHECK_STACK_ARG_PROBE. > Use TARGET_IMG_LDFLAGS to check start, bss_start, end symbols. > > * genkernsyms.sh.in: Handle HAVE_ASM_USCORE case. > > * genmk.rb: Add EXEEXT to CLEANFILES. Hi, I have fixed a few bugs in grub-pe2elf in this new patch,it should work as expected now. -- Bean [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: pe2elf_3.diff --] [-- Type: text/x-diff; name=pe2elf_3.diff, Size: 27295 bytes --] diff --git a/Makefile.in b/Makefile.in index 6f9474c..ccb5497 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,7 +68,11 @@ TARGET_CFLAGS = @TARGET_CFLAGS@ TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -I. -Iinclude -I$(srcdir)/include \ -Wall -W TARGET_LDFLAGS = @TARGET_LDFLAGS@ +TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ +TARGET_IMG_LDFLAGS = @TARGET_IMG_LDFLAGS@ +TARGET_OBJ2ELF = @TARGET_OBJ2ELF@ MODULE_LDFLAGS = @MODULE_LDFLAGS@ +EXEEXT = @EXEEXT@ OBJCOPY = @OBJCOPY@ STRIP = @STRIP@ NM = @NM@ diff --git a/aclocal.m4 b/aclocal.m4 index b7cc0a2..ee6c4db 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -73,7 +73,7 @@ else fi grub_cv_prog_objcopy_absolute=yes for link_addr in 2000 8000 7C00; do - if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} ${LDFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : + if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib ${TARGET_IMG_LDFLAGS_AC} -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : else AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr]) fi @@ -398,3 +398,19 @@ else AC_MSG_RESULT([no]) [fi] ]) + +dnl Check if the C compiler supports `-mstack-arg-probe' (Cygwin). +AC_DEFUN(grub_CHECK_STACK_ARG_PROBE,[ +[# Smashing stack arg probe. +sap_possible=yes] +AC_MSG_CHECKING([whether `$CC' accepts `-mstack-arg-probe']) +AC_LANG_CONFTEST([[void foo (void) { volatile char a[8]; a[3]; }]]) +[if eval "$ac_compile -S -mstack-arg-probe -o conftest.s" 2> /dev/null; then] + AC_MSG_RESULT([yes]) + [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? + rm -f conftest.s +else + sap_possible=no] + AC_MSG_RESULT([no]) +[fi] +]) diff --git a/conf/common.rmk b/conf/common.rmk index b403b04..c0087f5 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -99,6 +99,11 @@ bin_UTILITIES += grub-editenv grub_editenv_SOURCES = util/grub-editenv.c util/envblk.c util/misc.c kern/misc.c kern/err.c CLEANFILES += grub-editenv +# for grub-pe2elf +bin_UTILITIES += grub-pe2elf +grub_pe2elf_SOURCES = util/grub-pe2elf.c util/misc.c +CLEANFILES += grub-pe2elf + # For update-grub update-grub: util/update-grub.in config.status ./config.status --file=$@:$< diff --git a/conf/i386-pc-cygwin-img-ld.sc b/conf/i386-pc-cygwin-img-ld.sc new file mode 100644 index 0000000..a41cac7 --- /dev/null +++ b/conf/i386-pc-cygwin-img-ld.sc @@ -0,0 +1,53 @@ +/* Linker script to create grub .img files on Cygwin. */ + +SECTIONS +{ + .text : + { + start = . ; + *(.text) + etext = . ; + } + .data : + { + __data_start__ = . ; + *(.data) + __data_end__ = . ; + } + .rdata : + { + __rdata_start__ = . ; + *(.rdata) + __rdata_end__ = . ; + } + .pdata : + { + *(.pdata) + edata = . ; + } + .bss : + { + __bss_start__ = . ; + *(.bss) + __common_start__ = . ; + *(COMMON) + __bss_end__ = . ; + } + .edata : + { + *(.edata) + end = . ; + } + .stab : + { + *(.stab) + } + .stabstr : + { + *(.stabstr) + } +} + +ASSERT("__rdata_end__"=="edata", ".pdata not empty") +ASSERT("__bss_end__" =="end" , ".edata not empty") + diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index b677a96..84c0b7d 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -16,27 +16,27 @@ pkglib_IMAGES = boot.img diskboot.img kernel.img pxeboot.img lnxboot.img \ # For boot.img. boot_img_SOURCES = boot/i386/pc/boot.S boot_img_ASFLAGS = $(COMMON_ASFLAGS) -boot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00 +boot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 # For pxeboot.img pxeboot_img_SOURCES = boot/i386/pc/pxeboot.S pxeboot_img_ASFLAGS = $(COMMON_ASFLAGS) -pxeboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00 +pxeboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 # For diskboot.img. diskboot_img_SOURCES = boot/i386/pc/diskboot.S diskboot_img_ASFLAGS = $(COMMON_ASFLAGS) -diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,8000 +diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,8000 # For lnxboot.img. lnxboot_img_SOURCES = boot/i386/pc/lnxboot.S lnxboot_img_ASFLAGS = $(COMMON_ASFLAGS) -lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,6000 +lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,6000 # For cdboot.img. cdboot_img_SOURCES = boot/i386/pc/cdboot.S cdboot_img_ASFLAGS = $(COMMON_ASFLAGS) -cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00 +cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 # For kernel.img. kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \ @@ -53,7 +53,7 @@ kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h machine/kernel.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) +kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) MOSTLYCLEANFILES += symlist.c kernel_syms.lst DEFSYMFILES += kernel_syms.lst diff --git a/configure.ac b/configure.ac index 1d8bd08..bac5c9b 100644 --- a/configure.ac +++ b/configure.ac @@ -188,6 +188,30 @@ AC_CHECK_FUNCS(posix_memalign memalign) # Check for target programs. # + +# Use linker script if present, otherwise use builtin -N script. +AC_MSG_CHECKING([for option to link raw image]) +if test -f "${srcdir}/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc"; then + TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc" + TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}" + TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc" +else + TARGET_IMG_LDSCRIPT= + TARGET_IMG_LDFLAGS='-Wl,-N' + TARGET_IMG_LDFLAGS_AC='-Wl,-N' +fi +AC_SUBST(TARGET_IMG_LDSCRIPT) +AC_SUBST(TARGET_IMG_LDFLAGS) +AC_MSG_RESULT([$TARGET_IMG_LDFLAGS_AC]) + +# For platforms where ELF is not the default link format. +AC_MSG_CHECKING([for command to convert module to ELF format]) +if test "$host_os" = cygwin; then + TARGET_OBJ2ELF='grub-pe2elf.exe' +fi +AC_SUBST(TARGET_OBJ2ELF) +AC_MSG_RESULT([$TARGET_OBJ2ELF]) + # For cross-compiling. if test "x$target" != "x$host"; then # XXX this depends on the implementation of autoconf! @@ -278,6 +302,12 @@ grub_CHECK_STACK_PROTECTOR if test "x$ssp_possible" = xyes; then TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" fi +grub_CHECK_STACK_ARG_PROBE +# Cygwin's GCC uses alloca() to probe the stackframe on static +# stack allocations above some threshold. +if test x"$sap_possible" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe" +fi AC_SUBST(TARGET_CFLAGS) AC_SUBST(TARGET_CPPFLAGS) @@ -296,9 +326,14 @@ grub_PROG_OBJCOPY_ABSOLUTE grub_PROG_LD_BUILD_ID_NONE grub_ASM_USCORE if test "x$target_cpu" = xi386; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then + # Check symbols provided by linker script. + CFLAGS="$TARGET_CFLAGS -nostdlib $TARGET_IMG_LDFLAGS_AC -Wl,-Ttext,8000,--defsym,___main=0x8100" + fi grub_CHECK_START_SYMBOL grub_CHECK_BSS_START_SYMBOL grub_CHECK_END_SYMBOL + CFLAGS="$TARGET_CFLAGS" grub_I386_ASM_PREFIX_REQUIREMENT grub_I386_ASM_ADDR32 grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK diff --git a/genkernsyms.sh.in b/genkernsyms.sh.in index a5e1271..0df0bbf 100644 --- a/genkernsyms.sh.in +++ b/genkernsyms.sh.in @@ -16,9 +16,12 @@ : ${srcdir=@srcdir@} : ${CC=@CC@} +u= +grep "^#define HAVE_ASM_USCORE" config.h >/dev/null 2>&1 && u="_" + $CC -DGRUB_SYMBOL_GENERATOR=1 -E -I. -Iinclude -I"$srcdir/include" $* \ | grep -v '^#' \ | sed -n \ - -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}' \ - -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}' \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/'"$u"'\1 kernel/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/'"$u"'\1 kernel/;p;}' \ | sort -u diff --git a/genmk.rb b/genmk.rb index 56dee5c..71e9a4b 100644 --- a/genmk.rb +++ b/genmk.rb @@ -112,10 +112,11 @@ endif MOSTLYCLEANFILES += #{deps_str} UNDSYMFILES += #{undsym} -#{@name}: #{pre_obj} #{mod_obj} +#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) -rm -f $@ - $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ $^ - $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} #{mod_obj} + if [ ! -z $(TARGET_OBJ2ELF) ]; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@ #{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str} -rm -f $@ @@ -194,7 +195,7 @@ class Utility deps = objs.collect {|obj| obj.suffix('d')} deps_str = deps.join(' '); - "CLEANFILES += #{@name} #{objs_str} + "CLEANFILES += #{@name}$(EXEEXT) #{objs_str} MOSTLYCLEANFILES += #{deps_str} #{@name}: $(#{prefix}_DEPENDENCIES) #{objs_str} diff --git a/include/grub/dl.h b/include/grub/dl.h index b630c6f..bdde089 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -41,10 +41,10 @@ static void \ grub_mod_fini (void) #define GRUB_MOD_NAME(name) \ -__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .modname\n.string \"" #name "\"\n") #define GRUB_MOD_DEP(name) \ -__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .moddeps\n.string \"" #name "\"\n") struct grub_dl_segment { diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index c36d859..4b57ade 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -194,6 +194,18 @@ struct grub_pe32_section_table #define GRUB_PE32_SCN_MEM_READ 0x40000000 #define GRUB_PE32_SCN_MEM_WRITE 0x80000000 +#define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 +#define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +#define GRUB_PE32_SCN_ALIGN_4BYTES 0x00300000 +#define GRUB_PE32_SCN_ALIGN_8BYTES 0x00400000 +#define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 +#define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 +#define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 + +#define GRUB_PE32_SCN_ALIGN_SHIFT 20 +#define GRUB_PE32_SCN_ALIGN_MASK 7 + + struct grub_pe32_header { /* This should be filled in with GRUB_PE32_MSDOS_STUB. */ @@ -221,4 +233,35 @@ struct grub_pe32_fixup_block #define GRUB_PE32_REL_BASED_ABSOLUTE 0 #define GRUB_PE32_REL_BASED_HIGHLOW 3 +struct grub_pe32_symbol +{ + union + { + char short_name[8]; + grub_uint32_t long_name[2]; + }; + + grub_uint32_t value; + grub_uint16_t section; + grub_uint16_t type; + grub_uint8_t storage_class; + grub_uint8_t num_aux; +} __attribute__ ((packed)); + +#define GRUB_PE32_SYM_CLASS_EXTERNAL 2 +#define GRUB_PE32_SYM_CLASS_STATIC 3 +#define GRUB_PE32_SYM_CLASS_FILE 0x67 + +#define GRUB_PE32_DT_FUNCTION 0x20 + +struct grub_pe32_reloc +{ + grub_uint32_t offset; + grub_uint32_t symtab_index; + grub_uint16_t type; +} __attribute__ ((packed)); + +#define GRUB_PE32_REL_I386_DIR32 0x6 +#define GRUB_PE32_REL_I386_REL32 0x14 + #endif /* ! GRUB_EFI_PE32_HEADER */ diff --git a/include/grub/symbol.h b/include/grub/symbol.h index aa0ea5a..e951490 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -28,8 +28,14 @@ # define EXT_C(sym) sym #endif +#ifndef __CYGWIN__ #define FUNCTION(x) .globl EXT_C(x) ; .type EXT_C(x), "function" ; EXT_C(x): #define VARIABLE(x) .globl EXT_C(x) ; .type EXT_C(x), "object" ; EXT_C(x): +#else +/* .type not supported for non-ELF targets. XXX: Check this in configure? */ +#define FUNCTION(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 32; .endef; EXT_C(x): +#define VARIABLE(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 0; .endef; EXT_C(x): +#endif /* Mark an exported symbol. */ #ifndef GRUB_SYMBOL_GENERATOR diff --git a/kern/dl.c b/kern/dl.c index c0d9f1d..d606ece 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -454,7 +454,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) const char *name = (char *) e + s->sh_offset; const char *max = name + s->sh_size; - while (name < max) + while ((name < max) && (*name)) { grub_dl_t m; grub_dl_dep_t dep; diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c new file mode 100755 index 0000000..5df48a5 --- /dev/null +++ b/util/grub-pe2elf.c @@ -0,0 +1,520 @@ +/* grub-pe2elf.c - tool to convert pe image to elf. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/util/misc.h> +#include <grub/elf.h> +#include <grub/efi/pe32.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n"); + else + printf ("\ +Usage: grub-editenv [OPTIONS] input [output]\n\ +\n\ +Tool to convert pe image to elf.\n\ +\nOptions:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +/* + * Section layout + * + * null + * .text + * .rdata + * .data + * .bss + * .modname + * .moddeps + * .symtab + * .strtab + * relocation sections + */ + +#define TEXT_SECTION 1 +#define RDATA_SECTION 2 +#define DATA_SECTION 3 +#define BSS_SECTION 4 +#define MODNAME_SECTION 5 +#define MODDEPS_SECTION 6 +#define SYMTAB_SECTION 7 +#define STRTAB_SECTION 8 + +#define REL_SECTION 9 +#define MAX_SECTIONS 12 + +#define STRTAB_BLOCK 256 + +static char *strtab; +static int strtab_max, strtab_len; + +Elf32_Ehdr ehdr; +Elf32_Shdr shdr[MAX_SECTIONS]; +int num_sections; +grub_uint32_t offset; + +static int +insert_string (char *name) +{ + int len, result; + + if (*name == '_') + name++; + + len = strlen (name); + if (strtab_len + len >= strtab_max) + { + strtab_max += STRTAB_BLOCK; + strtab = xrealloc (strtab, strtab_max); + } + + strcpy (strtab + strtab_len, name); + result = strtab_len; + strtab_len += len + 1; + + return result; +} + +static int * +write_section_data (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr) +{ + int *section_map; + int i; + + section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int)); + section_map[0] = 0; + + for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) + { + grub_uint32_t idx; + + if (! strcmp (pe_shdr->name, ".text")) + { + idx = TEXT_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + } + else if (! strcmp (pe_shdr->name, ".rdata")) + { + idx = RDATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC; + } + else if (! strcmp (pe_shdr->name, ".data")) + { + idx = DATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".bss")) + { + idx = BSS_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".modname")) + idx = MODNAME_SECTION; + else if (! strcmp (pe_shdr->name, ".moddeps")) + idx = MODDEPS_SECTION; + else + { + section_map[i + 1] = -1; + continue; + } + + section_map[i + 1] = idx; + + shdr[idx].sh_type = (idx == BSS_SECTION) ? SHT_NOBITS : SHT_PROGBITS; + shdr[idx].sh_size = pe_shdr->raw_data_size; + shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + + if (idx != BSS_SECTION) + { + shdr[idx].sh_offset = offset; + grub_util_write_image_at (image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size, offset, fp); + + offset += pe_shdr->raw_data_size; + } + + if (pe_shdr->relocations_offset) + { + char name[5 + strlen (pe_shdr->name)]; + + if (num_sections >= MAX_SECTIONS) + grub_util_error ("Too many sections"); + + sprintf (name, ".rel%s", pe_shdr->name); + + shdr[num_sections].sh_name = insert_string (name); + shdr[num_sections].sh_link = i; + shdr[num_sections].sh_info = idx; + + shdr[idx].sh_name = shdr[num_sections].sh_name + 4; + + num_sections++; + } + else + shdr[idx].sh_name = insert_string (pe_shdr->name); + } + + return section_map; +} + +static void +write_reloc_section (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + Elf32_Sym *symtab, + int *symtab_map) +{ + int i; + + for (i = REL_SECTION; i < num_sections; i++) + { + struct grub_pe32_section_table *pe_sec; + struct grub_pe32_reloc *pe_rel; + Elf32_Rel *rel; + int num_rels, j, modified; + + pe_sec = pe_shdr + shdr[i].sh_link; + pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset); + rel = (Elf32_Rel *) xmalloc (pe_sec->num_relocations * sizeof (Elf32_Rel)); + num_rels = 0; + modified = 0; + + for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++) + { + int type; + grub_uint32_t ofs, *addr; + + if ((pe_rel->symtab_index >= pe_chdr->num_symbols) || + (symtab_map[pe_rel->symtab_index] == -1)) + grub_util_error ("Invalid symbol"); + + if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) + type = R_386_32; + else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) + type = R_386_PC32; + else + grub_util_error ("Unknown pe relocation type %d\n", pe_rel->type); + + ofs = pe_rel->offset - pe_sec->virtual_address; + addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs); + if (type == R_386_PC32) + { + unsigned char code; + + code = image[pe_sec->raw_data_offset + ofs - 1]; + + if (((code != 0xe8) && (code != 0xe9)) || (*addr)) + grub_util_error ("Invalid relocation (%x %x)", code, *addr); + + modified = 1; + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx) + { + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx + != shdr[i].sh_info) + grub_util_error ("Cross section call is not allowed"); + + *addr = (symtab[symtab_map[pe_rel->symtab_index]].st_value + - ofs - 4); + + continue; + } + else + *addr = -4; + } + else + if ((ELF32_ST_TYPE (symtab[symtab_map[pe_rel->symtab_index]].st_info) == STT_SECTION) && + (symtab[symtab_map[pe_rel->symtab_index]].st_value)) + { + *addr += symtab[symtab_map[pe_rel->symtab_index]].st_value; + modified = 1; + } + + rel[num_rels].r_offset = ofs; + rel[num_rels].r_info = ELF32_R_INFO (symtab_map[pe_rel->symtab_index], + type); + num_rels++; + } + + if (modified) + grub_util_write_image_at (image + pe_sec->raw_data_offset, + shdr[shdr[i].sh_info].sh_size, + shdr[shdr[i].sh_info].sh_offset, + fp); + + shdr[i].sh_type = SHT_REL; + shdr[i].sh_offset = offset; + shdr[i].sh_link = SYMTAB_SECTION; + shdr[i].sh_addralign = 4; + shdr[i].sh_entsize = sizeof (Elf32_Rel); + shdr[i].sh_size = num_rels * sizeof (Elf32_Rel); + + grub_util_write_image_at (rel, shdr[i].sh_size, offset, fp); + offset += shdr[i].sh_size; + free (rel); + } +} + +static void +write_symbol_table (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + int *section_map) +{ + struct grub_pe32_symbol *pe_symtab; + char *pe_strtab; + Elf32_Sym *symtab; + int *symtab_map, num_syms; + int i; + + pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset); + pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols); + + symtab = (Elf32_Sym *) xmalloc ((pe_chdr->num_symbols + 1) * + sizeof (Elf32_Sym)); + memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf32_Sym)); + num_syms = 1; + + symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int)); + + for (i = 0; i < (int) pe_chdr->num_symbols; + i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1) + { + int bind, type; + + symtab_map[i] = -1; + if ((pe_symtab->section > pe_chdr->num_sections) || + (section_map[pe_symtab->section] == -1)) + continue; + + if (! pe_symtab->section) + type = STT_NOTYPE; + else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION) + type = STT_FUNC; + else + type = STT_OBJECT; + + if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL) + bind = STB_GLOBAL; + else + bind = STB_LOCAL; + + if ((type != STT_FUNC) && (pe_symtab->num_aux)) + { + type = STT_SECTION; + + symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name; + } + else + { + char *name; + + name = ((pe_symtab->long_name[0]) ? pe_symtab->short_name : + pe_strtab + pe_symtab->long_name[1]); + + if ((strcmp (name, "_grub_mod_init")) && + (strcmp (name, "_grub_mod_fini")) && + (bind == STB_LOCAL)) + continue; + + symtab[num_syms].st_name = insert_string (name); + } + + symtab[num_syms].st_shndx = section_map[pe_symtab->section]; + symtab[num_syms].st_value = pe_symtab->value; + symtab[num_syms].st_info = ELF32_ST_INFO (bind, type); + + symtab_map[i] = num_syms; + num_syms++; + } + + write_reloc_section (fp, image, pe_chdr, pe_shdr, symtab, symtab_map); + + shdr[SYMTAB_SECTION].sh_name = insert_string (".symtab"); + shdr[SYMTAB_SECTION].sh_type = SHT_SYMTAB; + shdr[SYMTAB_SECTION].sh_offset = offset; + shdr[SYMTAB_SECTION].sh_size = num_syms * sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_entsize = sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_link = STRTAB_SECTION; + shdr[SYMTAB_SECTION].sh_addralign = 4; + + grub_util_write_image_at (symtab, shdr[SYMTAB_SECTION].sh_size, + offset, fp); + offset += shdr[SYMTAB_SECTION].sh_size; + + free (symtab); + free (symtab_map); +} + +static void +write_string_table (FILE* fp) +{ + shdr[STRTAB_SECTION].sh_name = insert_string (".strtab"); + shdr[STRTAB_SECTION].sh_type = SHT_STRTAB; + shdr[STRTAB_SECTION].sh_offset = offset; + shdr[STRTAB_SECTION].sh_size = strtab_len; + shdr[STRTAB_SECTION].sh_addralign = 1; + grub_util_write_image_at (strtab, strtab_len, offset, fp); + offset += strtab_len; + + free (strtab); +} + +static void +write_section_header (FILE* fp) +{ + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_version = EV_CURRENT; + ehdr.e_type = ET_REL; + + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_386; + + ehdr.e_ehsize = sizeof (ehdr); + ehdr.e_shentsize = sizeof (Elf32_Shdr); + ehdr.e_shstrndx = STRTAB_SECTION; + + ehdr.e_shoff = offset; + ehdr.e_shnum = num_sections; + grub_util_write_image_at (&shdr, sizeof (Elf32_Shdr) * num_sections, + offset, fp); + + grub_util_write_image_at (&ehdr, sizeof (Elf32_Ehdr), 0, fp); +} + +static void +convert_pe (FILE* fp, char *image) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + int *section_map; + + pe_chdr = (struct grub_pe32_coff_header *) image; + if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386) + grub_util_error ("Invalid coff image"); + + strtab = xmalloc (STRTAB_BLOCK); + strtab_max = STRTAB_BLOCK; + strtab[0] = 0; + strtab_len = 1; + + offset = sizeof (ehdr); + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + num_sections = REL_SECTION; + + section_map = write_section_data (fp, image, pe_chdr, pe_shdr); + + write_symbol_table (fp, image, pe_chdr, pe_shdr, section_map); + free (section_map); + + write_string_table (fp); + + write_section_header (fp); +} + +int +main (int argc, char *argv[]) +{ + char *image; + FILE* fp; + + progname = "grub-pe2elf"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain PATH. */ + if (optind >= argc) + { + fprintf (stderr, "Filename not specified.\n"); + usage (1); + } + + image = grub_util_read_image (argv[optind]); + + if (optind + 1 < argc) + optind++; + + fp = fopen (argv[optind], "wb"); + if (! fp) + grub_util_error ("cannot open %s", argv[optind]); + + convert_pe (fp, image); + + fclose (fp); + + return 0; +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-23 20:28 ` Bean @ 2008-07-23 21:13 ` Christian Franke 2008-07-23 22:24 ` Christian Franke 0 siblings, 1 reply; 9+ messages in thread From: Christian Franke @ 2008-07-23 21:13 UTC (permalink / raw) To: The development of GRUB 2 Bean wrote: > On Wed, Jul 23, 2008 at 1:54 PM, Bean <bean123ch@gmail.com> wrote: > > ... > Hi, > > I have fixed a few bugs in grub-pe2elf in this new patch,it should > work as expected now. > > Yes, 3rd patch looks good. Thanks for the converter! Christian ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-23 21:13 ` Christian Franke @ 2008-07-23 22:24 ` Christian Franke 2008-07-24 3:39 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Christian Franke @ 2008-07-23 22:24 UTC (permalink / raw) To: The development of GRUB 2 Christian Franke wrote: > Bean wrote: >> On Wed, Jul 23, 2008 at 1:54 PM, Bean <bean123ch@gmail.com> wrote: >> ... >> Hi, >> >> I have fixed a few bugs in grub-pe2elf in this new patch,it should >> work as expected now. >> >> > > Yes, 3rd patch looks good. Thanks for the converter! > Another real world test (grub-install on an USB flash drive and boot) works. Patch is IMO good to go. Then only the fix for update-grub-lib:make_system_path_relative_to_its_root() remains for OOTB Cygwin support. Christian ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-23 22:24 ` Christian Franke @ 2008-07-24 3:39 ` Bean 2008-07-24 5:32 ` Christian Franke 0 siblings, 1 reply; 9+ messages in thread From: Bean @ 2008-07-24 3:39 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 824 bytes --] On Thu, Jul 24, 2008 at 6:24 AM, Christian Franke <Christian.Franke@t-online.de> wrote: > Christian Franke wrote: >> >> Bean wrote: >>> >>> On Wed, Jul 23, 2008 at 1:54 PM, Bean <bean123ch@gmail.com> wrote: >>> ... >>> Hi, >>> >>> I have fixed a few bugs in grub-pe2elf in this new patch,it should >>> work as expected now. >>> >>> >> >> Yes, 3rd patch looks good. Thanks for the converter! >> > > Another real world test (grub-install on an USB flash drive and boot) works. > > Patch is IMO good to go. > > > Then only the fix for > update-grub-lib:make_system_path_relative_to_its_root() remains for OOTB > Cygwin support. Hi, Oh nice. Here is a new patch with small adjustment to grub-pe2elf, which makes handling a little simpler. Please check if it breaks anything. If no one objects, I'd commit it soon. -- Bean [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: pe2elf_4.diff --] [-- Type: text/x-diff; name=pe2elf_4.diff, Size: 27001 bytes --] diff --git a/Makefile.in b/Makefile.in index 6f9474c..ccb5497 100644 --- a/Makefile.in +++ b/Makefile.in @@ -68,7 +68,11 @@ TARGET_CFLAGS = @TARGET_CFLAGS@ TARGET_CPPFLAGS = @TARGET_CPPFLAGS@ -I. -Iinclude -I$(srcdir)/include \ -Wall -W TARGET_LDFLAGS = @TARGET_LDFLAGS@ +TARGET_IMG_LDSCRIPT = @TARGET_IMG_LDSCRIPT@ +TARGET_IMG_LDFLAGS = @TARGET_IMG_LDFLAGS@ +TARGET_OBJ2ELF = @TARGET_OBJ2ELF@ MODULE_LDFLAGS = @MODULE_LDFLAGS@ +EXEEXT = @EXEEXT@ OBJCOPY = @OBJCOPY@ STRIP = @STRIP@ NM = @NM@ diff --git a/aclocal.m4 b/aclocal.m4 index b7cc0a2..ee6c4db 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -73,7 +73,7 @@ else fi grub_cv_prog_objcopy_absolute=yes for link_addr in 2000 8000 7C00; do - if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} ${LDFLAGS} -nostdlib -Wl,-N -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : + if AC_TRY_COMMAND([${CC-cc} ${CFLAGS} -nostdlib ${TARGET_IMG_LDFLAGS_AC} -Wl,-Ttext -Wl,$link_addr conftest.o -o conftest.exec]); then : else AC_MSG_ERROR([${CC-cc} cannot link at address $link_addr]) fi @@ -398,3 +398,19 @@ else AC_MSG_RESULT([no]) [fi] ]) + +dnl Check if the C compiler supports `-mstack-arg-probe' (Cygwin). +AC_DEFUN(grub_CHECK_STACK_ARG_PROBE,[ +[# Smashing stack arg probe. +sap_possible=yes] +AC_MSG_CHECKING([whether `$CC' accepts `-mstack-arg-probe']) +AC_LANG_CONFTEST([[void foo (void) { volatile char a[8]; a[3]; }]]) +[if eval "$ac_compile -S -mstack-arg-probe -o conftest.s" 2> /dev/null; then] + AC_MSG_RESULT([yes]) + [# Should we clear up other files as well, having called `AC_LANG_CONFTEST'? + rm -f conftest.s +else + sap_possible=no] + AC_MSG_RESULT([no]) +[fi] +]) diff --git a/conf/common.rmk b/conf/common.rmk index b403b04..c0087f5 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -99,6 +99,11 @@ bin_UTILITIES += grub-editenv grub_editenv_SOURCES = util/grub-editenv.c util/envblk.c util/misc.c kern/misc.c kern/err.c CLEANFILES += grub-editenv +# for grub-pe2elf +bin_UTILITIES += grub-pe2elf +grub_pe2elf_SOURCES = util/grub-pe2elf.c util/misc.c +CLEANFILES += grub-pe2elf + # For update-grub update-grub: util/update-grub.in config.status ./config.status --file=$@:$< diff --git a/conf/i386-pc-cygwin-img-ld.sc b/conf/i386-pc-cygwin-img-ld.sc new file mode 100644 index 0000000..a41cac7 --- /dev/null +++ b/conf/i386-pc-cygwin-img-ld.sc @@ -0,0 +1,53 @@ +/* Linker script to create grub .img files on Cygwin. */ + +SECTIONS +{ + .text : + { + start = . ; + *(.text) + etext = . ; + } + .data : + { + __data_start__ = . ; + *(.data) + __data_end__ = . ; + } + .rdata : + { + __rdata_start__ = . ; + *(.rdata) + __rdata_end__ = . ; + } + .pdata : + { + *(.pdata) + edata = . ; + } + .bss : + { + __bss_start__ = . ; + *(.bss) + __common_start__ = . ; + *(COMMON) + __bss_end__ = . ; + } + .edata : + { + *(.edata) + end = . ; + } + .stab : + { + *(.stab) + } + .stabstr : + { + *(.stabstr) + } +} + +ASSERT("__rdata_end__"=="edata", ".pdata not empty") +ASSERT("__bss_end__" =="end" , ".edata not empty") + diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index b677a96..84c0b7d 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -16,27 +16,27 @@ pkglib_IMAGES = boot.img diskboot.img kernel.img pxeboot.img lnxboot.img \ # For boot.img. boot_img_SOURCES = boot/i386/pc/boot.S boot_img_ASFLAGS = $(COMMON_ASFLAGS) -boot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00 +boot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 # For pxeboot.img pxeboot_img_SOURCES = boot/i386/pc/pxeboot.S pxeboot_img_ASFLAGS = $(COMMON_ASFLAGS) -pxeboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00 +pxeboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 # For diskboot.img. diskboot_img_SOURCES = boot/i386/pc/diskboot.S diskboot_img_ASFLAGS = $(COMMON_ASFLAGS) -diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,8000 +diskboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,8000 # For lnxboot.img. lnxboot_img_SOURCES = boot/i386/pc/lnxboot.S lnxboot_img_ASFLAGS = $(COMMON_ASFLAGS) -lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,6000 +lnxboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,6000 # For cdboot.img. cdboot_img_SOURCES = boot/i386/pc/cdboot.S cdboot_img_ASFLAGS = $(COMMON_ASFLAGS) -cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,7C00 +cdboot_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,7C00 # For kernel.img. kernel_img_SOURCES = kern/i386/pc/startup.S kern/main.c kern/device.c \ @@ -53,7 +53,7 @@ kernel_img_HEADERS = arg.h boot.h cache.h device.h disk.h dl.h elf.h elfload.h \ machine/memory.h machine/loader.h machine/vga.h machine/vbe.h machine/kernel.h kernel_img_CFLAGS = $(COMMON_CFLAGS) kernel_img_ASFLAGS = $(COMMON_ASFLAGS) -kernel_img_LDFLAGS = $(COMMON_LDFLAGS) -Wl,-N,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) +kernel_img_LDFLAGS = $(COMMON_LDFLAGS) $(TARGET_IMG_LDFLAGS) -Wl,-Ttext,$(GRUB_MEMORY_MACHINE_LINK_ADDR) $(COMMON_CFLAGS) MOSTLYCLEANFILES += symlist.c kernel_syms.lst DEFSYMFILES += kernel_syms.lst diff --git a/configure.ac b/configure.ac index 1d8bd08..bac5c9b 100644 --- a/configure.ac +++ b/configure.ac @@ -188,6 +188,30 @@ AC_CHECK_FUNCS(posix_memalign memalign) # Check for target programs. # + +# Use linker script if present, otherwise use builtin -N script. +AC_MSG_CHECKING([for option to link raw image]) +if test -f "${srcdir}/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc"; then + TARGET_IMG_LDSCRIPT='$(top_srcdir)'"/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc" + TARGET_IMG_LDFLAGS="-Wl,-T${TARGET_IMG_LDSCRIPT}" + TARGET_IMG_LDFLAGS_AC="-Wl,-T${srcdir}/conf/${target_cpu}-${platform}-${target_os}-img-ld.sc" +else + TARGET_IMG_LDSCRIPT= + TARGET_IMG_LDFLAGS='-Wl,-N' + TARGET_IMG_LDFLAGS_AC='-Wl,-N' +fi +AC_SUBST(TARGET_IMG_LDSCRIPT) +AC_SUBST(TARGET_IMG_LDFLAGS) +AC_MSG_RESULT([$TARGET_IMG_LDFLAGS_AC]) + +# For platforms where ELF is not the default link format. +AC_MSG_CHECKING([for command to convert module to ELF format]) +if test "$host_os" = cygwin; then + TARGET_OBJ2ELF='grub-pe2elf.exe' +fi +AC_SUBST(TARGET_OBJ2ELF) +AC_MSG_RESULT([$TARGET_OBJ2ELF]) + # For cross-compiling. if test "x$target" != "x$host"; then # XXX this depends on the implementation of autoconf! @@ -278,6 +302,12 @@ grub_CHECK_STACK_PROTECTOR if test "x$ssp_possible" = xyes; then TARGET_CFLAGS="$TARGET_CFLAGS -fno-stack-protector" fi +grub_CHECK_STACK_ARG_PROBE +# Cygwin's GCC uses alloca() to probe the stackframe on static +# stack allocations above some threshold. +if test x"$sap_possible" = xyes; then + TARGET_CFLAGS="$TARGET_CFLAGS -mno-stack-arg-probe" +fi AC_SUBST(TARGET_CFLAGS) AC_SUBST(TARGET_CPPFLAGS) @@ -296,9 +326,14 @@ grub_PROG_OBJCOPY_ABSOLUTE grub_PROG_LD_BUILD_ID_NONE grub_ASM_USCORE if test "x$target_cpu" = xi386; then + if test ! -z "$TARGET_IMG_LDSCRIPT"; then + # Check symbols provided by linker script. + CFLAGS="$TARGET_CFLAGS -nostdlib $TARGET_IMG_LDFLAGS_AC -Wl,-Ttext,8000,--defsym,___main=0x8100" + fi grub_CHECK_START_SYMBOL grub_CHECK_BSS_START_SYMBOL grub_CHECK_END_SYMBOL + CFLAGS="$TARGET_CFLAGS" grub_I386_ASM_PREFIX_REQUIREMENT grub_I386_ASM_ADDR32 grub_I386_ASM_ABSOLUTE_WITHOUT_ASTERISK diff --git a/genkernsyms.sh.in b/genkernsyms.sh.in index a5e1271..0df0bbf 100644 --- a/genkernsyms.sh.in +++ b/genkernsyms.sh.in @@ -16,9 +16,12 @@ : ${srcdir=@srcdir@} : ${CC=@CC@} +u= +grep "^#define HAVE_ASM_USCORE" config.h >/dev/null 2>&1 && u="_" + $CC -DGRUB_SYMBOL_GENERATOR=1 -E -I. -Iinclude -I"$srcdir/include" $* \ | grep -v '^#' \ | sed -n \ - -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}' \ - -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/\1 kernel/;p;}' \ + -e '/EXPORT_FUNC *([a-zA-Z0-9_]*)/{s/.*EXPORT_FUNC *(\([a-zA-Z0-9_]*\)).*/'"$u"'\1 kernel/;p;}' \ + -e '/EXPORT_VAR *([a-zA-Z0-9_]*)/{s/.*EXPORT_VAR *(\([a-zA-Z0-9_]*\)).*/'"$u"'\1 kernel/;p;}' \ | sort -u diff --git a/genmk.rb b/genmk.rb index 56dee5c..71e9a4b 100644 --- a/genmk.rb +++ b/genmk.rb @@ -112,10 +112,11 @@ endif MOSTLYCLEANFILES += #{deps_str} UNDSYMFILES += #{undsym} -#{@name}: #{pre_obj} #{mod_obj} +#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) -rm -f $@ - $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ $^ - $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -R .note -R .comment $@ + $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) $(MODULE_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} #{mod_obj} + if [ ! -z $(TARGET_OBJ2ELF) ]; then ./$(TARGET_OBJ2ELF) $@ || (rm -f $@; exit 1); fi + $(STRIP) --strip-unneeded -K grub_mod_init -K grub_mod_fini -K _grub_mod_init -K _grub_mod_fini -R .note -R .comment $@ #{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str} -rm -f $@ @@ -194,7 +195,7 @@ class Utility deps = objs.collect {|obj| obj.suffix('d')} deps_str = deps.join(' '); - "CLEANFILES += #{@name} #{objs_str} + "CLEANFILES += #{@name}$(EXEEXT) #{objs_str} MOSTLYCLEANFILES += #{deps_str} #{@name}: $(#{prefix}_DEPENDENCIES) #{objs_str} diff --git a/include/grub/dl.h b/include/grub/dl.h index b630c6f..bdde089 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -41,10 +41,10 @@ static void \ grub_mod_fini (void) #define GRUB_MOD_NAME(name) \ -__asm__ (".section .modname,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .modname\n.string \"" #name "\"\n") #define GRUB_MOD_DEP(name) \ -__asm__ (".section .moddeps,\"S\"\n.string \"" #name "\"\n.previous") +__asm__ (".section .moddeps\n.string \"" #name "\"\n") struct grub_dl_segment { diff --git a/include/grub/efi/pe32.h b/include/grub/efi/pe32.h index c36d859..4b57ade 100644 --- a/include/grub/efi/pe32.h +++ b/include/grub/efi/pe32.h @@ -194,6 +194,18 @@ struct grub_pe32_section_table #define GRUB_PE32_SCN_MEM_READ 0x40000000 #define GRUB_PE32_SCN_MEM_WRITE 0x80000000 +#define GRUB_PE32_SCN_ALIGN_1BYTES 0x00100000 +#define GRUB_PE32_SCN_ALIGN_2BYTES 0x00200000 +#define GRUB_PE32_SCN_ALIGN_4BYTES 0x00300000 +#define GRUB_PE32_SCN_ALIGN_8BYTES 0x00400000 +#define GRUB_PE32_SCN_ALIGN_16BYTES 0x00500000 +#define GRUB_PE32_SCN_ALIGN_32BYTES 0x00600000 +#define GRUB_PE32_SCN_ALIGN_64BYTES 0x00700000 + +#define GRUB_PE32_SCN_ALIGN_SHIFT 20 +#define GRUB_PE32_SCN_ALIGN_MASK 7 + + struct grub_pe32_header { /* This should be filled in with GRUB_PE32_MSDOS_STUB. */ @@ -221,4 +233,35 @@ struct grub_pe32_fixup_block #define GRUB_PE32_REL_BASED_ABSOLUTE 0 #define GRUB_PE32_REL_BASED_HIGHLOW 3 +struct grub_pe32_symbol +{ + union + { + char short_name[8]; + grub_uint32_t long_name[2]; + }; + + grub_uint32_t value; + grub_uint16_t section; + grub_uint16_t type; + grub_uint8_t storage_class; + grub_uint8_t num_aux; +} __attribute__ ((packed)); + +#define GRUB_PE32_SYM_CLASS_EXTERNAL 2 +#define GRUB_PE32_SYM_CLASS_STATIC 3 +#define GRUB_PE32_SYM_CLASS_FILE 0x67 + +#define GRUB_PE32_DT_FUNCTION 0x20 + +struct grub_pe32_reloc +{ + grub_uint32_t offset; + grub_uint32_t symtab_index; + grub_uint16_t type; +} __attribute__ ((packed)); + +#define GRUB_PE32_REL_I386_DIR32 0x6 +#define GRUB_PE32_REL_I386_REL32 0x14 + #endif /* ! GRUB_EFI_PE32_HEADER */ diff --git a/include/grub/symbol.h b/include/grub/symbol.h index aa0ea5a..e951490 100644 --- a/include/grub/symbol.h +++ b/include/grub/symbol.h @@ -28,8 +28,14 @@ # define EXT_C(sym) sym #endif +#ifndef __CYGWIN__ #define FUNCTION(x) .globl EXT_C(x) ; .type EXT_C(x), "function" ; EXT_C(x): #define VARIABLE(x) .globl EXT_C(x) ; .type EXT_C(x), "object" ; EXT_C(x): +#else +/* .type not supported for non-ELF targets. XXX: Check this in configure? */ +#define FUNCTION(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 32; .endef; EXT_C(x): +#define VARIABLE(x) .globl EXT_C(x) ; .def EXT_C(x); .scl 2; .type 0; .endef; EXT_C(x): +#endif /* Mark an exported symbol. */ #ifndef GRUB_SYMBOL_GENERATOR diff --git a/kern/dl.c b/kern/dl.c index c0d9f1d..d606ece 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -454,7 +454,7 @@ grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) const char *name = (char *) e + s->sh_offset; const char *max = name + s->sh_size; - while (name < max) + while ((name < max) && (*name)) { grub_dl_t m; grub_dl_dep_t dep; diff --git a/util/grub-pe2elf.c b/util/grub-pe2elf.c new file mode 100755 index 0000000..d703d33 --- /dev/null +++ b/util/grub-pe2elf.c @@ -0,0 +1,514 @@ +/* grub-pe2elf.c - tool to convert pe image to elf. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2008 Free Software Foundation, Inc. + * + * GRUB is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * GRUB is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with GRUB. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> +#include <grub/types.h> +#include <grub/util/misc.h> +#include <grub/elf.h> +#include <grub/efi/pe32.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-editenv --help'' for more information.\n"); + else + printf ("\ +Usage: grub-editenv [OPTIONS] input [output]\n\ +\n\ +Tool to convert pe image to elf.\n\ +\nOptions:\n\ + -h, --help display this message and exit\n\ + -V, --version print version information and exit\n\ + -v, --verbose print verbose messages\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +/* + * Section layout + * + * null + * .text + * .rdata + * .data + * .bss + * .modname + * .moddeps + * .symtab + * .strtab + * relocation sections + */ + +#define TEXT_SECTION 1 +#define RDATA_SECTION 2 +#define DATA_SECTION 3 +#define BSS_SECTION 4 +#define MODNAME_SECTION 5 +#define MODDEPS_SECTION 6 +#define SYMTAB_SECTION 7 +#define STRTAB_SECTION 8 + +#define REL_SECTION 9 +#define MAX_SECTIONS 12 + +#define STRTAB_BLOCK 256 + +static char *strtab; +static int strtab_max, strtab_len; + +Elf32_Ehdr ehdr; +Elf32_Shdr shdr[MAX_SECTIONS]; +int num_sections; +grub_uint32_t offset; + +static int +insert_string (char *name) +{ + int len, result; + + if (*name == '_') + name++; + + len = strlen (name); + if (strtab_len + len >= strtab_max) + { + strtab_max += STRTAB_BLOCK; + strtab = xrealloc (strtab, strtab_max); + } + + strcpy (strtab + strtab_len, name); + result = strtab_len; + strtab_len += len + 1; + + return result; +} + +static int * +write_section_data (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr) +{ + int *section_map; + int i; + + section_map = xmalloc ((pe_chdr->num_sections + 1) * sizeof (int)); + section_map[0] = 0; + + for (i = 0; i < pe_chdr->num_sections; i++, pe_shdr++) + { + grub_uint32_t idx; + + if (! strcmp (pe_shdr->name, ".text")) + { + idx = TEXT_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_EXECINSTR; + } + else if (! strcmp (pe_shdr->name, ".rdata")) + { + idx = RDATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC; + } + else if (! strcmp (pe_shdr->name, ".data")) + { + idx = DATA_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".bss")) + { + idx = BSS_SECTION; + shdr[idx].sh_flags = SHF_ALLOC | SHF_WRITE; + } + else if (! strcmp (pe_shdr->name, ".modname")) + idx = MODNAME_SECTION; + else if (! strcmp (pe_shdr->name, ".moddeps")) + idx = MODDEPS_SECTION; + else + { + section_map[i + 1] = -1; + continue; + } + + section_map[i + 1] = idx; + + shdr[idx].sh_type = (idx == BSS_SECTION) ? SHT_NOBITS : SHT_PROGBITS; + shdr[idx].sh_size = pe_shdr->raw_data_size; + shdr[idx].sh_addralign = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + + if (idx != BSS_SECTION) + { + shdr[idx].sh_offset = offset; + grub_util_write_image_at (image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size, offset, fp); + + offset += pe_shdr->raw_data_size; + } + + if (pe_shdr->relocations_offset) + { + char name[5 + strlen (pe_shdr->name)]; + + if (num_sections >= MAX_SECTIONS) + grub_util_error ("Too many sections"); + + sprintf (name, ".rel%s", pe_shdr->name); + + shdr[num_sections].sh_name = insert_string (name); + shdr[num_sections].sh_link = i; + shdr[num_sections].sh_info = idx; + + shdr[idx].sh_name = shdr[num_sections].sh_name + 4; + + num_sections++; + } + else + shdr[idx].sh_name = insert_string (pe_shdr->name); + } + + return section_map; +} + +static void +write_reloc_section (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + Elf32_Sym *symtab, + int *symtab_map) +{ + int i; + + for (i = REL_SECTION; i < num_sections; i++) + { + struct grub_pe32_section_table *pe_sec; + struct grub_pe32_reloc *pe_rel; + Elf32_Rel *rel; + int num_rels, j, modified; + + pe_sec = pe_shdr + shdr[i].sh_link; + pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset); + rel = (Elf32_Rel *) xmalloc (pe_sec->num_relocations * sizeof (Elf32_Rel)); + num_rels = 0; + modified = 0; + + for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++) + { + int type; + grub_uint32_t ofs, *addr; + + if ((pe_rel->symtab_index >= pe_chdr->num_symbols) || + (symtab_map[pe_rel->symtab_index] == -1)) + grub_util_error ("Invalid symbol"); + + if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) + type = R_386_32; + else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) + type = R_386_PC32; + else + grub_util_error ("Unknown pe relocation type %d\n", pe_rel->type); + + ofs = pe_rel->offset - pe_sec->virtual_address; + addr = (grub_uint32_t *)(image + pe_sec->raw_data_offset + ofs); + if (type == R_386_PC32) + { + unsigned char code; + + code = image[pe_sec->raw_data_offset + ofs - 1]; + + if (((code != 0xe8) && (code != 0xe9)) || (*addr)) + grub_util_error ("Invalid relocation (%x %x)", code, *addr); + + modified = 1; + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx) + { + if (symtab[symtab_map[pe_rel->symtab_index]].st_shndx + != shdr[i].sh_info) + grub_util_error ("Cross section call is not allowed"); + + *addr = (symtab[symtab_map[pe_rel->symtab_index]].st_value + - ofs - 4); + + continue; + } + else + *addr = -4; + } + + rel[num_rels].r_offset = ofs; + rel[num_rels].r_info = ELF32_R_INFO (symtab_map[pe_rel->symtab_index], + type); + num_rels++; + } + + if (modified) + grub_util_write_image_at (image + pe_sec->raw_data_offset, + shdr[shdr[i].sh_info].sh_size, + shdr[shdr[i].sh_info].sh_offset, + fp); + + shdr[i].sh_type = SHT_REL; + shdr[i].sh_offset = offset; + shdr[i].sh_link = SYMTAB_SECTION; + shdr[i].sh_addralign = 4; + shdr[i].sh_entsize = sizeof (Elf32_Rel); + shdr[i].sh_size = num_rels * sizeof (Elf32_Rel); + + grub_util_write_image_at (rel, shdr[i].sh_size, offset, fp); + offset += shdr[i].sh_size; + free (rel); + } +} + +static void +write_symbol_table (FILE* fp, char *image, + struct grub_pe32_coff_header *pe_chdr, + struct grub_pe32_section_table *pe_shdr, + int *section_map) +{ + struct grub_pe32_symbol *pe_symtab; + char *pe_strtab; + Elf32_Sym *symtab; + int *symtab_map, num_syms; + int i; + + pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset); + pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols); + + symtab = (Elf32_Sym *) xmalloc ((pe_chdr->num_symbols + 1) * + sizeof (Elf32_Sym)); + memset (symtab, 0, (pe_chdr->num_symbols + 1) * sizeof (Elf32_Sym)); + num_syms = 1; + + symtab_map = (int *) xmalloc (pe_chdr->num_symbols * sizeof (int)); + + for (i = 0; i < (int) pe_chdr->num_symbols; + i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1) + { + int bind, type; + + symtab_map[i] = -1; + if ((pe_symtab->section > pe_chdr->num_sections) || + (section_map[pe_symtab->section] == -1)) + continue; + + if (! pe_symtab->section) + type = STT_NOTYPE; + else if (pe_symtab->type == GRUB_PE32_DT_FUNCTION) + type = STT_FUNC; + else + type = STT_OBJECT; + + if (pe_symtab->storage_class == GRUB_PE32_SYM_CLASS_EXTERNAL) + bind = STB_GLOBAL; + else + bind = STB_LOCAL; + + if ((type != STT_FUNC) && (pe_symtab->num_aux)) + { + if (! pe_symtab->value) + type = STT_SECTION; + + symtab[num_syms].st_name = shdr[section_map[pe_symtab->section]].sh_name; + } + else + { + char *name; + + name = ((pe_symtab->long_name[0]) ? pe_symtab->short_name : + pe_strtab + pe_symtab->long_name[1]); + + if ((strcmp (name, "_grub_mod_init")) && + (strcmp (name, "_grub_mod_fini")) && + (bind == STB_LOCAL)) + continue; + + symtab[num_syms].st_name = insert_string (name); + } + + symtab[num_syms].st_shndx = section_map[pe_symtab->section]; + symtab[num_syms].st_value = pe_symtab->value; + symtab[num_syms].st_info = ELF32_ST_INFO (bind, type); + + symtab_map[i] = num_syms; + num_syms++; + } + + write_reloc_section (fp, image, pe_chdr, pe_shdr, symtab, symtab_map); + + shdr[SYMTAB_SECTION].sh_name = insert_string (".symtab"); + shdr[SYMTAB_SECTION].sh_type = SHT_SYMTAB; + shdr[SYMTAB_SECTION].sh_offset = offset; + shdr[SYMTAB_SECTION].sh_size = num_syms * sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_entsize = sizeof (Elf32_Sym); + shdr[SYMTAB_SECTION].sh_link = STRTAB_SECTION; + shdr[SYMTAB_SECTION].sh_addralign = 4; + + grub_util_write_image_at (symtab, shdr[SYMTAB_SECTION].sh_size, + offset, fp); + offset += shdr[SYMTAB_SECTION].sh_size; + + free (symtab); + free (symtab_map); +} + +static void +write_string_table (FILE* fp) +{ + shdr[STRTAB_SECTION].sh_name = insert_string (".strtab"); + shdr[STRTAB_SECTION].sh_type = SHT_STRTAB; + shdr[STRTAB_SECTION].sh_offset = offset; + shdr[STRTAB_SECTION].sh_size = strtab_len; + shdr[STRTAB_SECTION].sh_addralign = 1; + grub_util_write_image_at (strtab, strtab_len, offset, fp); + offset += strtab_len; + + free (strtab); +} + +static void +write_section_header (FILE* fp) +{ + ehdr.e_ident[EI_MAG0] = ELFMAG0; + ehdr.e_ident[EI_MAG1] = ELFMAG1; + ehdr.e_ident[EI_MAG2] = ELFMAG2; + ehdr.e_ident[EI_MAG3] = ELFMAG3; + ehdr.e_ident[EI_VERSION] = EV_CURRENT; + ehdr.e_version = EV_CURRENT; + ehdr.e_type = ET_REL; + + ehdr.e_ident[EI_CLASS] = ELFCLASS32; + ehdr.e_ident[EI_DATA] = ELFDATA2LSB; + ehdr.e_machine = EM_386; + + ehdr.e_ehsize = sizeof (ehdr); + ehdr.e_shentsize = sizeof (Elf32_Shdr); + ehdr.e_shstrndx = STRTAB_SECTION; + + ehdr.e_shoff = offset; + ehdr.e_shnum = num_sections; + grub_util_write_image_at (&shdr, sizeof (Elf32_Shdr) * num_sections, + offset, fp); + + grub_util_write_image_at (&ehdr, sizeof (Elf32_Ehdr), 0, fp); +} + +static void +convert_pe (FILE* fp, char *image) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + int *section_map; + + pe_chdr = (struct grub_pe32_coff_header *) image; + if (grub_le_to_cpu16 (pe_chdr->machine) != GRUB_PE32_MACHINE_I386) + grub_util_error ("Invalid coff image"); + + strtab = xmalloc (STRTAB_BLOCK); + strtab_max = STRTAB_BLOCK; + strtab[0] = 0; + strtab_len = 1; + + offset = sizeof (ehdr); + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + num_sections = REL_SECTION; + + section_map = write_section_data (fp, image, pe_chdr, pe_shdr); + + write_symbol_table (fp, image, pe_chdr, pe_shdr, section_map); + free (section_map); + + write_string_table (fp); + + write_section_header (fp); +} + +int +main (int argc, char *argv[]) +{ + char *image; + FILE* fp; + + progname = "grub-pe2elf"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'h': + usage (0); + break; + + case 'V': + printf ("%s (%s) %s\n", progname, PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + /* Obtain PATH. */ + if (optind >= argc) + { + fprintf (stderr, "Filename not specified.\n"); + usage (1); + } + + image = grub_util_read_image (argv[optind]); + + if (optind + 1 < argc) + optind++; + + fp = fopen (argv[optind], "wb"); + if (! fp) + grub_util_error ("cannot open %s", argv[optind]); + + convert_pe (fp, image); + + fclose (fp); + + return 0; +} ^ permalink raw reply related [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-24 3:39 ` Bean @ 2008-07-24 5:32 ` Christian Franke 2008-07-24 14:56 ` Bean 0 siblings, 1 reply; 9+ messages in thread From: Christian Franke @ 2008-07-24 5:32 UTC (permalink / raw) To: The development of GRUB 2 Bean wrote: >> ... >> Another real world test (grub-install on an USB flash drive and boot) works. >> >> Patch is IMO good to go. >> >> >> Then only the fix for >> update-grub-lib:make_system_path_relative_to_its_root() remains for OOTB >> Cygwin support. >> > > Hi, > > Oh nice. Here is a new patch with small adjustment to grub-pe2elf, > which makes handling a little simpler. Please check if it breaks > anything. > > Looks good. Christian ^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH] New tool to convert pe image to elf 2008-07-24 5:32 ` Christian Franke @ 2008-07-24 14:56 ` Bean 0 siblings, 0 replies; 9+ messages in thread From: Bean @ 2008-07-24 14:56 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Jul 24, 2008 at 1:32 PM, Christian Franke <Christian.Franke@t-online.de> wrote: > Bean wrote: >>> >>> ... >>> Another real world test (grub-install on an USB flash drive and boot) >>> works. >>> >>> Patch is IMO good to go. >>> >>> >>> Then only the fix for >>> update-grub-lib:make_system_path_relative_to_its_root() remains for OOTB >>> Cygwin support. >>> >> >> Hi, >> >> Oh nice. Here is a new patch with small adjustment to grub-pe2elf, >> which makes handling a little simpler. Please check if it breaks >> anything. Hi, Committed. -- Bean ^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2008-07-24 14:56 UTC | newest] Thread overview: 9+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2008-07-22 21:56 [PATCH] New tool to convert pe image to elf Bean 2008-07-22 22:05 ` Christian Franke 2008-07-23 5:54 ` Bean 2008-07-23 20:28 ` Bean 2008-07-23 21:13 ` Christian Franke 2008-07-23 22:24 ` Christian Franke 2008-07-24 3:39 ` Bean 2008-07-24 5:32 ` Christian Franke 2008-07-24 14:56 ` Bean
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.