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
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;
+}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to