This adds Cygwin support to kernel sources. It handles the issues
introduced by PE->ELF conversion and adds support for HAVE_ASM_USCORE.
Christian
2007-07-20 Christian Franke <[EMAIL PROTECTED]>
* 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_symbols): Add check for grub_mod_init
and grub_mod_fini for symbols without a type. Handle HAVE_ASM_USCORE
case for these symbols.
(grub_dl_resolve_dependencies): Add check for trailing nullbytes
in symbol table. This fixes an infinite loop if table is zero filled.
* kern/i386/dl.c [__CYGWIN__] (fix_pc_rel_relocation): New function
to fix bad PC relative relocation produced by objcopy.
[__CYGWIN__] (grub_arch_dl_relocate_symbols): Add fix of PC relative
relocation.
(grub_arch_dl_relocate_symbols): Abort on unknown relocation type.
diff --git a/include/grub/dl.h b/include/grub/dl.h
index b630c6f..3029f95 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -40,11 +40,12 @@ grub_##name##_fini (void) { grub_mod_fini (); } \
static void \
grub_mod_fini (void)
+/* Note: .previous not supported for non-ELF targets. */
#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/symbol.h b/include/grub/symbol.h
index aa0ea5a..72209d1 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) ; EXT_C(x):
+#define VARIABLE(x) .globl EXT_C(x) ; EXT_C(x):
+#endif
/* Mark an exported symbol. */
#ifndef GRUB_SYMBOL_GENERATOR
diff --git a/kern/dl.c b/kern/dl.c
index c0d9f1d..7950c0d 100644
--- a/kern/dl.c
+++ b/kern/dl.c
@@ -53,6 +53,12 @@ typedef Elf64_Sym Elf_Sym;
#endif
+#ifdef HAVE_ASM_USCORE
+# define SYM_USCORE "_"
+#else
+# define SYM_USCORE ""
+#endif
+
struct grub_dl_list
@@ -347,17 +353,31 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
unsigned char type = ELF_ST_TYPE (sym->st_info);
unsigned char bind = ELF_ST_BIND (sym->st_info);
const char *name = str + sym->st_name;
-
+ int check_mod_func = 0;
+
switch (type)
{
case STT_NOTYPE:
- /* Resolve a global symbol. */
- if (sym->st_name != 0 && sym->st_shndx == 0)
+ if (sym->st_name != 0)
{
- sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
- if (! sym->st_value)
- return grub_error (GRUB_ERR_BAD_MODULE,
- "the symbol `%s' not found", name);
+ if (sym->st_shndx == 0)
+ {
+ /* Resolve a global symbol. */
+ sym->st_value = (Elf_Addr) grub_dl_resolve_symbol (name);
+ if (! sym->st_value)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "the symbol `%s' not found", name);
+ }
+ else
+ { /* Static functions and global variables have no type
+ if initial format was not ELF. */
+ sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
+ sym->st_shndx);
+ if (bind == STB_LOCAL)
+ check_mod_func = 1;
+ else if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
+ return grub_errno;
+ }
}
else
sym->st_value = 0;
@@ -374,14 +394,10 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
case STT_FUNC:
sym->st_value += (Elf_Addr) grub_dl_get_section_addr (mod,
sym->st_shndx);
- if (bind != STB_LOCAL)
- if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
- return grub_errno;
-
- if (grub_strcmp (name, "grub_mod_init") == 0)
- mod->init = (void (*) (grub_dl_t)) sym->st_value;
- else if (grub_strcmp (name, "grub_mod_fini") == 0)
- mod->fini = (void (*) (void)) sym->st_value;
+ if (bind == STB_LOCAL)
+ check_mod_func = 1;
+ else if (grub_dl_register_symbol (name, (void *) sym->st_value, mod))
+ return grub_errno;
break;
case STT_SECTION:
@@ -397,6 +413,13 @@ grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
return grub_error (GRUB_ERR_BAD_MODULE,
"unknown symbol type `%d'", (int) type);
}
+ if (check_mod_func)
+ {
+ if (grub_strcmp (name, SYM_USCORE "grub_mod_init") == 0)
+ mod->init = (void (*) (grub_dl_t)) sym->st_value;
+ else if (grub_strcmp (name, SYM_USCORE "grub_mod_fini") == 0)
+ mod->fini = (void (*) (void)) sym->st_value;
+ }
}
return GRUB_ERR_NONE;
@@ -454,7 +477,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) /* Segment may contain trailing 0. */
{
grub_dl_t m;
grub_dl_dep_t dep;
diff --git a/kern/i386/dl.c b/kern/i386/dl.c
index e9e43e5..94d1510 100644
--- a/kern/i386/dl.c
+++ b/kern/i386/dl.c
@@ -37,6 +37,28 @@ grub_arch_dl_check_header (void *ehdr)
return GRUB_ERR_NONE;
}
+#ifdef __CYGWIN__
+/* Fix PC relative relocation. Objcopy does not adjust
+the addent when converting from pe-i386 to elf32-i386. */
+static int
+fix_pc_rel_relocation (Elf32_Word *addr)
+{
+ /* To be safe, check instruction first. */
+ const unsigned char * pc = (const unsigned char *)addr - 1;
+ if (!(*pc == 0xe8/*call*/ || *pc == 0xe9/*jmp*/))
+ return grub_error (GRUB_ERR_BAD_MODULE, "unknown pc-relative instruction %02x", *pc);
+ /* Check and adjust offset. */
+ if (*addr != (Elf32_Word)-4)
+ {
+ if (*addr != 0)
+ return grub_error (GRUB_ERR_BAD_MODULE, "invalid pc-relative relocation base %lx",
+ (long)(*addr));
+ *addr = (Elf32_Word)-4;
+ }
+ return GRUB_ERR_NONE;
+}
+#endif
+
/* Relocate symbols. */
grub_err_t
grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
@@ -99,9 +121,17 @@ grub_arch_dl_relocate_symbols (grub_dl_t mod, void *ehdr)
break;
case R_386_PC32:
+#ifdef __CYGWIN__
+ if (fix_pc_rel_relocation (addr))
+ return grub_errno;
+#endif
*addr += (sym->st_value - (Elf32_Word) seg->addr
- rel->r_offset);
break;
+
+ default:
+ return grub_error (GRUB_ERR_BAD_MODULE, "unknown relocation type %x.",
+ ELF32_R_TYPE (rel->r_info));
}
}
}
_______________________________________________
Grub-devel mailing list
Grub-devel@gnu.org
http://lists.gnu.org/mailman/listinfo/grub-devel