All of lore.kernel.org
 help / color / mirror / Atom feed
* [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.