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  <[EMAIL PROTECTED]>

        * 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
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 @@
 : [EMAIL PROTECTED]@}
 : [EMAIL PROTECTED]@}
 
+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}
 
[EMAIL PROTECTED]: #{pre_obj} #{mod_obj}
[EMAIL PROTECTED]: #{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 += [EMAIL PROTECTED] #{objs_str}
+    "CLEANFILES += [EMAIL PROTECTED](EXEEXT) #{objs_str}
 MOSTLYCLEANFILES += #{deps_str}
 
 [EMAIL PROTECTED]: $(#{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;
+}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel

Reply via email to