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 @@
: address@hidden@}
: address@hidden@}
+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}
address@hidden: #{pre_obj} #{mod_obj}
address@hidden: #{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 += address@hidden #{objs_str}
+ "CLEANFILES += address@hidden(EXEEXT) #{objs_str}
MOSTLYCLEANFILES += #{deps_str}
address@hidden: $(#{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 .
+ */
+
+#include
+#include
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+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;
+}