* [PATCH] New object format
@ 2009-07-14 15:49 Bean
2009-07-14 17:57 ` please stop this Robert Millan
` (2 more replies)
0 siblings, 3 replies; 25+ messages in thread
From: Bean @ 2009-07-14 15:49 UTC (permalink / raw)
To: The development of GRUB 2
[-- Attachment #1: Type: text/plain, Size: 974 bytes --]
Hi,
This patch implement a new object format, the advantages are:
Reduce size dramatically, some result:
Size of all modules:
original: 645575
new: 519093
Dynamic loader:
original
text data bss dec hex filename
412 0 0 412 19c kernel_img-kern___target_cpu__dl.o
3052 0 2064 5116 13fc kernel_img-kern_dl.o
new:
text data bss dec hex filename
2272 0 2064 4336 10f0 kernel_img-kern_dl.o
Greatly simplify the build process:
1, compile *.c, *.S to *.o
2, use grub-mkmod to merge *.o file to mod
3, use grub-symdb to maintain module dependence
so there is no pre-* mod-* def-* und-* anymore.
grub-mkmod support both pe and elf format, no need to convert with grub-pe2elf.
BTW, this patch breaks other platform. And it seems there is some bug
in elf->mod converter. But the pe->mod works quite nice, I can load
graphic menu and even run osdetect script with lua.
--
Bean
[-- Attachment #2: obj.diff --]
[-- Type: text/x-patch, Size: 87812 bytes --]
diff --git a/Makefile.in b/Makefile.in
index 3d208e7..d984872 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -147,11 +147,9 @@ include $(srcdir)/conf/$(target_cpu)-$(platform).mk
### General targets.
CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA)
-pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst
-moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk
- cat $(DEFSYMFILES) /dev/null \
- | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \
- || (rm -f $@; exit 1)
+pkglib_DATA += modsym.lst command.lst fs.lst partmap.lst parttool.lst handler.lst
+modsym.lst: $(MODFILES) grub-symdb
+ ./grub-symdb -d . update $?
command.lst: $(COMMANDFILES)
cat $^ /dev/null | sort > $@
diff --git a/conf/common.rmk b/conf/common.rmk
index 07ff04e..ddb368e 100644
--- a/conf/common.rmk
+++ b/conf/common.rmk
@@ -125,6 +125,23 @@ endif
grub_pe2elf_SOURCES = util/grub-pe2elf.c util/misc.c
CLEANFILES += grub-pe2elf
+# grub-mkmod
+bin_UTILITIES += grub-mkmod
+grub_mkmod_SOURCES = util/grub-mkmod.c util/misc.c util/obj.c \
+ util/obj_pe.c util/obj_elf.c kern/list.c
+CLEANFILES += grub-mkmod
+
+# grub-symdb
+bin_UTILITIES += grub-symdb
+grub_symdb_SOURCES = util/grub-symdb.c util/obj.c util/misc.c kern/list.c
+CLEANFILES += grub-symdb
+
+# grub-objdump
+bin_UTILITIES += grub-objdump
+grub_objdump_SOURCES = util/grub-objdump.c util/obj.c util/misc.c \
+ util/obj_dump.c kern/list.c
+CLEANFILES += grub-objdump
+
# grub_macho2img assumes a lot about source file.
# So installing it definitively is useless
# But adding to bin_UTILITIES is needed for
@@ -512,15 +529,15 @@ sh_mod_CFLAGS = $(COMMON_CFLAGS)
sh_mod_LDFLAGS = $(COMMON_LDFLAGS)
# For lua.mod.
-lua_mod_SOURCES = script/lua/lapi.c script/lua/lcode.c script/lua/ldebug.c \
+lua_mod_SOURCES = script/lua/grub_main.c script/lua/grub_lib.c \
+ script/lua/lapi.c script/lua/lcode.c script/lua/ldebug.c \
script/lua/ldo.c script/lua/ldump.c script/lua/lfunc.c \
script/lua/lgc.c script/lua/llex.c script/lua/lmem.c \
script/lua/lobject.c script/lua/lopcodes.c script/lua/lparser.c \
script/lua/lstate.c script/lua/lstring.c script/lua/ltable.c \
script/lua/ltm.c script/lua/lundump.c script/lua/lvm.c \
script/lua/lzio.c script/lua/lauxlib.c script/lua/lbaselib.c \
- script/lua/linit.c script/lua/ltablib.c script/lua/lstrlib.c \
- script/lua/grub_main.c script/lua/grub_lib.c
+ script/lua/linit.c script/lua/ltablib.c script/lua/lstrlib.c
lua_mod_CFLAGS = $(COMMON_CFLAGS)
lua_mod_LDFLAGS = $(COMMON_LDFLAGS)
diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk
index f1915b6..185ffd4 100644
--- a/conf/i386-pc.rmk
+++ b/conf/i386-pc.rmk
@@ -53,7 +53,7 @@ kernel_img_SOURCES = kern/i386/pc/startup.S \
kern/misc.c kern/mm.c kern/reader.c kern/term.c \
kern/rescue_parser.c kern/rescue_reader.c \
kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \
- kern/$(target_cpu)/dl.c kern/i386/pc/init.c kern/i386/pc/mmap.c \
+ kern/i386/pc/init.c kern/i386/pc/mmap.c \
kern/parser.c kern/partition.c \
kern/i386/tsc.c kern/i386/pit.c \
kern/generic/rtc_get_time_ms.c \
diff --git a/genmk.rb b/genmk.rb
index e3866c1..39141f4 100644
--- a/genmk.rb
+++ b/genmk.rb
@@ -106,60 +106,16 @@ class PModule
objs_str = objs.join(' ')
deps = objs.collect {|obj| obj.suffix('d')}
deps_str = deps.join(' ')
- pre_obj = 'pre-' + @name.suffix('o')
- mod_src = 'mod-' + @name.suffix('c')
- mod_obj = mod_src.suffix('o')
- defsym = 'def-' + @name.suffix('lst')
- undsym = 'und-' + @name.suffix('lst')
mod_name = File.basename(@name, '.mod')
symbolic_name = mod_name.sub(/\.[^\.]*$/, '')
- "CLEANFILES += #{@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{undsym}
-ifneq ($(#{prefix}_EXPORTS),no)
-CLEANFILES += #{defsym}
-DEFSYMFILES += #{defsym}
-endif
+ "CLEANFILES += #{@name} #{objs_str}
MOSTLYCLEANFILES += #{deps_str}
-UNDSYMFILES += #{undsym}
-
-ifneq ($(TARGET_APPLE_CC),1)
-#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF)
- -rm -f $@
- $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} #{mod_obj}
- if test ! -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 $@
-else
-#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF)
- -rm -f $@
- -rm -f $@.bin
- $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@.bin #{pre_obj} #{mod_obj}
- $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@
- -rm -f $@.bin
-endif
-
-#{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str}
- -rm -f $@
- $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{objs_str}
-#{mod_obj}: #{mod_src}
- $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $<
-
-#{mod_src}: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh
- sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1)
-
-ifneq ($(#{prefix}_EXPORTS),no)
-ifneq ($(TARGET_APPLE_CC),1)
-#{defsym}: #{pre_obj}
- $(NM) -g --defined-only -P -p $< | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@
-else
-#{defsym}: #{pre_obj}
- $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]' | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@
-endif
-endif
+#{@name}: $(#{prefix}_DEPENDENCIES) #{objs_str} grub-mkmod
+ ./grub-mkmod -o $@ $(filter %.o, $^)
-#{undsym}: #{pre_obj}
- echo '#{mod_name}' > $@
- $(NM) -u -P -p $< | cut -f1 -d' ' >> $@
+MODFILES += #{@name}
" + objs.collect_with_index do |obj, i|
src = sources[i]
diff --git a/include/grub/dl.h b/include/grub/dl.h
index e24b832..3f8b328 100644
--- a/include/grub/dl.h
+++ b/include/grub/dl.h
@@ -85,7 +85,6 @@ struct grub_dl
};
typedef struct grub_dl *grub_dl_t;
-grub_err_t EXPORT_FUNC(grub_dl_check_header) (void *ehdr, grub_size_t size);
grub_dl_t EXPORT_FUNC(grub_dl_load_file) (const char *filename);
grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name);
grub_dl_t grub_dl_load_core (void *addr, grub_size_t size);
diff --git a/include/grub/elf.h b/include/grub/elf.h
index 1a1ec13..6d2f28d 100644
--- a/include/grub/elf.h
+++ b/include/grub/elf.h
@@ -454,8 +454,8 @@ typedef struct
the end of a chain, meaning no further symbols are found in that bucket. */
#define STN_UNDEF 0 /* End of a chain. */
-#define STN_ABS 65521
-
+#define STN_ABS 0xfff1
+#define STN_COMMON 0xfff2
/* How to extract and insert information held in the st_other field. */
diff --git a/include/grub/obj.h b/include/grub/obj.h
new file mode 100644
index 0000000..29ff8dc
--- /dev/null
+++ b/include/grub/obj.h
@@ -0,0 +1,90 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/>.
+ */
+
+#ifndef GRUB_OBJ_H
+#define GRUB_OBJ_H 1
+
+#include <grub/types.h>
+
+#define GRUB_OBJ_HEADER_MAGIC 0x4a424f47 /* GOBJ */
+#define GRUB_OBJ_HEADER_VERSION 1
+
+#define GRUB_OBJ_SEG_END 0
+#define GRUB_OBJ_SEG_TEXT 1
+#define GRUB_OBJ_SEG_DATA 2
+#define GRUB_OBJ_SEG_RDATA 3
+#define GRUB_OBJ_SEG_BSS 4
+
+#define GRUB_OBJ_FUNC_NONE 0xffff
+
+struct grub_obj_segment
+{
+ grub_uint8_t type;
+ grub_uint32_t offset;
+ grub_uint8_t align;
+ grub_uint32_t size;
+} __attribute__((packed));
+
+struct grub_obj_header
+{
+ grub_uint32_t magic;
+ grub_uint16_t version;
+ grub_uint16_t symbol_table;
+ grub_uint16_t reloc_table;
+ grub_uint16_t string_table;
+ grub_uint16_t init_func;
+ grub_uint16_t fini_func;
+ grub_uint32_t mod_deps;
+ struct grub_obj_segment segments[1];
+} __attribute__((packed));
+
+#define GRUB_OBJ_SEGMENT_END 0xff
+
+#define GRUB_OBJ_REL_DIR32 0
+#define GRUB_OBJ_REL_REL32 1
+#define GRUB_OBJ_REL_DIR64 2
+#define GRUB_OBJ_REL_REL64 3
+
+#define GRUB_OBJ_REL_ISREL 1
+#define GRUB_OBJ_REL_64BIT 2
+
+struct grub_obj_symbol
+{
+ grub_uint8_t segment;
+ grub_uint16_t name;
+ grub_uint32_t offset;
+} __attribute__((packed));
+
+struct grub_obj_reloc
+{
+ grub_uint8_t segment;
+ grub_uint8_t type;
+ grub_uint32_t offset;
+ grub_uint8_t symbol_segment;
+} __attribute__((packed));
+
+struct grub_obj_reloc_extern
+{
+ grub_uint8_t segment;
+ grub_uint8_t type;
+ grub_uint32_t offset;
+ grub_uint8_t symbol_segment;
+ grub_uint16_t symbol_name;
+} __attribute__((packed));
+
+#endif /* ! GRUB_OBJ_H */
diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h
index 6a93ab0..841d702 100644
--- a/include/grub/util/misc.h
+++ b/include/grub/util/misc.h
@@ -26,6 +26,7 @@
#include <config.h>
#include <grub/types.h>
+#include <grub/list.h>
#ifdef __NetBSD__
/* NetBSD uses /boot for its boot block. */
@@ -46,6 +47,9 @@ void grub_util_error (const char *fmt, ...) __attribute__ ((noreturn));
void *xmalloc (size_t size);
void *xrealloc (void *ptr, size_t size);
char *xstrdup (const char *str);
+void *xmalloc_zero (size_t size);
+
+void * grub_list_reverse (grub_list_t head);
char *grub_util_get_path (const char *dir, const char *file);
size_t grub_util_get_fp_size (FILE *fp);
@@ -56,6 +60,8 @@ void grub_util_load_image (const char *path, char *buf);
void grub_util_write_image (const char *img, size_t size, FILE *out);
void grub_util_write_image_at (const void *img, size_t size, off_t offset,
FILE *out);
+char * grub_util_get_module_name (const char *str);
+char * grub_util_get_module_path (const char *prefix, const char *str);
#ifndef HAVE_ASPRINTF
diff --git a/include/grub/util/obj.h b/include/grub/util/obj.h
new file mode 100644
index 0000000..f0cd610
--- /dev/null
+++ b/include/grub/util/obj.h
@@ -0,0 +1,85 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/>.
+ */
+
+#ifndef GRUB_UTIL_OBJ_HEADER
+#define GRUB_UTIL_OBJ_HEADER 1
+
+#include <config.h>
+#include <grub/types.h>
+#include <grub/obj.h>
+#include <grub/list.h>
+
+#include <stdio.h>
+
+struct grub_util_obj_segment
+{
+ struct grub_util_obj_segment *next;
+ struct grub_obj_segment segment;
+ char *data;
+ grub_uint32_t raw_size;
+ grub_uint32_t file_off;
+ int index;
+};
+
+struct grub_util_obj_symbol
+{
+ struct grub_util_obj_symbol *next;
+ char *name;
+ struct grub_util_obj_segment *segment;
+ struct grub_obj_symbol symbol;
+};
+
+struct grub_util_obj_reloc
+{
+ struct grub_util_obj_reloc *next;
+ struct grub_util_obj_segment *segment;
+ struct grub_obj_reloc reloc;
+ struct grub_util_obj_segment *symbol_segment;
+ grub_uint32_t symbol_offset;
+ char *symbol_name;
+};
+
+struct grub_util_obj
+{
+ struct grub_util_obj_segment *segments;
+ struct grub_util_obj_symbol *symbols;
+ struct grub_util_obj_reloc *relocs;
+ grub_uint32_t mod_attr;
+ grub_uint32_t mod_deps;
+};
+
+#define GRUB_OBJ_MERGE_NONE 0
+#define GRUB_OBJ_MERGE_SAME 1
+#define GRUB_OBJ_MERGE_ALL 2
+
+void grub_obj_reverse (struct grub_util_obj *obj);
+void grub_obj_sort_segments (struct grub_util_obj *obj);
+void grub_obj_merge_segments (struct grub_util_obj *obj, int merge);
+void grub_obj_reloc_symbols (struct grub_util_obj *obj, int merge);
+void grub_obj_save (struct grub_util_obj *obj, char *mod_name, FILE *fp);
+struct grub_util_obj *grub_obj_load (char *image, int size, int load_data);
+void grub_obj_free (struct grub_util_obj *obj);
+
+void grub_obj_dump_segments (struct grub_util_obj *obj);
+void grub_obj_dump_symbols (struct grub_util_obj *obj);
+void grub_obj_dump_relocs (struct grub_util_obj *obj);
+
+int pe_add_file (struct grub_util_obj *obj, char *image, int size);
+int elf_add_file (struct grub_util_obj *obj, char *image, int size);
+
+#endif /* ! GRUB_UTIL_OBJ_HEADER */
diff --git a/kern/dl.c b/kern/dl.c
index 6c863be..fd81dd7 100644
--- a/kern/dl.c
+++ b/kern/dl.c
@@ -18,8 +18,8 @@
*/
#include <config.h>
-#include <grub/elf.h>
#include <grub/dl.h>
+#include <grub/obj.h>
#include <grub/misc.h>
#include <grub/mm.h>
#include <grub/err.h>
@@ -219,78 +219,46 @@ grub_dl_get_section_addr (grub_dl_t mod, unsigned n)
return 0;
}
-/* Check if EHDR is a valid ELF header. */
-grub_err_t
-grub_dl_check_header (void *ehdr, grub_size_t size)
-{
- Elf_Ehdr *e = ehdr;
-
- /* Check the header size. */
- if (size < sizeof (Elf_Ehdr))
- return grub_error (GRUB_ERR_BAD_OS, "ELF header smaller than expected");
-
- /* Check the magic numbers. */
- if (grub_arch_dl_check_header (ehdr)
- || e->e_ident[EI_MAG0] != ELFMAG0
- || e->e_ident[EI_MAG1] != ELFMAG1
- || e->e_ident[EI_MAG2] != ELFMAG2
- || e->e_ident[EI_MAG3] != ELFMAG3
- || e->e_ident[EI_VERSION] != EV_CURRENT
- || e->e_version != EV_CURRENT)
- return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic");
-
- return GRUB_ERR_NONE;
-}
-
/* Load all segments from memory specified by E. */
static grub_err_t
-grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
+grub_dl_load_segments (grub_dl_t mod, struct grub_obj_header *e)
{
unsigned i;
- Elf_Shdr *s;
+ struct grub_obj_segment *s;
- for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff);
- i < e->e_shnum;
- i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize))
+ for (i = 0, s = &e->segments[0]; s->type != GRUB_OBJ_SEGMENT_END; i++, s++)
{
- if (s->sh_flags & SHF_ALLOC)
+ grub_dl_segment_t seg;
+ void *addr;
+
+ seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
+ if (! seg)
+ return grub_errno;
+
+ addr = grub_memalign (s->align, s->size);
+ if (! addr)
{
- grub_dl_segment_t seg;
+ grub_free (seg);
+ return grub_errno;
+ }
- seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg));
- if (! seg)
- return grub_errno;
+ grub_memset (addr, 0, s->size);
+ grub_memcpy (addr, (char *) e + s->offset,
+ (s + 1)->offset - s->offset);
+ seg->addr = addr;
- if (s->sh_size)
- {
- void *addr;
-
- addr = grub_memalign (s->sh_addralign, s->sh_size);
- if (! addr)
- {
- grub_free (seg);
- return grub_errno;
- }
-
- switch (s->sh_type)
- {
- case SHT_PROGBITS:
- grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size);
- break;
- case SHT_NOBITS:
- grub_memset (addr, 0, s->sh_size);
- break;
- }
-
- seg->addr = addr;
- }
- else
- seg->addr = 0;
+ seg->size = s->size;
+ seg->section = i;
+ seg->next = mod->segment;
+ mod->segment = seg;
- seg->size = s->sh_size;
- seg->section = i;
- seg->next = mod->segment;
- mod->segment = seg;
+ if (! i)
+ {
+ if (e->init_func != GRUB_OBJ_FUNC_NONE)
+ mod->init = (void (*) (grub_dl_t)) ((char *) addr + e->init_func);
+
+ if (e->fini_func != GRUB_OBJ_FUNC_NONE)
+ mod->fini = (void (*) (void)) ((char *) addr + e->fini_func);
}
}
@@ -298,92 +266,67 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e)
}
static grub_err_t
-grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e)
+grub_dl_resolve_symbols (grub_dl_t mod, struct grub_obj_header *e)
{
- unsigned i;
- Elf_Shdr *s;
- Elf_Sym *sym;
- const char *str;
- Elf_Word size, entsize;
-
- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
- i < e->e_shnum;
- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
- if (s->sh_type == SHT_SYMTAB)
- break;
+ char *strtab;
+ struct grub_obj_symbol *sym;
+ struct grub_obj_reloc_extern *rel;
- if (i == e->e_shnum)
- return grub_error (GRUB_ERR_BAD_MODULE, "no symbol table");
+ strtab = (char *) e + e->string_table;
-#ifdef GRUB_MODULES_MACHINE_READONLY
- mod->symtab = grub_malloc (s->sh_size);
- memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size);
-#else
- mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset);
-#endif
- sym = mod->symtab;
- size = s->sh_size;
- entsize = s->sh_entsize;
+ for (sym = (struct grub_obj_symbol *) ((char *) e + e->symbol_table);
+ sym->segment != GRUB_OBJ_SEGMENT_END; sym++)
+ {
+ char *addr;
- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link);
- str = (char *) e + s->sh_offset;
+ addr = grub_dl_get_section_addr (mod, sym->segment);
+ addr += sym->offset;
- for (i = 0;
- i < size / entsize;
- i++, sym = (Elf_Sym *) ((char *) sym + entsize))
- {
- 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;
+ if (grub_dl_register_symbol (strtab + sym->name, addr, mod))
+ return grub_errno;
+ }
- switch (type)
- {
- case STT_NOTYPE:
- /* Resolve a global symbol. */
- if (sym->st_name != 0 && sym->st_shndx == 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);
- }
- else
- sym->st_value = 0;
- break;
+ for (rel = (struct grub_obj_reloc_extern *) ((char *) e + e->reloc_table);
+ rel->segment != GRUB_OBJ_SEGMENT_END;)
+ {
+ char *addr, *symbol_addr;
+ int type;
- case STT_OBJECT:
- 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;
- break;
+ addr = grub_dl_get_section_addr (mod, rel->segment);
+ addr += rel->offset;
+ type = rel->type;
- 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;
- break;
+ if (rel->symbol_segment == GRUB_OBJ_SEGMENT_END)
+ {
+ char *name;
+
+ name = strtab + rel->symbol_name;
+ symbol_addr = grub_dl_resolve_symbol (name);
+ if (! symbol_addr)
+ return grub_error (GRUB_ERR_BAD_MODULE,
+ "the symbol `%s' not found", name);
+ rel++;
+ }
+ else
+ {
+ symbol_addr = grub_dl_get_section_addr (mod, rel->symbol_segment);
+ rel = (struct grub_obj_reloc_extern *)
+ ((char *) rel + sizeof (struct grub_obj_reloc));
+ }
- case STT_SECTION:
- sym->st_value = (Elf_Addr) grub_dl_get_section_addr (mod,
- sym->st_shndx);
+ switch (type)
+ {
+ case GRUB_OBJ_REL_DIR32:
+ *((grub_uint32_t *) addr) += (grub_uint32_t) symbol_addr;
break;
- case STT_FILE:
- sym->st_value = 0;
+ case GRUB_OBJ_REL_REL32:
+ *((grub_uint32_t *) addr) += (grub_uint32_t) (symbol_addr - addr);
break;
default:
return grub_error (GRUB_ERR_BAD_MODULE,
- "unknown symbol type `%d'", (int) type);
+ "unknown reloc type %d", type);
}
}
@@ -398,74 +341,31 @@ grub_dl_call_init (grub_dl_t mod)
}
static grub_err_t
-grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e)
+grub_dl_resolve_dependencies (grub_dl_t mod, char *name)
{
- Elf_Shdr *s;
- const char *str;
- unsigned i;
-
- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
- str = (char *) e + s->sh_offset;
-
- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
- i < e->e_shnum;
- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
- if (grub_strcmp (str + s->sh_name, ".modname") == 0)
- {
- mod->name = grub_strdup ((char *) e + s->sh_offset);
- if (! mod->name)
- return grub_errno;
- break;
- }
-
- if (i == e->e_shnum)
- return grub_error (GRUB_ERR_BAD_MODULE, "no module name found");
-
- return GRUB_ERR_NONE;
-}
-
-static grub_err_t
-grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e)
-{
- Elf_Shdr *s;
- const char *str;
- unsigned i;
-
- s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize);
- str = (char *) e + s->sh_offset;
-
- for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff);
- i < e->e_shnum;
- i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize))
- if (grub_strcmp (str + s->sh_name, ".moddeps") == 0)
- {
- const char *name = (char *) e + s->sh_offset;
- const char *max = name + s->sh_size;
-
- while ((name < max) && (*name))
- {
- grub_dl_t m;
- grub_dl_dep_t dep;
-
- m = grub_dl_load (name);
- if (! m)
- return grub_errno;
+ while (1)
+ {
+ grub_dl_t m;
+ grub_dl_dep_t dep;
- grub_dl_ref (m);
+ name += grub_strlen (name) + 1;
+ if (! *name)
+ return GRUB_ERR_NONE;
- dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
- if (! dep)
- return grub_errno;
+ m = grub_dl_load (name);
+ if (! m)
+ return grub_errno;
- dep->mod = m;
- dep->next = mod->dep;
- mod->dep = dep;
+ grub_dl_ref (m);
- name += grub_strlen (name) + 1;
- }
- }
+ dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep));
+ if (! dep)
+ return grub_errno;
- return GRUB_ERR_NONE;
+ dep->mod = m;
+ dep->next = mod->dep;
+ mod->dep = dep;
+ }
}
#ifndef GRUB_UTIL
@@ -510,25 +410,18 @@ grub_dl_flush_cache (grub_dl_t mod)
grub_dl_t
grub_dl_load_core (void *addr, grub_size_t size)
{
- Elf_Ehdr *e;
+ struct grub_obj_header *e;
grub_dl_t mod;
+ char *name;
grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr,
(unsigned long) size);
- e = addr;
- if (grub_dl_check_header (e, size))
- return 0;
-
- if (e->e_type != ET_REL)
- {
- grub_error (GRUB_ERR_BAD_MODULE, "invalid ELF file type");
- return 0;
- }
- /* Make sure that every section is within the core. */
- if (size < e->e_shoff + e->e_shentsize * e->e_shnum)
+ e = addr;
+ if ((e->magic != GRUB_OBJ_HEADER_MAGIC) ||
+ (e->version != GRUB_OBJ_HEADER_VERSION))
{
- grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core");
+ grub_error (GRUB_ERR_BAD_OS, "invalid object file");
return 0;
}
@@ -536,7 +429,9 @@ grub_dl_load_core (void *addr, grub_size_t size)
if (! mod)
return 0;
- mod->name = 0;
+ name = (char *) addr + e->mod_deps;
+
+ mod->name = grub_strdup (name);
mod->ref_count = 1;
mod->dep = 0;
mod->segment = 0;
@@ -544,11 +439,9 @@ grub_dl_load_core (void *addr, grub_size_t size)
mod->fini = 0;
grub_dprintf ("modules", "relocating to %p\n", mod);
- if (grub_dl_resolve_name (mod, e)
- || grub_dl_resolve_dependencies (mod, e)
+ if (grub_dl_resolve_dependencies (mod, name)
|| grub_dl_load_segments (mod, e)
- || grub_dl_resolve_symbols (mod, e)
- || grub_arch_dl_relocate_symbols (mod, e))
+ || grub_dl_resolve_symbols (mod, e))
{
mod->fini = 0;
grub_dl_unload (mod);
diff --git a/util/grub-mkmod.c b/util/grub-mkmod.c
new file mode 100644
index 0000000..1ed1b55
--- /dev/null
+++ b/util/grub-mkmod.c
@@ -0,0 +1,176 @@
+/* grub-mkmod.c - tool to generate mod file from object files. */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+int
+grub_strcmp (const char *s1, const char *s2)
+{
+ return strcmp (s1, s2);
+}
+
+static struct option options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"output", required_argument, 0, 'o'},
+ {"name", required_argument, 0, 'n'},
+ {0, 0, 0, 0}
+};
+
+static void
+usage (int status)
+{
+ if (status)
+ fprintf (stderr, "Try ``grub-mkmod --help'' for more information.\n");
+ else
+ printf ("\
+Usage: grub-mkmod [OPTIONS] [OBJECT_FILES].\n\
+\n\
+Tool to generate mod file from object files.\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\
+ -o, --output=FILE output a generated image to FILE [default=stdout]\n\
+ -n, --name=NAME set module name\n\
+\n\
+Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
+
+ exit (status);
+}
+
+static void
+add_file (struct grub_util_obj *obj, char *image, int size)
+{
+ if ((! elf_add_file (obj, image, size)) &&
+ (! pe_add_file (obj, image, size)))
+ grub_util_error ("Invalid object format");
+}
+
+static void
+mkmod (char *objs[], char *name, FILE *fp)
+{
+ struct grub_util_obj *obj;
+ int merge = GRUB_OBJ_MERGE_ALL;
+
+ obj = xmalloc_zero (sizeof (*obj));
+ while (*objs)
+ {
+ char *image;
+ int size;
+
+ image = grub_util_read_image (*objs);
+ size = grub_util_get_image_size (*objs);
+ add_file (obj, image, size);
+ free (image);
+ objs++;
+ }
+
+ grub_obj_reverse (obj);
+ grub_obj_sort_segments (obj);
+ grub_obj_merge_segments (obj, merge);
+ grub_obj_reloc_symbols (obj, merge);
+ grub_obj_save (obj, name, fp);
+
+ grub_obj_free (obj);
+}
+
+int
+main (int argc, char *argv[])
+{
+ FILE *fp = stdout;
+ char *output = NULL;
+ char *name = NULL;
+
+ progname = "grub-pe2mod";
+
+ /* Check for options. */
+ while (1)
+ {
+ int c = getopt_long (argc, argv, "hVvo:n:", 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;
+
+ case 'o':
+ if (output)
+ free (output);
+
+ output = xstrdup (optarg);
+ break;
+
+ case 'n':
+ if (name)
+ free (name);
+
+ name = xstrdup (optarg);
+ break;
+
+ default:
+ usage (1);
+ break;
+ }
+ }
+
+ if (! name)
+ {
+ if (! output)
+ grub_util_error ("no module name");
+ name = grub_util_get_module_name (output);
+ }
+
+ if (output)
+ {
+ fp = fopen (output, "wb");
+ if (! fp)
+ grub_util_error ("cannot open %s", output);
+ free (output);
+ }
+
+ mkmod (argv + optind, name, fp);
+
+ fclose (fp);
+ free (name);
+
+ return 0;
+}
diff --git a/util/grub-objdump.c b/util/grub-objdump.c
new file mode 100644
index 0000000..9a30362
--- /dev/null
+++ b/util/grub-objdump.c
@@ -0,0 +1,172 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <getopt.h>
+
+int
+grub_strcmp (const char *s1, const char *s2)
+{
+ return strcmp (s1, s2);
+}
+
+static struct option options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"version", no_argument, 0, 'V'},
+ {"verbose", no_argument, 0, 'v'},
+ {"all-headers", no_argument, 0, 'x'},
+ {"segment", no_argument, 0, 's'},
+ {"syms", no_argument, 0, 't'},
+ {"reloc", no_argument, 0, 'r'},
+ {0, 0, 0, 0}
+};
+
+static void
+usage (int status)
+{
+ if (status)
+ fprintf (stderr, "Try ``grub-mkmod --help'' for more information.\n");
+ else
+ printf ("\
+Usage: grub-objdump [OPTIONS] [MODULE_FILES].\n\
+\n\
+Tool to generate mod file from object files.\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\
+ -x, --all display all information\n\
+ -s, --segment display segment information\n\
+ -t, --syms display symbol table\n\
+ -r, --reloc display reloc table\n\
+\n\
+Report bugs to <%s>.\n", PACKAGE_BUGREPORT);
+
+ exit (status);
+}
+
+#define FLAG_DUMP_SEGMENT 1
+#define FLAG_DUMP_SYMBOL 2
+#define FLAG_DUMP_RELOC 4
+#define FLAG_DUMP_ALL 7
+
+static void
+objdump (char *objs[], int flag)
+{
+ while (*objs)
+ {
+ struct grub_util_obj *obj;
+ char *image;
+ int size;
+
+ image = grub_util_read_image (*objs);
+ size = grub_util_get_image_size (*objs);
+ obj = grub_obj_load (image, size, 1);
+
+ printf ("filename: %s\n", *objs);
+ printf ("mod name: %s\n", image + obj->mod_deps);
+ printf ("mod attr: 0x%x\n", obj->mod_attr);
+ printf ("mod deps: 0x%x\n", obj->mod_deps);
+
+ if (flag & FLAG_DUMP_SEGMENT)
+ {
+ printf ("\n");
+ grub_obj_dump_segments (obj);
+ }
+
+ if (flag & FLAG_DUMP_SYMBOL)
+ {
+ printf ("\n");
+ grub_obj_dump_symbols (obj);
+ }
+
+ if (flag & FLAG_DUMP_RELOC)
+ {
+ printf ("\n");
+ grub_obj_dump_relocs (obj);
+ }
+
+ grub_obj_free (obj);
+ free (image);
+ objs++;
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ int flag = 0;
+
+ progname = "grub-objdump";
+
+ /* Check for options. */
+ while (1)
+ {
+ int c = getopt_long (argc, argv, "hVvxstr", 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;
+
+ case 'x':
+ flag |= FLAG_DUMP_ALL;
+ break;
+
+ case 's':
+ flag |= FLAG_DUMP_SEGMENT;
+ break;
+
+ case 't':
+ flag |= FLAG_DUMP_SYMBOL;
+ break;
+
+ case 'r':
+ flag |= FLAG_DUMP_RELOC;
+ break;
+
+ default:
+ usage (1);
+ break;
+ }
+ }
+
+ objdump (argv + optind, flag);
+
+ return 0;
+}
diff --git a/util/grub-symdb.c b/util/grub-symdb.c
new file mode 100644
index 0000000..94a0904
--- /dev/null
+++ b/util/grub-symdb.c
@@ -0,0 +1,811 @@
+/* grub-symdb.c - manage symbol database */
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#define _GNU_SOURCE 1
+#include <getopt.h>
+
+int
+grub_strcmp (const char *s1, const char *s2)
+{
+ return strcmp (s1, s2);
+}
+
+struct grub_symbol_list
+{
+ struct grub_symbol_list *next;
+ char *name;
+ struct grub_named_list *defs;
+ struct grub_named_list *unds;
+};
+
+static struct grub_symbol_list *symbol_list;
+
+struct grub_update_list
+{
+ struct grub_update_list *next;
+ char *name;
+ struct grub_named_list *add_mods;
+ struct grub_named_list *del_mods;
+ struct grub_named_list *cur_mods;
+};
+
+static struct grub_update_list *update_list;
+
+struct grub_mod_syms
+{
+ struct grub_named_list *defs;
+ struct grub_named_list *unds;
+};
+
+
+void *
+grub_sort_list_find (grub_named_list_t head, const char *name)
+{
+ grub_named_list_t result = 0;
+
+ auto int list_find (grub_named_list_t item);
+ int list_find (grub_named_list_t item)
+ {
+ int r;
+
+ r = strcmp (name, item->name);
+ if (! r)
+ {
+ result = item;
+ return 1;
+ }
+
+ return (r < 0);
+ }
+
+ grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_find);
+ return result;
+}
+
+static void
+grub_sort_list_insert (grub_named_list_t *head, grub_named_list_t item)
+{
+ auto int test (grub_named_list_t new_item, grub_named_list_t item);
+ int test (grub_named_list_t new_item, grub_named_list_t item)
+ {
+ return (strcmp (new_item->name, item->name) < 0);
+ }
+
+ grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (item),
+ (grub_list_test_t) test);
+}
+
+static void
+free_named_list (grub_named_list_t *head)
+{
+ grub_named_list_t cur = *head;
+
+ while (cur)
+ {
+ grub_named_list_t tmp;
+
+ tmp = cur;
+ cur = cur->next;
+ free ((char *) tmp->name);
+ free (tmp);
+ }
+
+ *head = 0;
+}
+
+static int
+remove_string (grub_named_list_t *head, char *name)
+{
+ grub_named_list_t p;
+
+ p = grub_sort_list_find (*head, name);
+ if (p)
+ {
+ grub_list_remove (GRUB_AS_LIST_P (head), GRUB_AS_LIST (p));
+ free ((char *) p->name);
+ free (p);
+
+ return 1;
+ }
+
+ return 0;
+}
+
+static int
+insert_string (grub_named_list_t *head, char *name)
+{
+ struct grub_named_list *n;
+
+ n = grub_sort_list_find (*head, name);
+ if (n)
+ return 0;
+
+ n = xmalloc (sizeof (struct grub_named_list));
+ n->name = xstrdup (name);
+ grub_sort_list_insert (head, n);
+
+ return 1;
+}
+
+static struct grub_symbol_list *
+insert_symbol (char *name)
+{
+ struct grub_symbol_list *n;
+
+ n = grub_sort_list_find (GRUB_AS_NAMED_LIST (symbol_list), name);
+ if (! n)
+ {
+ n = xmalloc (sizeof (struct grub_symbol_list));
+ n->name = xstrdup (name);
+ n->defs = 0;
+ n->unds = 0;
+
+ grub_sort_list_insert (GRUB_AS_NAMED_LIST_P (&symbol_list),
+ GRUB_AS_NAMED_LIST (n));
+ }
+
+ return n;
+}
+
+static struct grub_update_list *
+insert_update (char *name)
+{
+ struct grub_update_list *n;
+
+ n = grub_sort_list_find (GRUB_AS_NAMED_LIST (update_list), name);
+ if (! n)
+ {
+ n = xmalloc (sizeof (struct grub_update_list));
+ n->name = xstrdup (name);
+ n->add_mods = 0;
+ n->del_mods = 0;
+ n->cur_mods = 0;
+
+ grub_sort_list_insert (GRUB_AS_NAMED_LIST_P (&update_list),
+ GRUB_AS_NAMED_LIST (n));
+ }
+
+ return n;
+}
+
+static void
+add_update (char *m1, char *m2, int is_add)
+{
+ struct grub_update_list *u;
+
+ u = insert_update (m2);
+ if (is_add)
+ {
+ remove_string (&u->del_mods, m1);
+ insert_string (&u->add_mods, m1);
+ }
+ else
+ insert_string (&u->del_mods, m1);
+}
+
+static void
+read_symdb (char *path)
+{
+ FILE *fp;
+ char line[512];
+ struct grub_symbol_list *sym = 0;
+
+ fp = fopen (path, "r");
+ if (! fp)
+ return;
+
+ while (fgets (line, sizeof (line), fp))
+ {
+ char *p;
+
+ p = line + strlen (line) - 1;
+ while ((p >= line) && ((*p == '\r') || (*p == '\n') || (*p == ' ')))
+ p--;
+
+ if (p < line)
+ continue;
+
+ *(p + 1) = 0;
+
+ p = line;
+ while (*p == ' ')
+ p++;
+
+ if (*p == '#')
+ continue;
+
+ if ((*p == '+') || (*p == '-'))
+ {
+ if (! sym)
+ grub_util_error ("No current symbol.");
+
+ insert_string ((*p == '+') ? &sym->defs : &sym->unds, p + 1);
+ }
+ else
+ sym = insert_symbol (p);
+ }
+
+ fclose (fp);
+}
+
+static void
+write_symdb (char *path)
+{
+ FILE *fp;
+ struct grub_symbol_list *sym;
+
+ fp = fopen (path, "w");
+ if (! fp)
+ grub_util_error ("Can\'t write to ", path);
+
+ sym = symbol_list;
+ while (sym)
+ {
+ struct grub_named_list *mod;
+
+ fprintf (fp, "%s\n", sym->name);
+ mod = sym->defs;
+ while (mod)
+ {
+ fprintf (fp, "+%s\n", mod->name);
+ mod = mod->next;
+ }
+ mod = sym->unds;
+ while (mod)
+ {
+ fprintf (fp, "-%s\n", mod->name);
+ mod = mod->next;
+ }
+
+ sym = sym->next;
+ }
+
+ fclose (fp);
+}
+
+static void
+check_symdb (void)
+{
+ struct grub_symbol_list *sym;
+
+ sym = symbol_list;
+ while (sym)
+ {
+ if (! sym->defs)
+ printf ("undefined: %s\n", sym->name);
+ else if (sym->defs->next)
+ printf ("duplicate: %s\n", sym->name);
+
+ sym = sym->next;
+ }
+}
+
+static void
+read_mod_syms (struct grub_mod_syms *mod_syms, char *path)
+{
+ struct grub_util_obj *obj;
+ char *image;
+ size_t size;
+ struct grub_util_obj_symbol *sym;
+ struct grub_util_obj_reloc *rel;
+
+ mod_syms->defs = 0;
+ mod_syms->unds = 0;
+
+ image = grub_util_read_image (path);
+ size = grub_util_get_image_size (path);
+ obj = grub_obj_load (image, size, 0);
+
+ sym = obj->symbols;
+ while (sym)
+ {
+ insert_string (&mod_syms->defs, sym->name);
+ sym = sym->next;
+ }
+
+ rel = obj->relocs;
+ while (rel)
+ {
+ if (rel->symbol_name)
+ insert_string (&mod_syms->unds, rel->symbol_name);
+ rel = rel->next;
+ }
+
+ grub_obj_free (obj);
+ free (image);
+}
+
+static void
+update_mods (char *mods[], const char *dir)
+{
+ for (; mods[0]; mods++)
+ {
+ char *mod_name, *mod_path;
+ struct grub_mod_syms mod_syms;
+ struct grub_named_list *m;
+
+ mod_name = grub_util_get_module_name (mods[0]);
+ mod_path = grub_util_get_module_path (dir, mod_name);
+
+ if (! strcmp (mod_name, "grub-symdb"))
+ {
+ free (mod_name);
+ free (mod_path);
+ continue;
+ }
+
+ read_mod_syms (&mod_syms, mod_path);
+
+ m = mod_syms.defs;
+ while (m)
+ {
+ struct grub_symbol_list *sym;
+ struct grub_named_list *n;
+
+ sym = insert_symbol ((char *) m->name);
+ insert_string (&sym->defs, mod_name);
+
+ n = sym->unds;
+ while (n)
+ {
+ add_update ((char *) mod_name, (char *) n->name, 1);
+ n = n->next;
+ }
+
+ m = m->next;
+ }
+
+ m = mod_syms.unds;
+ while (m)
+ {
+ struct grub_symbol_list *sym;
+ struct grub_named_list *n;
+
+ sym = insert_symbol ((char *) m->name);
+ insert_string (&sym->unds, mod_name);
+
+ n = sym->defs;
+ while (n)
+ {
+ add_update ((char *) n->name, (char *) mod_name, 1);
+ n = n->next;
+ }
+
+ m = m->next;
+ }
+
+ free (mod_name);
+ free (mod_path);
+ }
+}
+
+static void
+remove_mods (char *mods[])
+{
+ for (; mods[0]; mods++)
+ {
+ char *mod_name;
+ struct grub_symbol_list *sym;
+
+ mod_name = grub_util_get_module_name (mods[0]);
+
+ sym = symbol_list;
+ while (sym)
+ {
+ struct grub_named_list *m, *n;
+
+ m = sym->defs;
+ while (m)
+ {
+ int r;
+
+ r = strcmp (mod_name, m->name);
+ if (! r)
+ break;
+
+ if (r < 0)
+ {
+ m = 0;
+ break;
+ }
+
+ m = m->next;
+ }
+
+ n = sym->unds;
+ while (n)
+ {
+ if (m)
+ {
+ add_update ((char *) m->name, (char *) n->name, 0);
+ }
+ else
+ {
+ int r;
+
+ r = strcmp (mod_name, n->name);
+ if (! r)
+ {
+ m = sym->defs;
+ while (m)
+ {
+ add_update ((char *) m->name, (char *) n->name, 0);
+ m = m->next;
+ }
+
+ break;
+ }
+
+ if (r < 0)
+ break;
+ }
+
+ n = n->next;
+ }
+
+ sym = sym->next;
+ }
+
+ free (mod_name);
+ }
+}
+
+static void
+dump_update (void)
+{
+ struct grub_update_list *u;
+
+ u = update_list;
+ while (u)
+ {
+ struct grub_named_list *n;
+
+ printf ("%s:" , u->name);
+ n = u->add_mods;
+ while (n)
+ {
+ printf (" +%s", n->name);
+ n = n->next;
+ }
+
+ n = u->del_mods;
+ while (n)
+ {
+ printf (" -%s", n->name);
+ n = n->next;
+ }
+
+ printf ("\n");
+ u = u->next;
+ }
+}
+
+static void
+update_deps (struct grub_update_list *u, char *path)
+{
+ struct grub_named_list *n;
+ int modified;
+
+ modified = 0;
+ n = u->del_mods;
+ while (n)
+ {
+ modified |= remove_string (&u->cur_mods, (char *) n->name);
+ n = n->next;
+ }
+ n = u->add_mods;
+ while (n)
+ {
+ modified |= insert_string (&u->cur_mods, (char *) n->name);
+ n = n->next;
+ }
+
+ if (modified)
+ {
+ char *image, *p;
+ struct grub_obj_header *hdr;
+ int size;
+ FILE *fp;
+
+ image = grub_util_read_image (path);
+ hdr = (struct grub_obj_header *) image;
+
+ size = hdr->mod_deps;
+ size += strlen (image + size) + 1;
+
+ fp = fopen (path, "wb");
+ if (! fp)
+ grub_util_error ("Can\'t write to %s", path);
+
+ grub_util_write_image (image, size, fp);
+
+ p = image;
+ n = u->cur_mods;
+ while (n)
+ {
+ strcpy (p, n->name);
+ p += strlen (p) + 1;
+ n = n->next;
+ }
+ *(p++) = 0;
+
+ grub_util_write_image (image, p - image, fp);
+
+ fclose (fp);
+ free (image);
+ }
+}
+
+static void
+write_moddep (struct grub_update_list *u, FILE *fp)
+{
+ struct grub_named_list *n;
+
+ if (! u->cur_mods)
+ return;
+
+ fprintf (fp, "%s:", u->name);
+ n = u->cur_mods;
+ while (n)
+ {
+ fprintf (fp, " %s", n->name);
+ n = n->next;
+ }
+
+ fprintf (fp, "\n");
+ free_named_list (&u->cur_mods);
+}
+
+static void
+update_moddep (char *dir)
+{
+ FILE *fp;
+ struct stat st;
+ char *path, *image;
+ struct grub_update_list *u;
+
+ path = grub_util_get_path (dir, "moddep.lst");
+ image = (stat (path, &st) == 0) ? grub_util_read_image (path) : 0;
+
+ fp = fopen (path, "w");
+ if (! fp)
+ grub_util_error ("Can\'t write to ", path);
+
+ if (image)
+ {
+ char *line;
+
+ line = image;
+ while (*line)
+ {
+ char *p, *c;
+ int n;
+
+ n = strcspn (line, "\r\n");
+ p = line;
+
+ line += n;
+ while ((*line == '\r') || (*line == '\n'))
+ line++;
+
+ *(p + n) = 0;
+
+ c = strchr (p, ':');
+ if (! c)
+ continue;
+
+ *c = 0;
+ u = update_list;
+ while (u)
+ {
+ int r;
+
+ r = strcmp (p, u->name);
+ if (! r)
+ break;
+
+ if (r < 0)
+ {
+ u = 0;
+ break;
+ }
+
+ u = u->next;
+ }
+ *c = ':';
+
+ if (u)
+ write_moddep (u, fp);
+ else
+ fprintf (fp, "%s\n", p);
+ }
+ }
+
+ u = update_list;
+ while (u)
+ {
+ write_moddep (u, fp);
+ u = u->next;
+ }
+
+ fclose (fp);
+ free (path);
+ free (image);
+}
+
+static void
+apply_update (char *dir)
+{
+ struct grub_update_list *u;
+
+ u = update_list;
+ while (u)
+ {
+ char *mod_path;
+
+ mod_path = grub_util_get_module_path (dir, u->name);
+ update_deps (u, mod_path);
+ free (mod_path);
+ u = u->next;
+ }
+
+ update_moddep (dir);
+}
+
+static struct option options[] =
+ {
+ {"directory", required_argument, 0, 'd'},
+ {"test", no_argument, 0, 't'},
+ {"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-symdb --help'' for more information.\n");
+ else
+ printf ("\
+Usage: grub-symdb [OPTION]... COMMAND\n\
+\n\
+Manage the symbol database of GRUB.\n\
+\nCommands:\n\
+ update MODULES add/update modules to the symbol database\n\
+ remove MODULES remove modules from the symbol databsae\n\
+ check check for duplicate and unresolved symbols\n\
+\n\
+ -d, --directory=DIR use images and modules under DIR [default=%s]\n\
+ -t, --test test mode\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\
+", GRUB_LIBDIR, PACKAGE_BUGREPORT);
+
+ exit (status);
+}
+
+int
+main (int argc, char *argv[])
+{
+ char *dir = NULL;
+ char *path;
+ int test_mode = 0;
+
+ progname = "grub-symdb";
+
+ while (1)
+ {
+ int c = getopt_long (argc, argv, "d:thVv", options, 0);
+
+ if (c == -1)
+ break;
+ else
+ switch (c)
+ {
+ case 'd':
+ if (dir)
+ free (dir);
+
+ dir = xstrdup (optarg);
+ break;
+
+ case 't':
+ test_mode++;
+ break;
+
+ case 'h':
+ usage (0);
+ break;
+
+ case 'V':
+ printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION);
+ return 0;
+
+ case 'v':
+ verbosity++;
+ break;
+
+ default:
+ usage (1);
+ break;
+ }
+ }
+
+ if (! dir)
+ dir = xstrdup (GRUB_LIBDIR);
+
+ path = grub_util_get_path (dir, "modsym.lst");
+
+ argv += optind;
+ argc -= optind;
+ if (argc == 0)
+ grub_util_error ("No command specified.");
+
+ read_symdb (path);
+ if (! strcmp (argv[0], "update"))
+ {
+ remove_mods (argv + 1);
+ update_mods (argv + 1, dir);
+ if (test_mode)
+ dump_update ();
+ else
+ {
+ apply_update (dir);
+ write_symdb (path);
+ }
+ }
+ else if (! strcmp (argv[0], "remove"))
+ {
+ remove_mods (argv + 1);
+ if (test_mode)
+ dump_update ();
+ else
+ {
+ apply_update (dir);
+ write_symdb (path);
+ }
+ }
+ else if (! strcmp (argv[0], "check"))
+ {
+ check_symdb ();
+ }
+ else
+ grub_util_error ("Unkown command %s.", argv[0]);
+
+ free (path);
+ free (dir);
+
+ return 0;
+}
diff --git a/util/misc.c b/util/misc.c
index f615a42..955a184 100644
--- a/util/misc.c
+++ b/util/misc.c
@@ -143,6 +143,36 @@ xstrdup (const char *str)
return dup;
}
+void *
+xmalloc_zero (size_t size)
+{
+ void *p;
+
+ p = xmalloc (size);
+ memset (p, 0, size);
+
+ return p;
+}
+
+void *
+grub_list_reverse (grub_list_t head)
+{
+ grub_list_t prev;
+
+ prev = 0;
+ while (head)
+ {
+ grub_list_t temp;
+
+ temp = head->next;
+ head->next = prev;
+ prev = head;
+ head = temp;
+ }
+
+ return prev;
+}
+
char *
grub_util_get_path (const char *dir, const char *file)
{
@@ -251,6 +281,58 @@ grub_util_write_image (const char *img, size_t size, FILE *out)
grub_util_error ("write failed");
}
+char *
+grub_util_get_module_name (const char *str)
+{
+ char *base;
+ char *ext;
+
+ base = strrchr (str, '/');
+ if (! base)
+ base = (char *) str;
+ else
+ base++;
+
+ ext = strrchr (base, '.');
+ if (ext && strcmp (ext, ".mod") == 0)
+ {
+ char *name;
+
+ name = xmalloc (ext - base + 1);
+ memcpy (name, base, ext - base);
+ name[ext - base] = '\0';
+ return name;
+ }
+
+ return xstrdup (base);
+}
+
+char *
+grub_util_get_module_path (const char *prefix, const char *str)
+{
+ char *dir;
+ char *base;
+ char *ext;
+ char *ret;
+
+ ext = strrchr (str, '.');
+ if (ext && strcmp (ext, ".mod") == 0)
+ base = xstrdup (str);
+ else
+ {
+ base = xmalloc (strlen (str) + 4 + 1);
+ sprintf (base, "%s.mod", str);
+ }
+
+ dir = strchr (str, '/');
+ if (dir)
+ return base;
+
+ ret = grub_util_get_path (prefix, base);
+ free (base);
+ return ret;
+}
+
void *
grub_malloc (grub_size_t size)
{
diff --git a/util/obj.c b/util/obj.c
new file mode 100644
index 0000000..c83edac
--- /dev/null
+++ b/util/obj.c
@@ -0,0 +1,634 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+grub_obj_reverse (struct grub_util_obj *obj)
+{
+ obj->segments = grub_list_reverse (GRUB_AS_LIST (obj->segments));
+ obj->symbols = grub_list_reverse (GRUB_AS_LIST (obj->symbols));
+ obj->relocs = grub_list_reverse (GRUB_AS_LIST (obj->relocs));
+}
+
+void
+grub_obj_sort_segments (struct grub_util_obj *obj)
+{
+ grub_list_t n;
+ int i;
+
+ n = 0;
+ for (i = GRUB_OBJ_SEG_TEXT; i <= GRUB_OBJ_SEG_BSS; i++)
+ {
+ struct grub_util_obj_segment **p, *q;
+
+ for (p = &obj->segments, q = *p; q; q = *p)
+ if (q->segment.type == i)
+ {
+ *p = q->next;
+ grub_list_push (&n, GRUB_AS_LIST (q));
+ }
+ else
+ p = &(q->next);
+ }
+
+ obj->segments = grub_list_reverse (n);
+}
+
+static int
+check_merge (struct grub_util_obj_segment *s1,
+ struct grub_util_obj_segment *s2,
+ int merge)
+{
+ if (! s2)
+ return 0;
+
+ switch (merge)
+ {
+ case GRUB_OBJ_MERGE_NONE:
+ return (s1 == s2);
+
+ case GRUB_OBJ_MERGE_SAME:
+ return (s1->segment.type == s2->segment.type);
+
+ case GRUB_OBJ_MERGE_ALL:
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+grub_obj_merge_segments (struct grub_util_obj *obj, int merge)
+{
+ struct grub_util_obj_segment *p, *first;
+ grub_uint32_t offset;
+
+ if (merge == GRUB_OBJ_MERGE_NONE)
+ return;
+
+ first = 0;
+ offset = 0;
+ p = obj->segments;
+ while (p)
+ {
+ if (check_merge (p, first, merge))
+ {
+ grub_uint32_t mask;
+
+ if (p->segment.align > first->segment.align)
+ first->segment.align = p->segment.align;
+
+ mask = p->segment.align - 1;
+ offset = (offset + mask) & ~mask;
+ p->segment.offset = offset;
+ offset += p->segment.size;
+ }
+ else
+ {
+ first = p;
+ offset = p->segment.size;
+ }
+
+ p = p->next;
+ }
+}
+
+void
+grub_obj_reloc_symbols (struct grub_util_obj *obj, int merge)
+{
+ struct grub_util_obj_reloc *rel;
+
+ for (rel = obj->relocs; rel; rel = rel->next)
+ {
+ char *addr;
+
+ if (! rel->segment)
+ continue;
+
+ if (! rel->segment->data)
+ grub_util_error ("can\'t relocate in .bss segment");
+
+ addr = rel->segment->data + rel->reloc.offset;
+
+ if (! rel->symbol_segment)
+ {
+ struct grub_util_obj_symbol *sym;
+
+ sym = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->symbols),
+ rel->symbol_name);
+ if (sym)
+ {
+ if (rel->reloc.type & GRUB_OBJ_REL_64BIT)
+ *((grub_uint64_t *) addr) += sym->symbol.offset;
+ else
+ *((grub_uint32_t *) addr) += sym->symbol.offset;
+
+ rel->symbol_segment = sym->segment;
+ }
+ }
+
+ if (rel->symbol_segment)
+ {
+ grub_uint64_t delta;
+
+ delta = rel->symbol_segment->segment.offset;
+ if ((check_merge (rel->segment, rel->symbol_segment, merge)) &&
+ (rel->reloc.type & GRUB_OBJ_REL_ISREL))
+ {
+ delta -= rel->segment->segment.offset + rel->reloc.offset;
+ rel->segment = 0;
+ }
+
+ if (rel->reloc.type & GRUB_OBJ_REL_64BIT)
+ *((grub_uint64_t *) addr) += delta;
+ else
+ *((grub_uint32_t *) addr) += delta;
+ }
+ }
+}
+
+struct grub_strtab
+{
+ struct grub_strtab *next;
+ char *name;
+ int len;
+};
+typedef struct grub_strtab *grub_strtab_t;
+
+static int
+grub_strtab_find (grub_strtab_t head, char *name)
+{
+ int index = 1;
+ int len = strlen (name);
+
+ auto int scan_str (grub_strtab_t item);
+ int scan_str (grub_strtab_t item)
+ {
+ if (item->len >= len)
+ {
+ int ofs;
+
+ ofs = item->len - len;
+ if (! strcmp (item->name + ofs, name))
+ {
+ index += ofs;
+ return 1;
+ }
+ }
+
+ index += item->len + 1;
+ return 0;
+ }
+
+ if (! grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) scan_str))
+ index = -index;
+
+ return index;
+}
+
+static void
+grub_strtab_insert (grub_strtab_t *head, char *name)
+{
+ auto int test (grub_strtab_t new_item, grub_strtab_t item);
+ int test (grub_strtab_t new_item, grub_strtab_t item)
+ {
+ return (strcmp (new_item->name, item->name) < 0);
+ }
+
+ grub_strtab_t nitem;
+
+ if (grub_strtab_find (*head, name) > 0)
+ return;
+
+ nitem = xmalloc (sizeof (*nitem));
+ nitem->name = name;
+ nitem->len = strlen (name);
+
+ grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (nitem),
+ (grub_list_test_t) test);
+}
+
+#define GRUB_OBJ_HEADER_MAX 0xffff
+
+void
+grub_obj_save (struct grub_util_obj *obj, char *mod_name, FILE *fp)
+{
+ char *buf, *p;
+ struct grub_obj_header *hdr;
+ struct grub_util_obj_segment *seg;
+ struct grub_util_obj_symbol *sym;
+ struct grub_util_obj_reloc *rel;
+ int idx;
+ grub_uint32_t offset, raw_size;
+ grub_strtab_t strtab;
+ int strtab_size;
+ int mod_name_len = strlen (mod_name);
+ char mod_init[mod_name_len + 11];
+ char mod_fini[mod_name_len + 11];
+
+ if ((! obj->segments) || (obj->segments->segment.offset))
+ grub_util_error ("invalid segment");
+
+ buf = xmalloc (GRUB_OBJ_HEADER_MAX);
+ hdr = (struct grub_obj_header *) buf;
+
+ hdr->magic = GRUB_OBJ_HEADER_MAGIC;
+ hdr->version = GRUB_OBJ_HEADER_VERSION;
+ hdr->init_func = GRUB_OBJ_FUNC_NONE;
+ hdr->fini_func = GRUB_OBJ_FUNC_NONE;
+
+ idx = 0;
+ offset = 0;
+ raw_size = 0;
+ hdr->segments[0].offset = 0;
+ seg = obj->segments;
+ while (seg)
+ {
+ struct grub_util_obj_segment *cur;
+ grub_uint32_t mask;
+ int is_last;
+
+ cur = seg;
+ seg = seg->next;
+
+ if (! cur->segment.offset)
+ {
+ if (idx >= GRUB_OBJ_SEGMENT_END)
+ grub_util_error ("too many segments");
+
+ hdr->segments[idx].type = cur->segment.type;
+ hdr->segments[idx].align = cur->segment.align;
+ hdr->segments[idx].size = 0;
+ raw_size = 0;
+ }
+
+ cur->index = idx;
+ mask = cur->segment.align - 1;
+ hdr->segments[idx].size = (hdr->segments[idx].size + mask) & ~mask;
+ hdr->segments[idx].size += cur->segment.size;
+
+ is_last = ((! seg) || (! seg->segment.offset));
+
+ if (cur->segment.type != GRUB_OBJ_SEG_BSS)
+ {
+ raw_size = (raw_size + mask) & ~mask;
+ raw_size += (is_last) ? cur->raw_size : cur->segment.size;
+ }
+
+ if (is_last)
+ {
+ offset += raw_size;
+ idx++;
+ hdr->segments[idx].offset = offset;
+ }
+ }
+
+ hdr->segments[idx].type = GRUB_OBJ_SEGMENT_END;
+ p = ((char *) &hdr->segments[idx]) + 5;
+
+ sprintf (mod_init, "grub_%s_init", mod_name);
+ sprintf (mod_fini, "grub_%s_fini", mod_name);
+
+ strtab = 0;
+ sym = obj->symbols;
+ while (sym)
+ {
+ if (sym->segment)
+ {
+ if (! strcmp (sym->name, "grub_mod_init"))
+ {
+ if ((sym->symbol.offset >= GRUB_OBJ_HEADER_MAX) ||
+ (sym->segment->index))
+ grub_util_error ("init function too far");
+
+ hdr->init_func = sym->symbol.offset;
+ sym->segment = 0;
+ }
+ else if (! strcmp (sym->name, "grub_mod_fini"))
+ {
+ if ((sym->symbol.offset >= GRUB_OBJ_HEADER_MAX) ||
+ (sym->segment->index))
+ grub_util_error ("fini function too far");
+
+ hdr->fini_func = sym->symbol.offset;
+ sym->segment = 0;
+ }
+ else if ((! strcmp (sym->name, mod_init)) ||
+ (! strcmp (sym->name, mod_fini)))
+ {
+ sym->segment = 0;
+ }
+ else
+ grub_strtab_insert (&strtab, sym->name);
+ }
+ sym = sym->next;
+ }
+
+ rel = obj->relocs;
+ while (rel)
+ {
+ if ((rel->segment) && (! rel->symbol_segment))
+ grub_strtab_insert (&strtab, rel->symbol_name);
+ rel = rel->next;
+ }
+
+ strtab_size = - grub_strtab_find (strtab, "?");
+ if (strtab_size >= GRUB_OBJ_HEADER_MAX)
+ grub_util_error ("string table too large");
+
+ hdr->symbol_table = (p - buf);
+ sym = obj->symbols;
+ while (sym)
+ {
+ if (sym->segment)
+ {
+ struct grub_obj_symbol *s;
+
+ s = (struct grub_obj_symbol *) p;
+ p += sizeof (struct grub_obj_symbol);
+ if (p - buf >= GRUB_OBJ_HEADER_MAX)
+ grub_util_error ("symbol table too large");
+
+ s->segment = sym->segment->index;
+ s->name = grub_strtab_find (strtab, sym->name);
+ s->offset = sym->symbol.offset + sym->segment->segment.offset;
+ }
+ sym = sym->next;
+ }
+ *(p++) = GRUB_OBJ_SEGMENT_END;
+ if (p - buf >= GRUB_OBJ_HEADER_MAX)
+ grub_util_error ("symbol table too large");
+
+ hdr->reloc_table = (p - buf);
+ rel = obj->relocs;
+ while (rel)
+ {
+ if (rel->segment)
+ {
+ struct grub_obj_reloc_extern *r;
+
+ r = (struct grub_obj_reloc_extern *) p;
+ p += ((rel->symbol_segment) ? sizeof (struct grub_obj_reloc) :
+ sizeof (struct grub_obj_reloc_extern));
+ if (p - buf >= GRUB_OBJ_HEADER_MAX)
+ grub_util_error ("symbol table too large");
+
+ r->segment = rel->segment->index;
+ r->type = rel->reloc.type;
+ r->offset = rel->reloc.offset + rel->segment->segment.offset;
+ if (rel->symbol_segment)
+ {
+ r->symbol_segment = rel->symbol_segment->index;
+ }
+ else
+ {
+ r->symbol_segment = GRUB_OBJ_SEGMENT_END;
+ r->symbol_name = grub_strtab_find (strtab, rel->symbol_name);
+ }
+ }
+ rel = rel->next;
+ }
+ *(p++) = GRUB_OBJ_SEGMENT_END;
+ if (p - buf >= GRUB_OBJ_HEADER_MAX)
+ grub_util_error ("symbol table too large");
+
+ hdr->string_table = (p - buf);
+ offset = strtab_size + hdr->string_table;
+ idx = 0;
+ while (1)
+ {
+ hdr->segments[idx].offset += offset;
+ if (hdr->segments[idx].type == GRUB_OBJ_SEGMENT_END)
+ break;
+ idx++;
+ }
+ hdr->mod_deps = hdr->segments[idx].offset;
+
+ grub_util_write_image (buf, hdr->string_table, fp);
+ free (buf);
+
+ buf = xmalloc (strtab_size);
+ p = buf;
+ *(p++) = 0;
+
+ while (strtab)
+ {
+ grub_strtab_t cur;
+
+ cur = strtab;
+ strtab = strtab->next;
+
+ strcpy (p, cur->name);
+ p += cur->len + 1;
+ free (cur);
+ }
+
+ grub_util_write_image (buf, strtab_size, fp);
+ free (buf);
+
+ buf = xmalloc_zero (256);
+
+ seg = obj->segments;
+ raw_size = 0;
+ while (seg)
+ {
+ struct grub_util_obj_segment *cur;
+
+ cur = seg;
+ seg = seg->next;
+
+ if (! cur->segment.offset)
+ raw_size = 0;
+
+ if (cur->segment.type != GRUB_OBJ_SEG_BSS)
+ {
+ grub_uint32_t mask, size;
+ int is_last;
+
+ mask = cur->segment.align - 1;
+ size = (raw_size + mask) & ~mask;
+ if (size != raw_size)
+ {
+ if (size - raw_size > 256)
+ grub_util_error ("alignment too large");
+
+ grub_util_write_image (buf, size - raw_size, fp);
+ }
+
+ raw_size = size;
+ is_last = ((! seg) || (! seg->segment.offset));
+ size = (is_last) ? cur->raw_size : cur->segment.size;
+ grub_util_write_image (cur->data, size, fp);
+ raw_size += size;
+ }
+ else
+ break;
+ }
+
+ strcpy (buf, mod_name);
+ grub_util_write_image (buf, mod_name_len + 2, fp);
+ free (buf);
+}
+
+struct grub_util_obj *
+grub_obj_load (char *image, int size, int load_data)
+{
+ struct grub_util_obj *obj;
+ struct grub_obj_header *hdr;
+ struct grub_obj_symbol *sym;
+ struct grub_obj_reloc_extern *rel;
+ char *strtab;
+ struct grub_util_obj_segment **segments;
+ int i;
+
+ hdr = (struct grub_obj_header *) image;
+
+ if ((size <= (int) sizeof (*hdr)) || (hdr->magic != GRUB_OBJ_HEADER_MAGIC))
+ grub_util_error ("invalid module file");
+
+ if (hdr->version != GRUB_OBJ_HEADER_VERSION)
+ grub_util_error ("version number not match");
+
+ obj = xmalloc_zero (sizeof (*obj));
+ segments = xmalloc_zero (256 * sizeof (segments[0]));
+
+ for (i = 0; hdr->segments[i].type != GRUB_OBJ_SEGMENT_END; i++)
+ {
+ struct grub_util_obj_segment *p;
+
+ p = xmalloc_zero (sizeof (*p));
+ p->segment.type = hdr->segments[i].type;
+ p->segment.align = hdr->segments[i].align;
+ p->segment.size = hdr->segments[i].size;
+ p->file_off = hdr->segments[i].offset;
+ p->raw_size = hdr->segments[i + 1].offset - p->file_off;
+ p->index = i;
+
+ if ((p->raw_size) && (load_data))
+ {
+ p->data = xmalloc_zero (p->segment.size);
+ memcpy (p->data, image + p->file_off, p->raw_size);
+ }
+
+ segments[i] = p;
+ grub_list_push (GRUB_AS_LIST_P (&obj->segments), GRUB_AS_LIST (p));
+ }
+
+ obj->mod_attr = hdr->segments[i].offset;
+ obj->mod_deps = hdr->mod_deps;
+
+ strtab = image + hdr->string_table;
+ for (sym = (struct grub_obj_symbol *) (image + hdr->symbol_table);
+ sym->segment != GRUB_OBJ_SEGMENT_END; sym++)
+ {
+ struct grub_util_obj_symbol *p;
+
+ p = xmalloc_zero (sizeof (*p));
+ p->name = xstrdup (strtab + sym->name);
+ p->segment = segments[sym->segment];
+ p->symbol.offset = sym->offset;
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (p));
+ }
+
+ for (rel = (struct grub_obj_reloc_extern *) (image + hdr->reloc_table);
+ rel->segment != GRUB_OBJ_SEGMENT_END;)
+ {
+ struct grub_util_obj_reloc *p;
+
+ p = xmalloc_zero (sizeof (*p));
+ p->segment = segments[rel->segment];
+ p->reloc.type = rel->type;
+ p->reloc.offset = rel->offset;
+ if (rel->symbol_segment == GRUB_OBJ_SEGMENT_END)
+ {
+ p->symbol_name = xstrdup (strtab + rel->symbol_name);
+ rel++;
+ }
+ else
+ {
+ p->symbol_segment = segments[rel->symbol_segment];
+ rel = (struct grub_obj_reloc_extern *)
+ ((char *) rel + sizeof (struct grub_obj_reloc));
+ }
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->relocs), GRUB_AS_LIST (p));
+ }
+
+ free (segments);
+ grub_obj_reverse (obj);
+ return obj;
+}
+
+void
+grub_obj_free (struct grub_util_obj *obj)
+{
+ struct grub_util_obj_segment *seg;
+ struct grub_util_obj_symbol *sym;
+ struct grub_util_obj_reloc *rel;
+
+ seg = obj->segments;
+ while (seg)
+ {
+ struct grub_util_obj_segment *p;
+
+ p = seg;
+ seg = seg->next;
+
+ if (p->data)
+ free (p->data);
+
+ free (p);
+ }
+
+ sym = obj->symbols;
+ while (sym)
+ {
+ struct grub_util_obj_symbol *p;
+
+ p = sym;
+ sym = sym->next;
+
+ if (p->name)
+ free (p->name);
+
+ free (p);
+ }
+
+ rel = obj->relocs;
+ while (sym)
+ {
+ struct grub_util_obj_reloc *p;
+
+ p = rel;
+ rel = rel->next;
+
+ if (p->symbol_name)
+ free (p->symbol_name);
+
+ free (p);
+ }
+}
diff --git a/util/obj_dump.c b/util/obj_dump.c
new file mode 100644
index 0000000..4bfab89
--- /dev/null
+++ b/util/obj_dump.c
@@ -0,0 +1,140 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static char *
+get_segment_name (int type)
+{
+ switch (type)
+ {
+ case GRUB_OBJ_SEG_TEXT:
+ return ".text";
+
+ case GRUB_OBJ_SEG_DATA:
+ return ".data";
+
+ case GRUB_OBJ_SEG_RDATA:
+ return ".rdata";
+
+ case GRUB_OBJ_SEG_BSS:
+ return ".bss";
+ }
+
+ return "unknown";
+}
+
+static char *
+get_reloc_type (int type)
+{
+ switch (type)
+ {
+ case GRUB_OBJ_REL_DIR32:
+ return "dir32";
+
+ case GRUB_OBJ_REL_REL32:
+ return "rel32";
+
+ case GRUB_OBJ_REL_DIR64:
+ return "dir64";
+
+ case GRUB_OBJ_REL_REL64:
+ return "rel64";
+ }
+
+ return "unknown";
+}
+
+static int
+dump_segments_hook (struct grub_util_obj_segment *obj)
+{
+ printf ("%-10s%08x %08x %08x %08x %d\n",
+ get_segment_name (obj->segment.type),
+ obj->segment.offset, obj->segment.size, obj->raw_size,
+ obj->file_off, obj->segment.align);
+
+ return 0;
+}
+
+void
+grub_obj_dump_segments (struct grub_util_obj *obj)
+{
+ printf ("Segments:\n"
+ "Segment Offset Size Raw Size File Off Align\n");
+ grub_list_iterate (GRUB_AS_LIST (obj->segments),
+ (grub_list_hook_t) dump_segments_hook);
+}
+
+static int
+dump_symbols_hook (struct grub_util_obj_symbol *obj)
+{
+ if (obj->segment)
+ printf ("%-10s%08x %s\n",
+ get_segment_name (obj->segment->segment.type),
+ obj->symbol.offset + obj->segment->segment.offset, obj->name);
+
+ return 0;
+}
+
+void
+grub_obj_dump_symbols (struct grub_util_obj *obj)
+{
+ printf ("Symbols:\n"
+ "Segment Offset Name\n");
+ grub_list_iterate (GRUB_AS_LIST (obj->symbols),
+ (grub_list_hook_t) dump_symbols_hook);
+}
+
+static int
+dump_reloc_hook (struct grub_util_obj_reloc *obj)
+{
+ if (obj->segment)
+ {
+ grub_uint32_t value;
+
+ if (obj->segment->data)
+ value = *((grub_uint32_t *) (obj->segment->data + obj->reloc.offset));
+ else
+ value = 0;
+
+ printf ("%-10s%08x %08x %-10s%s\n",
+ get_segment_name (obj->segment->segment.type),
+ obj->reloc.offset + obj->segment->segment.offset, value,
+ get_reloc_type (obj->reloc.type),
+ ((! obj->symbol_segment) ? obj->symbol_name :
+ get_segment_name (obj->symbol_segment->segment.type)));
+ }
+
+ return 0;
+}
+
+void
+grub_obj_dump_relocs (struct grub_util_obj *obj)
+{
+ printf ("Relocs:\n"
+ "Segment Offset Value Type Name\n");
+ grub_list_iterate (GRUB_AS_LIST (obj->relocs),
+ (grub_list_hook_t) dump_reloc_hook);
+}
diff --git a/util/obj_elf.c b/util/obj_elf.c
new file mode 100644
index 0000000..3695079
--- /dev/null
+++ b/util/obj_elf.c
@@ -0,0 +1,360 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+#include <grub/elf.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#if GRUB_TARGET_SIZEOF_VOID_P == 4
+
+#define grub_target_to_host grub_target_to_host32
+#define grub_host_to_target grub_host_to_target32
+
+#elif GRUB_TARGET_SIZEOF_VOID_P == 8
+
+#define grub_target_to_host grub_target_to_host64
+#define grub_host_to_target grub_host_to_target64
+
+#endif
+
+static int
+check_elf_header (Elf_Ehdr *e, size_t size)
+{
+ if (size < sizeof (*e)
+ || e->e_ident[EI_MAG0] != ELFMAG0
+ || e->e_ident[EI_MAG1] != ELFMAG1
+ || e->e_ident[EI_MAG2] != ELFMAG2
+ || e->e_ident[EI_MAG3] != ELFMAG3
+ || e->e_ident[EI_VERSION] != EV_CURRENT
+ || e->e_version != EV_CURRENT)
+ return 0;
+
+ return 1;
+}
+
+/* Return the symbol table section, if any. */
+static Elf_Shdr *
+find_symtab_section (Elf_Shdr *sections,
+ Elf_Half section_entsize, Elf_Half num_sections)
+{
+ int i;
+ Elf_Shdr *s;
+
+ for (i = 0, s = sections;
+ i < num_sections;
+ i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+ if (s->sh_type == grub_cpu_to_le32 (SHT_SYMTAB))
+ return s;
+
+ return 0;
+}
+
+static void
+add_segments (struct grub_util_obj *obj,
+ struct grub_util_obj_segment **segments,
+ char *image,
+ Elf_Shdr *sections, int section_entsize, int num_sections)
+{
+ Elf_Shdr *s;
+ int i;
+
+ for (i = 0, s = sections;
+ i < num_sections;
+ i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+ {
+ int type;
+
+ if ((s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC))
+ == grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC))
+ type = GRUB_OBJ_SEG_TEXT;
+ else if (s->sh_flags & grub_cpu_to_le32 (SHF_ALLOC)
+ && ! (s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR)))
+ {
+ if (! (s->sh_flags & grub_cpu_to_le32 (SHF_WRITE)))
+ type = GRUB_OBJ_SEG_RDATA;
+ else if (s->sh_type == grub_cpu_to_le32 (SHT_NOBITS))
+ type = GRUB_OBJ_SEG_BSS;
+ else
+ type = GRUB_OBJ_SEG_DATA;
+ }
+ else
+ type = 0;
+
+
+ if ((type) && ((type == GRUB_OBJ_SEG_BSS) || (s->sh_size)))
+ {
+ struct grub_util_obj_segment *p;
+
+ p = xmalloc_zero (sizeof (*p));
+ p->segment.type = type;
+ p->segment.align = grub_le_to_cpu32 (s->sh_addralign);
+ p->segment.size = grub_le_to_cpu32 (s->sh_size);
+ segments[i] = p;
+
+ if (type == GRUB_OBJ_SEG_BSS)
+ {
+ p->raw_size = p->segment.size;
+ if (segments[0])
+ grub_util_error ("mutiple .bss segment");
+ segments[0] = p;
+ }
+ else
+ {
+ p->raw_size = p->segment.size;
+ p->data = xmalloc (p->raw_size);
+ memcpy (p->data, image + grub_le_to_cpu32 (s->sh_offset),
+ p->raw_size);
+ segments[i] = p;
+ grub_list_push (GRUB_AS_LIST_P (&obj->segments),
+ GRUB_AS_LIST (p));
+
+ }
+ }
+ }
+
+ if (! segments[0])
+ grub_util_error ("no .bss segment");
+}
+
+static void
+add_symbols (struct grub_util_obj *obj,
+ struct grub_util_obj_segment **segments,
+ char *image,
+ Elf_Shdr *sections, int section_entsize, int num_sections)
+{
+ int i;
+ Elf_Shdr *symtab_section, *str_sec;
+ Elf_Sym *sym;
+ int num_syms, sym_size;
+ char *strtab;
+
+ symtab_section = find_symtab_section (sections,
+ section_entsize, num_sections);
+ sym = (Elf_Sym *) (image + grub_target_to_host (symtab_section->sh_offset));
+ sym_size = grub_target_to_host32 (symtab_section->sh_entsize);
+ num_syms = grub_target_to_host32 (symtab_section->sh_size) / sym_size;
+ str_sec = (Elf_Shdr *) ((char *) sections
+ + (grub_target_to_host32 (symtab_section->sh_link)
+ * section_entsize));
+ strtab = image + grub_target_to_host32 (str_sec->sh_offset);
+
+ for (i = 0; i < num_syms;
+ i++, sym = (Elf_Sym *) ((char *) sym + sym_size))
+ {
+ Elf_Section index;
+ char *name;
+
+ name = strtab + grub_target_to_host32 (sym->st_name);
+
+ if ((ELF_ST_BIND (sym->st_info) == STB_LOCAL) &&
+ (strcmp (name, "grub_mod_init")) &&
+ (strcmp (name, "grub_mod_fini")))
+ continue;
+
+ index = grub_target_to_host16 (sym->st_shndx);
+
+ if (index == STN_UNDEF)
+ continue;
+
+ if (index == STN_COMMON)
+ {
+ if (! sym->st_value)
+ continue;
+ index = 0;
+ }
+
+ if ((index < num_sections) && (segments[index]))
+ {
+ struct grub_util_obj_symbol *p;
+
+ p = xmalloc_zero (sizeof (*p));
+ p->name = xstrdup (name);
+ p->segment = segments[index];
+ if (! index)
+ {
+ p->symbol.offset = p->segment->segment.size;
+ p->segment->segment.size += grub_target_to_host (sym->st_value);
+ }
+ else
+ p->symbol.offset = grub_target_to_host (sym->st_value);
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->symbols),
+ GRUB_AS_LIST (p));
+ }
+ }
+}
+
+static void
+add_relocs (struct grub_util_obj *obj,
+ struct grub_util_obj_segment **segments,
+ char *image,
+ Elf_Shdr *sections, int section_entsize, int num_sections)
+{
+ int i;
+ Elf_Shdr *s;
+
+ for (i = 0, s = sections;
+ i < num_sections;
+ i++, s = (Elf_Shdr *) ((char *) s + section_entsize))
+ if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) ||
+ (s->sh_type == grub_cpu_to_le32 (SHT_RELA)))
+ {
+ Elf_Rela *r;
+ Elf_Shdr *sym_sec, *str_sec;
+ int sym_size;
+ char *strtab;
+ Elf_Word r_size, num_rs, j;
+ Elf_Word target_index;
+
+ sym_sec = (Elf_Shdr *) ((char *) sections
+ + (grub_target_to_host32 (s->sh_link)
+ * section_entsize));
+ sym_size = grub_target_to_host32 (sym_sec->sh_entsize);
+
+ str_sec = (Elf_Shdr *) ((char *) sections
+ + (grub_target_to_host32 (sym_sec->sh_link)
+ * section_entsize));
+ strtab = image + grub_target_to_host32 (str_sec->sh_offset);
+
+ target_index = grub_target_to_host32 (s->sh_info);
+ if (! segments[target_index])
+ continue;
+
+ r_size = grub_target_to_host32 (s->sh_entsize);
+ num_rs = grub_target_to_host32 (s->sh_size) / r_size;
+
+ r = (Elf_Rela *) (image + grub_target_to_host32 (s->sh_offset));
+ for (j = 0;
+ j < num_rs;
+ j++, r = (Elf_Rela *) ((char *) r + r_size))
+ {
+ struct grub_util_obj_reloc *p;
+ Elf_Addr info, offset;
+ Elf_Sym *sym;
+ int sym_idx;
+ char *addr;
+ int type;
+
+ offset = grub_target_to_host (r->r_offset);
+ if (! segments[target_index]->data)
+ grub_util_error ("can\'t relocate in .bss segment");
+
+ addr = segments[target_index]->data + offset;
+ info = grub_target_to_host (r->r_info);
+
+ type = -1;
+ switch (ELF_R_TYPE (info))
+ {
+ case R_386_NONE:
+ break;
+
+ case R_386_32:
+ type = GRUB_OBJ_REL_DIR32;
+ break;
+
+ case R_386_PC32:
+ type = GRUB_OBJ_REL_REL32;
+ break;
+
+ default:
+ grub_util_error ("unknown relocation type %d",
+ ELF_R_TYPE (info));
+ }
+
+ if (type < 0)
+ continue;
+
+ if ((grub_target_to_host32 (s->sh_type) == SHT_RELA) &&
+ (r->r_addend))
+ {
+ if (type & GRUB_OBJ_REL_64BIT)
+ *((grub_uint64_t *) addr) += r->r_addend;
+ else
+ *((grub_uint32_t *) addr) += r->r_addend;
+ }
+
+ p = xmalloc_zero (sizeof (*p));
+ p->segment = segments[target_index];
+ p->reloc.type = type;
+ p->reloc.offset = offset;
+
+ sym = (Elf_Sym *) (image
+ + grub_target_to_host32 (sym_sec->sh_offset)
+ + (ELF_R_SYM (info) * sym_size));
+ sym_idx = grub_target_to_host16 (sym->st_shndx);
+ if (sym_idx == STN_ABS)
+ grub_util_error ("can\'t relocate absolute symbol");
+
+ if ((sym_idx != STN_UNDEF) && (sym_idx != STN_COMMON))
+ {
+ if (! segments[sym_idx])
+ grub_util_error ("no symbol segment");
+
+ p->symbol_segment = segments[sym_idx];
+ }
+ p->symbol_name = xstrdup (strtab +
+ grub_target_to_host32 (sym->st_name));
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->relocs),
+ GRUB_AS_LIST (p));
+ }
+ }
+}
+
+int
+elf_add_file (struct grub_util_obj *obj, char *image, int size)
+{
+ Elf_Ehdr *e;
+ Elf_Shdr *sections;
+ Elf_Off section_offset;
+ Elf_Half section_entsize;
+ Elf_Half num_sections;
+ struct grub_util_obj_segment **segments;
+
+ e = (Elf_Ehdr *) image;
+ if (! check_elf_header (e, size))
+ return 0;
+
+ section_offset = grub_target_to_host (e->e_shoff);
+ section_entsize = grub_target_to_host16 (e->e_shentsize);
+ num_sections = grub_target_to_host16 (e->e_shnum);
+
+ if (size < (int) (section_offset + section_entsize * num_sections))
+ grub_util_error ("invalid ELF format");
+
+ sections = (Elf_Shdr *) (image + section_offset);
+ segments = xmalloc_zero (num_sections * sizeof (segments[0]));
+ add_segments (obj, segments, image, sections, section_entsize, num_sections);
+ add_symbols (obj, segments, image, sections, section_entsize, num_sections);
+ add_relocs (obj, segments, image, sections, section_entsize, num_sections);
+
+ if (segments[0]->segment.size)
+ grub_list_push (GRUB_AS_LIST_P (&obj->segments),
+ GRUB_AS_LIST (segments[0]));
+ else
+ free (segments[0]);
+
+ free (segments);
+ return 1;
+}
diff --git a/util/obj_pe.c b/util/obj_pe.c
new file mode 100644
index 0000000..e168fb1
--- /dev/null
+++ b/util/obj_pe.c
@@ -0,0 +1,272 @@
+/*
+ * GRUB -- GRand Unified Bootloader
+ * Copyright (C) 2009 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/obj.h>
+#include <grub/util/misc.h>
+#include <grub/efi/pe32.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+static void
+add_segments (struct grub_util_obj *obj,
+ struct grub_util_obj_segment **segments,
+ char *image,
+ struct grub_pe32_section_table *pe_shdr, int num_secs)
+{
+ int i;
+
+ for (i = 0; i < num_secs; i++, pe_shdr++)
+ {
+ int type;
+
+ if (! strcmp (pe_shdr->name, ".text"))
+ type = GRUB_OBJ_SEG_TEXT;
+ else if (! strcmp (pe_shdr->name, ".data"))
+ type = GRUB_OBJ_SEG_DATA;
+ else if (! strcmp (pe_shdr->name, ".rdata"))
+ type = GRUB_OBJ_SEG_RDATA;
+ else if (! strcmp (pe_shdr->name, ".bss"))
+ type = GRUB_OBJ_SEG_BSS;
+ else
+ type = 0;
+
+ if ((type) && ((type == GRUB_OBJ_SEG_BSS) || (pe_shdr->raw_data_size)))
+ {
+ struct grub_util_obj_segment *p;
+
+ p = xmalloc_zero (sizeof (*p));
+ p->segment.type = type;
+ p->segment.align = 1 << (((pe_shdr->characteristics >>
+ GRUB_PE32_SCN_ALIGN_SHIFT) &
+ GRUB_PE32_SCN_ALIGN_MASK) - 1);
+ p->segment.size = pe_shdr->raw_data_size;
+ segments[i + 1] = p;
+
+ if (type == GRUB_OBJ_SEG_BSS)
+ {
+ p->raw_size = p->segment.size;
+ if (segments[0])
+ grub_util_error ("mutiple .bss segment");
+ segments[0] = p;
+ }
+ else
+ {
+ p->raw_size = p->segment.size;
+ p->data = xmalloc (pe_shdr->raw_data_size);
+ memcpy (p->data, image + pe_shdr->raw_data_offset,
+ pe_shdr->raw_data_size);
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->segments),
+ GRUB_AS_LIST (p));
+ }
+ }
+ }
+
+ if (! segments[0])
+ grub_util_error ("no .bss segment");
+}
+
+static char *
+get_symbol_name (struct grub_pe32_symbol *pe_sym, char *pe_strtab)
+{
+ char short_name[9];
+ char *name;
+
+ if (pe_sym->long_name[0])
+ {
+ strncpy (short_name, pe_sym->short_name, 8);
+ short_name[8] = 0;
+ name = short_name;
+ }
+ else
+ name = pe_strtab + pe_sym->long_name[1];
+
+ if (*name == '_')
+ name++;
+
+ return xstrdup (name);
+}
+
+static void
+add_symbols (struct grub_util_obj *obj,
+ struct grub_util_obj_segment **segments,
+ struct grub_pe32_symbol *pe_symtab, int num_syms,
+ char *pe_strtab)
+{
+ int i;
+
+ for (i = 0; i < num_syms;
+ i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1)
+ {
+ struct grub_util_obj_symbol *p;
+ char *name;
+
+ name = get_symbol_name (pe_symtab, pe_strtab);
+
+ if ((pe_symtab->section > num_syms) ||
+ (! segments[pe_symtab->section]) ||
+ ((pe_symtab->storage_class != GRUB_PE32_SYM_CLASS_EXTERNAL) &&
+ (strcmp (name, "grub_mod_init")) &&
+ (strcmp (name, "grub_mod_fini"))))
+ {
+ free (name);
+ continue;
+ }
+
+ if ((! pe_symtab->section) && (! pe_symtab->value))
+ {
+ free (name);
+ continue;
+ }
+
+ p = xmalloc_zero (sizeof (*p));
+ p->name = name;
+ p->segment = segments[pe_symtab->section];
+
+ if (! pe_symtab->section)
+ {
+ p->symbol.offset = p->segment->segment.size;
+ p->segment->segment.size += pe_symtab->value;
+ }
+ else
+ p->symbol.offset = pe_symtab->value;
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (p));
+ }
+}
+
+static void
+add_relocs (struct grub_util_obj *obj,
+ struct grub_util_obj_segment **segments,
+ char *image,
+ struct grub_pe32_section_table *pe_sec, int num_secs,
+ struct grub_pe32_symbol *pe_symtab, int num_syms,
+ char *pe_strtab)
+{
+ int i;
+
+ for (i = 0; i < num_secs; i++, pe_sec++)
+ {
+ struct grub_pe32_reloc *pe_rel;
+ int j;
+
+ if (! segments[i + 1])
+ continue;
+
+ pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset);
+ for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++)
+ {
+ struct grub_util_obj_reloc *p;
+ struct grub_pe32_symbol *pe_sym;
+ int type;
+
+ pe_sym = pe_symtab + pe_rel->symtab_index;
+
+ if (((int) pe_rel->symtab_index >= num_syms) ||
+ ((pe_sym->section) && (! segments[pe_sym->section])))
+ grub_util_error ("invalid symbol index");
+
+ if (pe_rel->type == GRUB_PE32_REL_I386_DIR32)
+ type = GRUB_OBJ_REL_DIR32;
+ else if (pe_rel->type == GRUB_PE32_REL_I386_REL32)
+ type = GRUB_OBJ_REL_REL32;
+ else
+ grub_util_error ("unknown pe relocation type %d\n", pe_rel->type);
+
+ p = xmalloc_zero (sizeof (*p));
+ p->segment = segments[i + 1];
+ p->reloc.type = type;
+ p->reloc.offset = pe_rel->offset - pe_sec->virtual_address;
+ if (pe_sym->section)
+ p->symbol_segment = segments[pe_sym->section];
+ p->symbol_name = get_symbol_name (pe_sym, pe_strtab);
+
+ if (! p->segment->data)
+ grub_util_error ("can\'t relocate in .bss segment");
+
+ if (type & GRUB_OBJ_REL_ISREL)
+ {
+ grub_uint8_t code;
+ grub_uint32_t *addr;
+
+ addr = (grub_uint32_t *) (p->segment->data + p->reloc.offset);
+ code = p->segment->data[p->reloc.offset - 1];
+ if (((code != 0xe8) && (code != 0xe9)) || (*addr))
+ grub_util_error ("invalid relocation (%x %x)", code, *addr);
+
+ if (p->reloc.type & GRUB_OBJ_REL_64BIT)
+ *((grub_uint64_t *) addr) = -4;
+ else
+ *((grub_uint32_t *) addr) = -4;
+ }
+
+ grub_list_push (GRUB_AS_LIST_P (&obj->relocs), GRUB_AS_LIST (p));
+ }
+ }
+}
+
+static int
+check_pe_header (struct grub_pe32_coff_header *c, size_t size)
+{
+ if ((size < sizeof (*c) ||
+ (grub_le_to_cpu16 (c->machine) != GRUB_PE32_MACHINE_I386)))
+ return 0;
+
+ return 1;
+}
+
+int
+pe_add_file (struct grub_util_obj *obj, char *image, int size)
+{
+ struct grub_pe32_coff_header *pe_chdr;
+ struct grub_pe32_section_table *pe_shdr;
+ struct grub_pe32_symbol *pe_symtab;
+ int num_secs, num_syms;
+ char *pe_strtab;
+ struct grub_util_obj_segment **segments;
+
+ pe_chdr = (struct grub_pe32_coff_header *) image;
+ if (! check_pe_header (pe_chdr, size))
+ return 0;
+
+ pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1);
+ num_secs = pe_chdr->num_sections;
+ segments = xmalloc_zero ((num_secs + 1) * sizeof (segments[0]));
+ add_segments (obj, segments, image, pe_shdr, num_secs);
+
+ pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset);
+ num_syms = pe_chdr->num_symbols;
+ pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols);
+
+ add_symbols (obj, segments, pe_symtab, num_syms, pe_strtab);
+ add_relocs (obj, segments, image, pe_shdr, num_secs,
+ pe_symtab, num_syms, pe_strtab);
+
+ if (segments[0]->segment.size)
+ grub_list_push (GRUB_AS_LIST_P (&obj->segments),
+ GRUB_AS_LIST (segments[0]));
+ else
+ free (segments[0]);
+
+ free (segments);
+ return 1;
+}
diff --git a/util/resolve.c b/util/resolve.c
index 8b33beb..32c9e82 100644
--- a/util/resolve.c
+++ b/util/resolve.c
@@ -126,58 +126,6 @@ read_dep_list (FILE *fp)
return dep_list;
}
-static char *
-get_module_name (const char *str)
-{
- char *base;
- char *ext;
-
- base = strrchr (str, '/');
- if (! base)
- base = (char *) str;
- else
- base++;
-
- ext = strrchr (base, '.');
- if (ext && strcmp (ext, ".mod") == 0)
- {
- char *name;
-
- name = xmalloc (ext - base + 1);
- memcpy (name, base, ext - base);
- name[ext - base] = '\0';
- return name;
- }
-
- return xstrdup (base);
-}
-
-static char *
-get_module_path (const char *prefix, const char *str)
-{
- char *dir;
- char *base;
- char *ext;
- char *ret;
-
- ext = strrchr (str, '.');
- if (ext && strcmp (ext, ".mod") == 0)
- base = xstrdup (str);
- else
- {
- base = xmalloc (strlen (str) + 4 + 1);
- sprintf (base, "%s.mod", str);
- }
-
- dir = strchr (str, '/');
- if (dir)
- return base;
-
- ret = grub_util_get_path (prefix, base);
- free (base);
- return ret;
-}
-
static void
add_module (const char *dir,
struct dep_list *dep_list,
@@ -190,7 +138,7 @@ add_module (const char *dir,
struct mod_list *mod;
struct dep_list *dep;
- mod_name = get_module_name (name);
+ mod_name = grub_util_get_module_name (name);
/* Check if the module has already been added. */
for (mod = *mod_head; mod; mod = mod->next)
@@ -218,7 +166,7 @@ add_module (const char *dir,
/* Add this path. */
path = (struct grub_util_path_list *) xmalloc (sizeof (*path));
- path->name = get_module_path (dir, name);
+ path->name = grub_util_get_module_path (dir, name);
path->next = *path_head;
*path_head = path;
}
^ permalink raw reply related [flat|nested] 25+ messages in thread* please stop this 2009-07-14 15:49 [PATCH] New object format Bean @ 2009-07-14 17:57 ` Robert Millan 2009-07-14 18:09 ` Pavel Roskin 2009-07-14 21:02 ` [PATCH] New object format Bean 2009-07-19 1:52 ` Isaac Dupree 2 siblings, 1 reply; 25+ messages in thread From: Robert Millan @ 2009-07-14 17:57 UTC (permalink / raw) To: The development of GRUB 2; +Cc: Bean, Yoshinori K. Okuji On Tue, Jul 14, 2009 at 11:49:37PM +0800, Bean wrote: > Hi, > > This patch implement a new object format, the advantages are: Hi Bean, Last time this was discussed [1], there was no consensus that we should switch to a new object format. Furthermore, Marco had some objections: http://lists.gnu.org/archive/html/grub-devel/2009-07/msg00101.html and I'm growing increasingly worried about this tendency. Just about every week we have to discuss a proposal that significantly affects core functionality, which may later be implemented and sent as a patch no matter what we have discussed, and if left unattended, merged in SVN, and afterwards we and our users have and additional burden of finding new bugs and fixing them. I agree that we have a problem due to lack of leadership, but this is not acceptable. Marco is busy right now (traveling), so please put this on hold untill he's back, then we can discuss it. Don't take me wrong, Bean I really appreciate your contribution to GRUB, but you see it as an experimentation ground, and GRUB is not a research project. PUPA was, but GRUB aims to be a stable bootloader. [1] http://lists.gnu.org/archive/html/grub-devel/2009-07/msg00098.html -- Robert Millan The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and how) you may access your data; but nobody's threatening your freedom: we still allow you to remove your data and not access it at all." ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: please stop this 2009-07-14 17:57 ` please stop this Robert Millan @ 2009-07-14 18:09 ` Pavel Roskin 2009-07-14 18:17 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Pavel Roskin @ 2009-07-14 18:09 UTC (permalink / raw) To: The development of GRUB 2 On Tue, 2009-07-14 at 19:57 +0200, Robert Millan wrote: > I agree that we have a problem due to lack of leadership, but this is not > acceptable. Marco is busy right now (traveling), so please put this on hold > untill he's back, then we can discuss it. I agree that we should not rush with such changes. However, publishing patches for discussion and testing is a good thing and should not be discouraged. -- Regards, Pavel Roskin ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: please stop this 2009-07-14 18:09 ` Pavel Roskin @ 2009-07-14 18:17 ` Bean 2009-07-16 15:23 ` Robert Millan 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-14 18:17 UTC (permalink / raw) To: The development of GRUB 2 On Wed, Jul 15, 2009 at 2:09 AM, Pavel Roskin<proski@gnu.org> wrote: > On Tue, 2009-07-14 at 19:57 +0200, Robert Millan wrote: > >> I agree that we have a problem due to lack of leadership, but this is not >> acceptable. Marco is busy right now (traveling), so please put this on hold >> untill he's back, then we can discuss it. > > I agree that we should not rush with such changes. However, publishing > patches for discussion and testing is a good thing and should not be > discouraged. Hi, Yeah, I don't mean to push it. In fact, I've created a git repository for my temporary work http://repo.or.cz/w/grub2/bean.git The new object format and library support would be committed there in case someone is interested. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: please stop this 2009-07-14 18:17 ` Bean @ 2009-07-16 15:23 ` Robert Millan 2009-07-16 16:10 ` Vladimir 'phcoder' Serbinenko 0 siblings, 1 reply; 25+ messages in thread From: Robert Millan @ 2009-07-16 15:23 UTC (permalink / raw) To: The development of GRUB 2 On Wed, Jul 15, 2009 at 02:17:39AM +0800, Bean wrote: > On Wed, Jul 15, 2009 at 2:09 AM, Pavel Roskin<proski@gnu.org> wrote: > > On Tue, 2009-07-14 at 19:57 +0200, Robert Millan wrote: > > > >> I agree that we have a problem due to lack of leadership, but this is not > >> acceptable. Marco is busy right now (traveling), so please put this on hold > >> untill he's back, then we can discuss it. > > > > I agree that we should not rush with such changes. However, publishing > > patches for discussion and testing is a good thing and should not be > > discouraged. > > Hi, > > Yeah, I don't mean to push it. In fact, I've created a git repository > for my temporary work > > http://repo.or.cz/w/grub2/bean.git Hi, Usually, I only go through the trouble of implementing things when it's clear they will be merged in some form. But I understand it's not the same for everyone. So if I missunderstood, please accept my apology. In any case, this kind of changes need wider consensus, and including the maintainers in it. And in general, I think we should hold off from big restructuring at this time. Using branches is a good idea IMHO (be it "someone's branch" or "pupa2" or whatever). -- Robert Millan The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and how) you may access your data; but nobody's threatening your freedom: we still allow you to remove your data and not access it at all." ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: please stop this 2009-07-16 15:23 ` Robert Millan @ 2009-07-16 16:10 ` Vladimir 'phcoder' Serbinenko 2009-07-18 18:15 ` Robert Millan 0 siblings, 1 reply; 25+ messages in thread From: Vladimir 'phcoder' Serbinenko @ 2009-07-16 16:10 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Jul 16, 2009 at 5:23 PM, Robert Millan<rmh@aybabtu.com> wrote: > On Wed, Jul 15, 2009 at 02:17:39AM +0800, Bean wrote: >> On Wed, Jul 15, 2009 at 2:09 AM, Pavel Roskin<proski@gnu.org> wrote: >> > On Tue, 2009-07-14 at 19:57 +0200, Robert Millan wrote: >> > >> >> I agree that we have a problem due to lack of leadership, but this is not >> >> acceptable. Marco is busy right now (traveling), so please put this on hold >> >> untill he's back, then we can discuss it. >> > >> > I agree that we should not rush with such changes. However, publishing >> > patches for discussion and testing is a good thing and should not be >> > discouraged. >> >> Hi, >> >> Yeah, I don't mean to push it. In fact, I've created a git repository >> for my temporary work >> >> http://repo.or.cz/w/grub2/bean.git > > Hi, > > Usually, I only go through the trouble of implementing things when it's > clear they will be merged in some form. But I understand it's not > the same for everyone. So if I missunderstood, please accept my apology. In some cases actually implementing something is needed to know whether it will give an advantage > > In any case, this kind of changes need wider consensus, and including the > maintainers in it. The problem is that most comments are in the form "maybe I agree maybe I don't". Such kind of discussions may never result in consensus. Useful patches lying in bitrot somewhere on the list is unfortunately something common. We need a better organisation and more dynamism if we want project to advance. New maintainer can make these changes happen. And generally I tend to accept a rule "absent person is wrong and agrees". Not because I don't respect other people but just because I don't see why project would eternally wait for someone to come by. I think that main rules are Sane-o-cracy and Do-o-cracy: As long as choice is sane and expandable doer decides > And in general, I think we should hold off from big > restructuring at this time. Using branches is a good idea IMHO (be it > "someone's branch" or "pupa2" or whatever). Having too many branches per developer may prevent GRUB from being GRand and Unified. > > -- > Robert Millan > > The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and > how) you may access your data; but nobody's threatening your freedom: we > still allow you to remove your data and not access it at all." > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/grub-devel > -- Regards Vladimir 'phcoder' Serbinenko Personal git repository: http://repo.or.cz/w/grub2/phcoder.git ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: please stop this 2009-07-16 16:10 ` Vladimir 'phcoder' Serbinenko @ 2009-07-18 18:15 ` Robert Millan 2009-07-18 18:53 ` Vladimir 'phcoder' Serbinenko 0 siblings, 1 reply; 25+ messages in thread From: Robert Millan @ 2009-07-18 18:15 UTC (permalink / raw) To: The development of GRUB 2 On Thu, Jul 16, 2009 at 06:10:48PM +0200, Vladimir 'phcoder' Serbinenko wrote: > > > > Usually, I only go through the trouble of implementing things when it's > > clear they will be merged in some form. But I understand it's not > > the same for everyone. So if I missunderstood, please accept my apology. > In some cases actually implementing something is needed to know > whether it will give an advantage Agreed, in some cases it helps. > > In any case, this kind of changes need wider consensus, and including the > > maintainers in it. > The problem is that most comments are in the form "maybe I agree maybe > I don't". Such kind of discussions may never result in consensus. > Useful patches lying in bitrot somewhere on the list is unfortunately > something common. We need a better organisation and more dynamism if > we want project to advance. New maintainer can make these changes > happen. And generally I tend to accept a rule "absent person is wrong > and agrees". Not because I don't respect other people but just because > I don't see why project would eternally wait for someone to come by. I > think that main rules are Sane-o-cracy and Do-o-cracy: As long as > choice is sane and expandable doer decides I agree we need better organisation, but I don't think even more dynamism is the answer. Actually I think we've got _more_ dynamism than we can handle (I don't think dynamism is bad, but we have to acknowledge our limits). Some people do lots of work, sometimes things we obviously want, and sometimes design changes that need careful review and analisys. The problem is that our resources to do the latter are not a la par with the amount of contribution we receive. What we have now is that often a single person comes up with an idea that changes GRUB in significant ways, it is proposed, and because we lack the resources to review it it's not reviewed, or only barely so. Then the "absent person is wrong and agrees" rule prevails, change is merged, and we may later find that this is not really what we wanted. Marco's been in Catalonia this week. Last thursday he came to Barcelona and we had some talk about the situation with GRUB. I can assure you that he's concerned about this. He sees this "maintainer's not here so let's do what ever we want" approach as a problem, although it's pretty understandable given the situation (he acknoledges that as well). > > And in general, I think we should hold off from big > > restructuring at this time. Using branches is a good idea IMHO (be it > > "someone's branch" or "pupa2" or whatever). > Having too many branches per developer may prevent GRUB from being > GRand and Unified. I think the "Unified" means it supports multiple filesystems, the Multiboot standard, etc, allowing it to support a wide variety of OSes. But it's just a word anyway... IMO, branches are useful sometimes, because they make it easier to experiment with new things without risk of breaking our core functionality. -- Robert Millan The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and how) you may access your data; but nobody's threatening your freedom: we still allow you to remove your data and not access it at all." ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: please stop this 2009-07-18 18:15 ` Robert Millan @ 2009-07-18 18:53 ` Vladimir 'phcoder' Serbinenko 0 siblings, 0 replies; 25+ messages in thread From: Vladimir 'phcoder' Serbinenko @ 2009-07-18 18:53 UTC (permalink / raw) To: The development of GRUB 2 >> > In any case, this kind of changes need wider consensus, and including the >> > maintainers in it. >> The problem is that most comments are in the form "maybe I agree maybe >> I don't". Such kind of discussions may never result in consensus. >> Useful patches lying in bitrot somewhere on the list is unfortunately >> something common. We need a better organisation and more dynamism if >> we want project to advance. New maintainer can make these changes >> happen. And generally I tend to accept a rule "absent person is wrong >> and agrees". Not because I don't respect other people but just because >> I don't see why project would eternally wait for someone to come by. I >> think that main rules are Sane-o-cracy and Do-o-cracy: As long as >> choice is sane and expandable doer decides > > I agree we need better organisation, but I don't think even more dynamism is > the answer. Actually I think we've got _more_ dynamism than we can handle > (I don't think dynamism is bad, but we have to acknowledge our limits). > > Some people do lots of work, sometimes things we obviously want, and > sometimes design changes that need careful review and analisys. The > problem is that our resources to do the latter are not a la par with the > amount of contribution we receive. I don't think that grub as a project isn't able to handle incoming patches. I think that lack of organisation just wastes the effort. Perhaps we could use some kind of core team approach. One example is to designate N core team members and need a confirmation of floor (N/2) core members for design changes and no oppositions and that at least one weak passed after such consensus and a confirmation of one core team member for ordinary patches or in case if author is in core team and no further replies one weak that patch is laying on the list. This way even if some core members are on vacation the system continues to work > > What we have now is that often a single person comes up with an idea that > changes GRUB in significant ways, it is proposed, and because we lack the > resources to review it it's not reviewed, or only barely so. Then the > "absent person is wrong and agrees" rule prevails, change is merged, and > we may later find that this is not really what we wanted. > > Marco's been in Catalonia this week. Last thursday he came to Barcelona and > we had some talk about the situation with GRUB. I can assure you that he's > concerned about this. He sees this "maintainer's not here so let's do what > ever we want" approach as a problem, although it's pretty understandable > given the situation (he acknoledges that as well). > If he'll be soonish available for discussion we should wait for him and discuss this altogether. > I think the "Unified" means it supports multiple filesystems, the Multiboot > standard, etc, allowing it to support a wide variety of OSes. Exactly. And if patches have problems to get in we risk not to recieve features the project merits and gets loads of forks (=fragmentation instead of unification) instead > But it's just > a word anyway... > > IMO, branches are useful sometimes, because they make it easier to experiment > with new things without risk of breaking our core functionality. > Could we perhaps create a developement branch in svn to share code easier? > -- > Robert Millan > > The DRM opt-in fallacy: "Your data belongs to us. We will decide when (and > how) you may access your data; but nobody's threatening your freedom: we > still allow you to remove your data and not access it at all." > > > _______________________________________________ > Grub-devel mailing list > Grub-devel@gnu.org > http://lists.gnu.org/mailman/listinfo/grub-devel > -- Regards Vladimir 'phcoder' Serbinenko Personal git repository: http://repo.or.cz/w/grub2/phcoder.git ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-14 15:49 [PATCH] New object format Bean 2009-07-14 17:57 ` please stop this Robert Millan @ 2009-07-14 21:02 ` Bean 2009-07-19 1:52 ` Isaac Dupree 2 siblings, 0 replies; 25+ messages in thread From: Bean @ 2009-07-14 21:02 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 1231 bytes --] Hi, Ok, find the bug for elf converter. elf and pe are both ok now. On Tue, Jul 14, 2009 at 11:49 PM, Bean<bean123ch@gmail.com> wrote: > Hi, > > This patch implement a new object format, the advantages are: > > Reduce size dramatically, some result: > > Size of all modules: > > original: 645575 > new: 519093 > > Dynamic loader: > > original > text data bss dec hex filename > 412 0 0 412 19c kernel_img-kern___target_cpu__dl.o > 3052 0 2064 5116 13fc kernel_img-kern_dl.o > > new: > text data bss dec hex filename > 2272 0 2064 4336 10f0 kernel_img-kern_dl.o > > Greatly simplify the build process: > > 1, compile *.c, *.S to *.o > 2, use grub-mkmod to merge *.o file to mod > 3, use grub-symdb to maintain module dependence > > so there is no pre-* mod-* def-* und-* anymore. > > grub-mkmod support both pe and elf format, no need to convert with grub-pe2elf. > > BTW, this patch breaks other platform. And it seems there is some bug > in elf->mod converter. But the pe->mod works quite nice, I can load > graphic menu and even run osdetect script with lua. > > -- > Bean > -- Bean [-- Attachment #2: obj.diff --] [-- Type: text/x-patch, Size: 88142 bytes --] diff --git a/Makefile.in b/Makefile.in index 3d208e7..d984872 100644 --- a/Makefile.in +++ b/Makefile.in @@ -147,11 +147,9 @@ include $(srcdir)/conf/$(target_cpu)-$(platform).mk ### General targets. CLEANFILES += $(pkglib_DATA) $(pkgdata_DATA) -pkglib_DATA += moddep.lst command.lst fs.lst partmap.lst parttool.lst handler.lst -moddep.lst: $(DEFSYMFILES) $(UNDSYMFILES) genmoddep.awk - cat $(DEFSYMFILES) /dev/null \ - | $(AWK) -f $(srcdir)/genmoddep.awk $(UNDSYMFILES) > $@ \ - || (rm -f $@; exit 1) +pkglib_DATA += modsym.lst command.lst fs.lst partmap.lst parttool.lst handler.lst +modsym.lst: $(MODFILES) grub-symdb + ./grub-symdb -d . update $? command.lst: $(COMMANDFILES) cat $^ /dev/null | sort > $@ diff --git a/conf/common.rmk b/conf/common.rmk index 07ff04e..ddb368e 100644 --- a/conf/common.rmk +++ b/conf/common.rmk @@ -125,6 +125,23 @@ endif grub_pe2elf_SOURCES = util/grub-pe2elf.c util/misc.c CLEANFILES += grub-pe2elf +# grub-mkmod +bin_UTILITIES += grub-mkmod +grub_mkmod_SOURCES = util/grub-mkmod.c util/misc.c util/obj.c \ + util/obj_pe.c util/obj_elf.c kern/list.c +CLEANFILES += grub-mkmod + +# grub-symdb +bin_UTILITIES += grub-symdb +grub_symdb_SOURCES = util/grub-symdb.c util/obj.c util/misc.c kern/list.c +CLEANFILES += grub-symdb + +# grub-objdump +bin_UTILITIES += grub-objdump +grub_objdump_SOURCES = util/grub-objdump.c util/obj.c util/misc.c \ + util/obj_dump.c kern/list.c +CLEANFILES += grub-objdump + # grub_macho2img assumes a lot about source file. # So installing it definitively is useless # But adding to bin_UTILITIES is needed for @@ -512,15 +529,15 @@ sh_mod_CFLAGS = $(COMMON_CFLAGS) sh_mod_LDFLAGS = $(COMMON_LDFLAGS) # For lua.mod. -lua_mod_SOURCES = script/lua/lapi.c script/lua/lcode.c script/lua/ldebug.c \ +lua_mod_SOURCES = script/lua/grub_main.c script/lua/grub_lib.c \ + script/lua/lapi.c script/lua/lcode.c script/lua/ldebug.c \ script/lua/ldo.c script/lua/ldump.c script/lua/lfunc.c \ script/lua/lgc.c script/lua/llex.c script/lua/lmem.c \ script/lua/lobject.c script/lua/lopcodes.c script/lua/lparser.c \ script/lua/lstate.c script/lua/lstring.c script/lua/ltable.c \ script/lua/ltm.c script/lua/lundump.c script/lua/lvm.c \ script/lua/lzio.c script/lua/lauxlib.c script/lua/lbaselib.c \ - script/lua/linit.c script/lua/ltablib.c script/lua/lstrlib.c \ - script/lua/grub_main.c script/lua/grub_lib.c + script/lua/linit.c script/lua/ltablib.c script/lua/lstrlib.c lua_mod_CFLAGS = $(COMMON_CFLAGS) lua_mod_LDFLAGS = $(COMMON_LDFLAGS) diff --git a/conf/i386-pc.rmk b/conf/i386-pc.rmk index f1915b6..185ffd4 100644 --- a/conf/i386-pc.rmk +++ b/conf/i386-pc.rmk @@ -53,7 +53,7 @@ kernel_img_SOURCES = kern/i386/pc/startup.S \ kern/misc.c kern/mm.c kern/reader.c kern/term.c \ kern/rescue_parser.c kern/rescue_reader.c \ kern/time.c kern/list.c kern/handler.c kern/command.c kern/corecmd.c \ - kern/$(target_cpu)/dl.c kern/i386/pc/init.c kern/i386/pc/mmap.c \ + kern/i386/pc/init.c kern/i386/pc/mmap.c \ kern/parser.c kern/partition.c \ kern/i386/tsc.c kern/i386/pit.c \ kern/generic/rtc_get_time_ms.c \ diff --git a/genmk.rb b/genmk.rb index e3866c1..39141f4 100644 --- a/genmk.rb +++ b/genmk.rb @@ -106,60 +106,16 @@ class PModule objs_str = objs.join(' ') deps = objs.collect {|obj| obj.suffix('d')} deps_str = deps.join(' ') - pre_obj = 'pre-' + @name.suffix('o') - mod_src = 'mod-' + @name.suffix('c') - mod_obj = mod_src.suffix('o') - defsym = 'def-' + @name.suffix('lst') - undsym = 'und-' + @name.suffix('lst') mod_name = File.basename(@name, '.mod') symbolic_name = mod_name.sub(/\.[^\.]*$/, '') - "CLEANFILES += #{@name} #{mod_obj} #{mod_src} #{pre_obj} #{objs_str} #{undsym} -ifneq ($(#{prefix}_EXPORTS),no) -CLEANFILES += #{defsym} -DEFSYMFILES += #{defsym} -endif + "CLEANFILES += #{@name} #{objs_str} MOSTLYCLEANFILES += #{deps_str} -UNDSYMFILES += #{undsym} - -ifneq ($(TARGET_APPLE_CC),1) -#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) - -rm -f $@ - $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{pre_obj} #{mod_obj} - if test ! -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 $@ -else -#{@name}: #{pre_obj} #{mod_obj} $(TARGET_OBJ2ELF) - -rm -f $@ - -rm -f $@.bin - $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@.bin #{pre_obj} #{mod_obj} - $(OBJCONV) -f$(TARGET_MODULE_FORMAT) -nr:_grub_mod_init:grub_mod_init -nr:_grub_mod_fini:grub_mod_fini -wd1106 -nu -nd $@.bin $@ - -rm -f $@.bin -endif - -#{pre_obj}: $(#{prefix}_DEPENDENCIES) #{objs_str} - -rm -f $@ - $(TARGET_CC) $(#{prefix}_LDFLAGS) $(TARGET_LDFLAGS) -Wl,-r,-d -o $@ #{objs_str} -#{mod_obj}: #{mod_src} - $(TARGET_CC) $(TARGET_CPPFLAGS) $(TARGET_CFLAGS) $(#{prefix}_CFLAGS) -c -o $@ $< - -#{mod_src}: $(builddir)/moddep.lst $(srcdir)/genmodsrc.sh - sh $(srcdir)/genmodsrc.sh '#{mod_name}' $< > $@ || (rm -f $@; exit 1) - -ifneq ($(#{prefix}_EXPORTS),no) -ifneq ($(TARGET_APPLE_CC),1) -#{defsym}: #{pre_obj} - $(NM) -g --defined-only -P -p $< | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@ -else -#{defsym}: #{pre_obj} - $(NM) -g -P -p $< | grep -E '^[a-zA-Z0-9_]* [TDS]' | sed 's/^\\([^ ]*\\).*/\\1 #{mod_name}/' > $@ -endif -endif +#{@name}: $(#{prefix}_DEPENDENCIES) #{objs_str} grub-mkmod + ./grub-mkmod -o $@ $(filter %.o, $^) -#{undsym}: #{pre_obj} - echo '#{mod_name}' > $@ - $(NM) -u -P -p $< | cut -f1 -d' ' >> $@ +MODFILES += #{@name} " + objs.collect_with_index do |obj, i| src = sources[i] diff --git a/include/grub/dl.h b/include/grub/dl.h index e24b832..3f8b328 100644 --- a/include/grub/dl.h +++ b/include/grub/dl.h @@ -85,7 +85,6 @@ struct grub_dl }; typedef struct grub_dl *grub_dl_t; -grub_err_t EXPORT_FUNC(grub_dl_check_header) (void *ehdr, grub_size_t size); grub_dl_t EXPORT_FUNC(grub_dl_load_file) (const char *filename); grub_dl_t EXPORT_FUNC(grub_dl_load) (const char *name); grub_dl_t grub_dl_load_core (void *addr, grub_size_t size); diff --git a/include/grub/elf.h b/include/grub/elf.h index 1a1ec13..6d2f28d 100644 --- a/include/grub/elf.h +++ b/include/grub/elf.h @@ -454,8 +454,8 @@ typedef struct the end of a chain, meaning no further symbols are found in that bucket. */ #define STN_UNDEF 0 /* End of a chain. */ -#define STN_ABS 65521 - +#define STN_ABS 0xfff1 +#define STN_COMMON 0xfff2 /* How to extract and insert information held in the st_other field. */ diff --git a/include/grub/obj.h b/include/grub/obj.h new file mode 100644 index 0000000..29ff8dc --- /dev/null +++ b/include/grub/obj.h @@ -0,0 +1,90 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/>. + */ + +#ifndef GRUB_OBJ_H +#define GRUB_OBJ_H 1 + +#include <grub/types.h> + +#define GRUB_OBJ_HEADER_MAGIC 0x4a424f47 /* GOBJ */ +#define GRUB_OBJ_HEADER_VERSION 1 + +#define GRUB_OBJ_SEG_END 0 +#define GRUB_OBJ_SEG_TEXT 1 +#define GRUB_OBJ_SEG_DATA 2 +#define GRUB_OBJ_SEG_RDATA 3 +#define GRUB_OBJ_SEG_BSS 4 + +#define GRUB_OBJ_FUNC_NONE 0xffff + +struct grub_obj_segment +{ + grub_uint8_t type; + grub_uint32_t offset; + grub_uint8_t align; + grub_uint32_t size; +} __attribute__((packed)); + +struct grub_obj_header +{ + grub_uint32_t magic; + grub_uint16_t version; + grub_uint16_t symbol_table; + grub_uint16_t reloc_table; + grub_uint16_t string_table; + grub_uint16_t init_func; + grub_uint16_t fini_func; + grub_uint32_t mod_deps; + struct grub_obj_segment segments[1]; +} __attribute__((packed)); + +#define GRUB_OBJ_SEGMENT_END 0xff + +#define GRUB_OBJ_REL_DIR32 0 +#define GRUB_OBJ_REL_REL32 1 +#define GRUB_OBJ_REL_DIR64 2 +#define GRUB_OBJ_REL_REL64 3 + +#define GRUB_OBJ_REL_ISREL 1 +#define GRUB_OBJ_REL_64BIT 2 + +struct grub_obj_symbol +{ + grub_uint8_t segment; + grub_uint16_t name; + grub_uint32_t offset; +} __attribute__((packed)); + +struct grub_obj_reloc +{ + grub_uint8_t segment; + grub_uint8_t type; + grub_uint32_t offset; + grub_uint8_t symbol_segment; +} __attribute__((packed)); + +struct grub_obj_reloc_extern +{ + grub_uint8_t segment; + grub_uint8_t type; + grub_uint32_t offset; + grub_uint8_t symbol_segment; + grub_uint16_t symbol_name; +} __attribute__((packed)); + +#endif /* ! GRUB_OBJ_H */ diff --git a/include/grub/util/misc.h b/include/grub/util/misc.h index 6a93ab0..841d702 100644 --- a/include/grub/util/misc.h +++ b/include/grub/util/misc.h @@ -26,6 +26,7 @@ #include <config.h> #include <grub/types.h> +#include <grub/list.h> #ifdef __NetBSD__ /* NetBSD uses /boot for its boot block. */ @@ -46,6 +47,9 @@ void grub_util_error (const char *fmt, ...) __attribute__ ((noreturn)); void *xmalloc (size_t size); void *xrealloc (void *ptr, size_t size); char *xstrdup (const char *str); +void *xmalloc_zero (size_t size); + +void * grub_list_reverse (grub_list_t head); char *grub_util_get_path (const char *dir, const char *file); size_t grub_util_get_fp_size (FILE *fp); @@ -56,6 +60,8 @@ void grub_util_load_image (const char *path, char *buf); void grub_util_write_image (const char *img, size_t size, FILE *out); void grub_util_write_image_at (const void *img, size_t size, off_t offset, FILE *out); +char * grub_util_get_module_name (const char *str); +char * grub_util_get_module_path (const char *prefix, const char *str); #ifndef HAVE_ASPRINTF diff --git a/include/grub/util/obj.h b/include/grub/util/obj.h new file mode 100644 index 0000000..2c35bc9 --- /dev/null +++ b/include/grub/util/obj.h @@ -0,0 +1,84 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/>. + */ + +#ifndef GRUB_UTIL_OBJ_HEADER +#define GRUB_UTIL_OBJ_HEADER 1 + +#include <config.h> +#include <grub/types.h> +#include <grub/obj.h> +#include <grub/list.h> + +#include <stdio.h> + +struct grub_util_obj_segment +{ + struct grub_util_obj_segment *next; + struct grub_obj_segment segment; + char *data; + grub_uint32_t raw_size; + grub_uint32_t file_off; + int index; +}; + +struct grub_util_obj_symbol +{ + struct grub_util_obj_symbol *next; + char *name; + struct grub_util_obj_segment *segment; + struct grub_obj_symbol symbol; +}; + +struct grub_util_obj_reloc +{ + struct grub_util_obj_reloc *next; + struct grub_util_obj_segment *segment; + struct grub_obj_reloc reloc; + struct grub_util_obj_segment *symbol_segment; + grub_uint32_t symbol_offset; + char *symbol_name; +}; + +struct grub_util_obj +{ + struct grub_util_obj_segment *segments; + struct grub_util_obj_symbol *symbols; + struct grub_util_obj_reloc *relocs; + grub_uint32_t mod_attr; +}; + +#define GRUB_OBJ_MERGE_NONE 0 +#define GRUB_OBJ_MERGE_SAME 1 +#define GRUB_OBJ_MERGE_ALL 2 + +void grub_obj_reverse (struct grub_util_obj *obj); +void grub_obj_sort_segments (struct grub_util_obj *obj); +void grub_obj_merge_segments (struct grub_util_obj *obj, int merge); +void grub_obj_reloc_symbols (struct grub_util_obj *obj, int merge); +void grub_obj_save (struct grub_util_obj *obj, char *mod_name, FILE *fp); +struct grub_util_obj *grub_obj_load (char *image, int size, int load_data); +void grub_obj_free (struct grub_util_obj *obj); + +void grub_obj_dump_segments (struct grub_util_obj *obj); +void grub_obj_dump_symbols (struct grub_util_obj *obj); +void grub_obj_dump_relocs (struct grub_util_obj *obj); + +int pe_add_file (struct grub_util_obj *obj, char *image, int size); +int elf_add_file (struct grub_util_obj *obj, char *image, int size); + +#endif /* ! GRUB_UTIL_OBJ_HEADER */ diff --git a/kern/dl.c b/kern/dl.c index 6c863be..fd81dd7 100644 --- a/kern/dl.c +++ b/kern/dl.c @@ -18,8 +18,8 @@ */ #include <config.h> -#include <grub/elf.h> #include <grub/dl.h> +#include <grub/obj.h> #include <grub/misc.h> #include <grub/mm.h> #include <grub/err.h> @@ -219,78 +219,46 @@ grub_dl_get_section_addr (grub_dl_t mod, unsigned n) return 0; } -/* Check if EHDR is a valid ELF header. */ -grub_err_t -grub_dl_check_header (void *ehdr, grub_size_t size) -{ - Elf_Ehdr *e = ehdr; - - /* Check the header size. */ - if (size < sizeof (Elf_Ehdr)) - return grub_error (GRUB_ERR_BAD_OS, "ELF header smaller than expected"); - - /* Check the magic numbers. */ - if (grub_arch_dl_check_header (ehdr) - || e->e_ident[EI_MAG0] != ELFMAG0 - || e->e_ident[EI_MAG1] != ELFMAG1 - || e->e_ident[EI_MAG2] != ELFMAG2 - || e->e_ident[EI_MAG3] != ELFMAG3 - || e->e_ident[EI_VERSION] != EV_CURRENT - || e->e_version != EV_CURRENT) - return grub_error (GRUB_ERR_BAD_OS, "invalid arch independent ELF magic"); - - return GRUB_ERR_NONE; -} - /* Load all segments from memory specified by E. */ static grub_err_t -grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) +grub_dl_load_segments (grub_dl_t mod, struct grub_obj_header *e) { unsigned i; - Elf_Shdr *s; + struct grub_obj_segment *s; - for (i = 0, s = (Elf_Shdr *)((char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *)((char *) s + e->e_shentsize)) + for (i = 0, s = &e->segments[0]; s->type != GRUB_OBJ_SEGMENT_END; i++, s++) { - if (s->sh_flags & SHF_ALLOC) + grub_dl_segment_t seg; + void *addr; + + seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg)); + if (! seg) + return grub_errno; + + addr = grub_memalign (s->align, s->size); + if (! addr) { - grub_dl_segment_t seg; + grub_free (seg); + return grub_errno; + } - seg = (grub_dl_segment_t) grub_malloc (sizeof (*seg)); - if (! seg) - return grub_errno; + grub_memset (addr, 0, s->size); + grub_memcpy (addr, (char *) e + s->offset, + (s + 1)->offset - s->offset); + seg->addr = addr; - if (s->sh_size) - { - void *addr; - - addr = grub_memalign (s->sh_addralign, s->sh_size); - if (! addr) - { - grub_free (seg); - return grub_errno; - } - - switch (s->sh_type) - { - case SHT_PROGBITS: - grub_memcpy (addr, (char *) e + s->sh_offset, s->sh_size); - break; - case SHT_NOBITS: - grub_memset (addr, 0, s->sh_size); - break; - } - - seg->addr = addr; - } - else - seg->addr = 0; + seg->size = s->size; + seg->section = i; + seg->next = mod->segment; + mod->segment = seg; - seg->size = s->sh_size; - seg->section = i; - seg->next = mod->segment; - mod->segment = seg; + if (! i) + { + if (e->init_func != GRUB_OBJ_FUNC_NONE) + mod->init = (void (*) (grub_dl_t)) ((char *) addr + e->init_func); + + if (e->fini_func != GRUB_OBJ_FUNC_NONE) + mod->fini = (void (*) (void)) ((char *) addr + e->fini_func); } } @@ -298,92 +266,67 @@ grub_dl_load_segments (grub_dl_t mod, const Elf_Ehdr *e) } static grub_err_t -grub_dl_resolve_symbols (grub_dl_t mod, Elf_Ehdr *e) +grub_dl_resolve_symbols (grub_dl_t mod, struct grub_obj_header *e) { - unsigned i; - Elf_Shdr *s; - Elf_Sym *sym; - const char *str; - Elf_Word size, entsize; - - for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) - if (s->sh_type == SHT_SYMTAB) - break; + char *strtab; + struct grub_obj_symbol *sym; + struct grub_obj_reloc_extern *rel; - if (i == e->e_shnum) - return grub_error (GRUB_ERR_BAD_MODULE, "no symbol table"); + strtab = (char *) e + e->string_table; -#ifdef GRUB_MODULES_MACHINE_READONLY - mod->symtab = grub_malloc (s->sh_size); - memcpy (mod->symtab, (char *) e + s->sh_offset, s->sh_size); -#else - mod->symtab = (Elf_Sym *) ((char *) e + s->sh_offset); -#endif - sym = mod->symtab; - size = s->sh_size; - entsize = s->sh_entsize; + for (sym = (struct grub_obj_symbol *) ((char *) e + e->symbol_table); + sym->segment != GRUB_OBJ_SEGMENT_END; sym++) + { + char *addr; - s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shentsize * s->sh_link); - str = (char *) e + s->sh_offset; + addr = grub_dl_get_section_addr (mod, sym->segment); + addr += sym->offset; - for (i = 0; - i < size / entsize; - i++, sym = (Elf_Sym *) ((char *) sym + entsize)) - { - 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; + if (grub_dl_register_symbol (strtab + sym->name, addr, mod)) + return grub_errno; + } - switch (type) - { - case STT_NOTYPE: - /* Resolve a global symbol. */ - if (sym->st_name != 0 && sym->st_shndx == 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); - } - else - sym->st_value = 0; - break; + for (rel = (struct grub_obj_reloc_extern *) ((char *) e + e->reloc_table); + rel->segment != GRUB_OBJ_SEGMENT_END;) + { + char *addr, *symbol_addr; + int type; - case STT_OBJECT: - 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; - break; + addr = grub_dl_get_section_addr (mod, rel->segment); + addr += rel->offset; + type = rel->type; - 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; - break; + if (rel->symbol_segment == GRUB_OBJ_SEGMENT_END) + { + char *name; + + name = strtab + rel->symbol_name; + symbol_addr = grub_dl_resolve_symbol (name); + if (! symbol_addr) + return grub_error (GRUB_ERR_BAD_MODULE, + "the symbol `%s' not found", name); + rel++; + } + else + { + symbol_addr = grub_dl_get_section_addr (mod, rel->symbol_segment); + rel = (struct grub_obj_reloc_extern *) + ((char *) rel + sizeof (struct grub_obj_reloc)); + } - case STT_SECTION: - sym->st_value = (Elf_Addr) grub_dl_get_section_addr (mod, - sym->st_shndx); + switch (type) + { + case GRUB_OBJ_REL_DIR32: + *((grub_uint32_t *) addr) += (grub_uint32_t) symbol_addr; break; - case STT_FILE: - sym->st_value = 0; + case GRUB_OBJ_REL_REL32: + *((grub_uint32_t *) addr) += (grub_uint32_t) (symbol_addr - addr); break; default: return grub_error (GRUB_ERR_BAD_MODULE, - "unknown symbol type `%d'", (int) type); + "unknown reloc type %d", type); } } @@ -398,74 +341,31 @@ grub_dl_call_init (grub_dl_t mod) } static grub_err_t -grub_dl_resolve_name (grub_dl_t mod, Elf_Ehdr *e) +grub_dl_resolve_dependencies (grub_dl_t mod, char *name) { - Elf_Shdr *s; - const char *str; - unsigned i; - - s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); - str = (char *) e + s->sh_offset; - - for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) - if (grub_strcmp (str + s->sh_name, ".modname") == 0) - { - mod->name = grub_strdup ((char *) e + s->sh_offset); - if (! mod->name) - return grub_errno; - break; - } - - if (i == e->e_shnum) - return grub_error (GRUB_ERR_BAD_MODULE, "no module name found"); - - return GRUB_ERR_NONE; -} - -static grub_err_t -grub_dl_resolve_dependencies (grub_dl_t mod, Elf_Ehdr *e) -{ - Elf_Shdr *s; - const char *str; - unsigned i; - - s = (Elf_Shdr *) ((char *) e + e->e_shoff + e->e_shstrndx * e->e_shentsize); - str = (char *) e + s->sh_offset; - - for (i = 0, s = (Elf_Shdr *) ((char *) e + e->e_shoff); - i < e->e_shnum; - i++, s = (Elf_Shdr *) ((char *) s + e->e_shentsize)) - if (grub_strcmp (str + s->sh_name, ".moddeps") == 0) - { - const char *name = (char *) e + s->sh_offset; - const char *max = name + s->sh_size; - - while ((name < max) && (*name)) - { - grub_dl_t m; - grub_dl_dep_t dep; - - m = grub_dl_load (name); - if (! m) - return grub_errno; + while (1) + { + grub_dl_t m; + grub_dl_dep_t dep; - grub_dl_ref (m); + name += grub_strlen (name) + 1; + if (! *name) + return GRUB_ERR_NONE; - dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep)); - if (! dep) - return grub_errno; + m = grub_dl_load (name); + if (! m) + return grub_errno; - dep->mod = m; - dep->next = mod->dep; - mod->dep = dep; + grub_dl_ref (m); - name += grub_strlen (name) + 1; - } - } + dep = (grub_dl_dep_t) grub_malloc (sizeof (*dep)); + if (! dep) + return grub_errno; - return GRUB_ERR_NONE; + dep->mod = m; + dep->next = mod->dep; + mod->dep = dep; + } } #ifndef GRUB_UTIL @@ -510,25 +410,18 @@ grub_dl_flush_cache (grub_dl_t mod) grub_dl_t grub_dl_load_core (void *addr, grub_size_t size) { - Elf_Ehdr *e; + struct grub_obj_header *e; grub_dl_t mod; + char *name; grub_dprintf ("modules", "module at %p, size 0x%lx\n", addr, (unsigned long) size); - e = addr; - if (grub_dl_check_header (e, size)) - return 0; - - if (e->e_type != ET_REL) - { - grub_error (GRUB_ERR_BAD_MODULE, "invalid ELF file type"); - return 0; - } - /* Make sure that every section is within the core. */ - if (size < e->e_shoff + e->e_shentsize * e->e_shnum) + e = addr; + if ((e->magic != GRUB_OBJ_HEADER_MAGIC) || + (e->version != GRUB_OBJ_HEADER_VERSION)) { - grub_error (GRUB_ERR_BAD_OS, "ELF sections outside core"); + grub_error (GRUB_ERR_BAD_OS, "invalid object file"); return 0; } @@ -536,7 +429,9 @@ grub_dl_load_core (void *addr, grub_size_t size) if (! mod) return 0; - mod->name = 0; + name = (char *) addr + e->mod_deps; + + mod->name = grub_strdup (name); mod->ref_count = 1; mod->dep = 0; mod->segment = 0; @@ -544,11 +439,9 @@ grub_dl_load_core (void *addr, grub_size_t size) mod->fini = 0; grub_dprintf ("modules", "relocating to %p\n", mod); - if (grub_dl_resolve_name (mod, e) - || grub_dl_resolve_dependencies (mod, e) + if (grub_dl_resolve_dependencies (mod, name) || grub_dl_load_segments (mod, e) - || grub_dl_resolve_symbols (mod, e) - || grub_arch_dl_relocate_symbols (mod, e)) + || grub_dl_resolve_symbols (mod, e)) { mod->fini = 0; grub_dl_unload (mod); diff --git a/util/grub-mkmod.c b/util/grub-mkmod.c new file mode 100644 index 0000000..1ed1b55 --- /dev/null +++ b/util/grub-mkmod.c @@ -0,0 +1,176 @@ +/* grub-mkmod.c - tool to generate mod file from object files. */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +int +grub_strcmp (const char *s1, const char *s2) +{ + return strcmp (s1, s2); +} + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {"output", required_argument, 0, 'o'}, + {"name", required_argument, 0, 'n'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-mkmod --help'' for more information.\n"); + else + printf ("\ +Usage: grub-mkmod [OPTIONS] [OBJECT_FILES].\n\ +\n\ +Tool to generate mod file from object files.\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\ + -o, --output=FILE output a generated image to FILE [default=stdout]\n\ + -n, --name=NAME set module name\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +static void +add_file (struct grub_util_obj *obj, char *image, int size) +{ + if ((! elf_add_file (obj, image, size)) && + (! pe_add_file (obj, image, size))) + grub_util_error ("Invalid object format"); +} + +static void +mkmod (char *objs[], char *name, FILE *fp) +{ + struct grub_util_obj *obj; + int merge = GRUB_OBJ_MERGE_ALL; + + obj = xmalloc_zero (sizeof (*obj)); + while (*objs) + { + char *image; + int size; + + image = grub_util_read_image (*objs); + size = grub_util_get_image_size (*objs); + add_file (obj, image, size); + free (image); + objs++; + } + + grub_obj_reverse (obj); + grub_obj_sort_segments (obj); + grub_obj_merge_segments (obj, merge); + grub_obj_reloc_symbols (obj, merge); + grub_obj_save (obj, name, fp); + + grub_obj_free (obj); +} + +int +main (int argc, char *argv[]) +{ + FILE *fp = stdout; + char *output = NULL; + char *name = NULL; + + progname = "grub-pe2mod"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVvo:n:", 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; + + case 'o': + if (output) + free (output); + + output = xstrdup (optarg); + break; + + case 'n': + if (name) + free (name); + + name = xstrdup (optarg); + break; + + default: + usage (1); + break; + } + } + + if (! name) + { + if (! output) + grub_util_error ("no module name"); + name = grub_util_get_module_name (output); + } + + if (output) + { + fp = fopen (output, "wb"); + if (! fp) + grub_util_error ("cannot open %s", output); + free (output); + } + + mkmod (argv + optind, name, fp); + + fclose (fp); + free (name); + + return 0; +} diff --git a/util/grub-objdump.c b/util/grub-objdump.c new file mode 100644 index 0000000..05a5b3e --- /dev/null +++ b/util/grub-objdump.c @@ -0,0 +1,176 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <getopt.h> + +int +grub_strcmp (const char *s1, const char *s2) +{ + return strcmp (s1, s2); +} + +static struct option options[] = { + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'V'}, + {"verbose", no_argument, 0, 'v'}, + {"all-headers", no_argument, 0, 'x'}, + {"segment", no_argument, 0, 's'}, + {"syms", no_argument, 0, 't'}, + {"reloc", no_argument, 0, 'r'}, + {0, 0, 0, 0} +}; + +static void +usage (int status) +{ + if (status) + fprintf (stderr, "Try ``grub-mkmod --help'' for more information.\n"); + else + printf ("\ +Usage: grub-objdump [OPTIONS] [MODULE_FILES].\n\ +\n\ +Tool to generate mod file from object files.\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\ + -x, --all display all information\n\ + -s, --segment display segment information\n\ + -t, --syms display symbol table\n\ + -r, --reloc display reloc table\n\ +\n\ +Report bugs to <%s>.\n", PACKAGE_BUGREPORT); + + exit (status); +} + +#define FLAG_DUMP_SEGMENT 1 +#define FLAG_DUMP_SYMBOL 2 +#define FLAG_DUMP_RELOC 4 +#define FLAG_DUMP_ALL 7 + +static void +objdump (char *objs[], int flag) +{ + while (*objs) + { + struct grub_util_obj *obj; + char *image; + struct grub_obj_header *e; + int size; + + image = grub_util_read_image (*objs); + size = grub_util_get_image_size (*objs); + obj = grub_obj_load (image, size, 1); + + e = (struct grub_obj_header *) image; + printf ("filename: %s\n", *objs); + printf ("mod name: %s\n", image + e->mod_deps); + printf ("mod attr: 0x%x\n", obj->mod_attr); + printf ("mod deps: 0x%x\n", e->mod_deps); + printf ("init func: 0x%x\n", e->init_func); + printf ("fini func: 0x%x\n", e->fini_func); + + if (flag & FLAG_DUMP_SEGMENT) + { + printf ("\n"); + grub_obj_dump_segments (obj); + } + + if (flag & FLAG_DUMP_SYMBOL) + { + printf ("\n"); + grub_obj_dump_symbols (obj); + } + + if (flag & FLAG_DUMP_RELOC) + { + printf ("\n"); + grub_obj_dump_relocs (obj); + } + + grub_obj_free (obj); + free (image); + objs++; + } +} + +int +main (int argc, char *argv[]) +{ + int flag = 0; + + progname = "grub-objdump"; + + /* Check for options. */ + while (1) + { + int c = getopt_long (argc, argv, "hVvxstr", 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; + + case 'x': + flag |= FLAG_DUMP_ALL; + break; + + case 's': + flag |= FLAG_DUMP_SEGMENT; + break; + + case 't': + flag |= FLAG_DUMP_SYMBOL; + break; + + case 'r': + flag |= FLAG_DUMP_RELOC; + break; + + default: + usage (1); + break; + } + } + + objdump (argv + optind, flag); + + return 0; +} diff --git a/util/grub-symdb.c b/util/grub-symdb.c new file mode 100644 index 0000000..94a0904 --- /dev/null +++ b/util/grub-symdb.c @@ -0,0 +1,811 @@ +/* grub-symdb.c - manage symbol database */ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> + +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <stdlib.h> +#include <sys/stat.h> + +#define _GNU_SOURCE 1 +#include <getopt.h> + +int +grub_strcmp (const char *s1, const char *s2) +{ + return strcmp (s1, s2); +} + +struct grub_symbol_list +{ + struct grub_symbol_list *next; + char *name; + struct grub_named_list *defs; + struct grub_named_list *unds; +}; + +static struct grub_symbol_list *symbol_list; + +struct grub_update_list +{ + struct grub_update_list *next; + char *name; + struct grub_named_list *add_mods; + struct grub_named_list *del_mods; + struct grub_named_list *cur_mods; +}; + +static struct grub_update_list *update_list; + +struct grub_mod_syms +{ + struct grub_named_list *defs; + struct grub_named_list *unds; +}; + + +void * +grub_sort_list_find (grub_named_list_t head, const char *name) +{ + grub_named_list_t result = 0; + + auto int list_find (grub_named_list_t item); + int list_find (grub_named_list_t item) + { + int r; + + r = strcmp (name, item->name); + if (! r) + { + result = item; + return 1; + } + + return (r < 0); + } + + grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) list_find); + return result; +} + +static void +grub_sort_list_insert (grub_named_list_t *head, grub_named_list_t item) +{ + auto int test (grub_named_list_t new_item, grub_named_list_t item); + int test (grub_named_list_t new_item, grub_named_list_t item) + { + return (strcmp (new_item->name, item->name) < 0); + } + + grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (item), + (grub_list_test_t) test); +} + +static void +free_named_list (grub_named_list_t *head) +{ + grub_named_list_t cur = *head; + + while (cur) + { + grub_named_list_t tmp; + + tmp = cur; + cur = cur->next; + free ((char *) tmp->name); + free (tmp); + } + + *head = 0; +} + +static int +remove_string (grub_named_list_t *head, char *name) +{ + grub_named_list_t p; + + p = grub_sort_list_find (*head, name); + if (p) + { + grub_list_remove (GRUB_AS_LIST_P (head), GRUB_AS_LIST (p)); + free ((char *) p->name); + free (p); + + return 1; + } + + return 0; +} + +static int +insert_string (grub_named_list_t *head, char *name) +{ + struct grub_named_list *n; + + n = grub_sort_list_find (*head, name); + if (n) + return 0; + + n = xmalloc (sizeof (struct grub_named_list)); + n->name = xstrdup (name); + grub_sort_list_insert (head, n); + + return 1; +} + +static struct grub_symbol_list * +insert_symbol (char *name) +{ + struct grub_symbol_list *n; + + n = grub_sort_list_find (GRUB_AS_NAMED_LIST (symbol_list), name); + if (! n) + { + n = xmalloc (sizeof (struct grub_symbol_list)); + n->name = xstrdup (name); + n->defs = 0; + n->unds = 0; + + grub_sort_list_insert (GRUB_AS_NAMED_LIST_P (&symbol_list), + GRUB_AS_NAMED_LIST (n)); + } + + return n; +} + +static struct grub_update_list * +insert_update (char *name) +{ + struct grub_update_list *n; + + n = grub_sort_list_find (GRUB_AS_NAMED_LIST (update_list), name); + if (! n) + { + n = xmalloc (sizeof (struct grub_update_list)); + n->name = xstrdup (name); + n->add_mods = 0; + n->del_mods = 0; + n->cur_mods = 0; + + grub_sort_list_insert (GRUB_AS_NAMED_LIST_P (&update_list), + GRUB_AS_NAMED_LIST (n)); + } + + return n; +} + +static void +add_update (char *m1, char *m2, int is_add) +{ + struct grub_update_list *u; + + u = insert_update (m2); + if (is_add) + { + remove_string (&u->del_mods, m1); + insert_string (&u->add_mods, m1); + } + else + insert_string (&u->del_mods, m1); +} + +static void +read_symdb (char *path) +{ + FILE *fp; + char line[512]; + struct grub_symbol_list *sym = 0; + + fp = fopen (path, "r"); + if (! fp) + return; + + while (fgets (line, sizeof (line), fp)) + { + char *p; + + p = line + strlen (line) - 1; + while ((p >= line) && ((*p == '\r') || (*p == '\n') || (*p == ' '))) + p--; + + if (p < line) + continue; + + *(p + 1) = 0; + + p = line; + while (*p == ' ') + p++; + + if (*p == '#') + continue; + + if ((*p == '+') || (*p == '-')) + { + if (! sym) + grub_util_error ("No current symbol."); + + insert_string ((*p == '+') ? &sym->defs : &sym->unds, p + 1); + } + else + sym = insert_symbol (p); + } + + fclose (fp); +} + +static void +write_symdb (char *path) +{ + FILE *fp; + struct grub_symbol_list *sym; + + fp = fopen (path, "w"); + if (! fp) + grub_util_error ("Can\'t write to ", path); + + sym = symbol_list; + while (sym) + { + struct grub_named_list *mod; + + fprintf (fp, "%s\n", sym->name); + mod = sym->defs; + while (mod) + { + fprintf (fp, "+%s\n", mod->name); + mod = mod->next; + } + mod = sym->unds; + while (mod) + { + fprintf (fp, "-%s\n", mod->name); + mod = mod->next; + } + + sym = sym->next; + } + + fclose (fp); +} + +static void +check_symdb (void) +{ + struct grub_symbol_list *sym; + + sym = symbol_list; + while (sym) + { + if (! sym->defs) + printf ("undefined: %s\n", sym->name); + else if (sym->defs->next) + printf ("duplicate: %s\n", sym->name); + + sym = sym->next; + } +} + +static void +read_mod_syms (struct grub_mod_syms *mod_syms, char *path) +{ + struct grub_util_obj *obj; + char *image; + size_t size; + struct grub_util_obj_symbol *sym; + struct grub_util_obj_reloc *rel; + + mod_syms->defs = 0; + mod_syms->unds = 0; + + image = grub_util_read_image (path); + size = grub_util_get_image_size (path); + obj = grub_obj_load (image, size, 0); + + sym = obj->symbols; + while (sym) + { + insert_string (&mod_syms->defs, sym->name); + sym = sym->next; + } + + rel = obj->relocs; + while (rel) + { + if (rel->symbol_name) + insert_string (&mod_syms->unds, rel->symbol_name); + rel = rel->next; + } + + grub_obj_free (obj); + free (image); +} + +static void +update_mods (char *mods[], const char *dir) +{ + for (; mods[0]; mods++) + { + char *mod_name, *mod_path; + struct grub_mod_syms mod_syms; + struct grub_named_list *m; + + mod_name = grub_util_get_module_name (mods[0]); + mod_path = grub_util_get_module_path (dir, mod_name); + + if (! strcmp (mod_name, "grub-symdb")) + { + free (mod_name); + free (mod_path); + continue; + } + + read_mod_syms (&mod_syms, mod_path); + + m = mod_syms.defs; + while (m) + { + struct grub_symbol_list *sym; + struct grub_named_list *n; + + sym = insert_symbol ((char *) m->name); + insert_string (&sym->defs, mod_name); + + n = sym->unds; + while (n) + { + add_update ((char *) mod_name, (char *) n->name, 1); + n = n->next; + } + + m = m->next; + } + + m = mod_syms.unds; + while (m) + { + struct grub_symbol_list *sym; + struct grub_named_list *n; + + sym = insert_symbol ((char *) m->name); + insert_string (&sym->unds, mod_name); + + n = sym->defs; + while (n) + { + add_update ((char *) n->name, (char *) mod_name, 1); + n = n->next; + } + + m = m->next; + } + + free (mod_name); + free (mod_path); + } +} + +static void +remove_mods (char *mods[]) +{ + for (; mods[0]; mods++) + { + char *mod_name; + struct grub_symbol_list *sym; + + mod_name = grub_util_get_module_name (mods[0]); + + sym = symbol_list; + while (sym) + { + struct grub_named_list *m, *n; + + m = sym->defs; + while (m) + { + int r; + + r = strcmp (mod_name, m->name); + if (! r) + break; + + if (r < 0) + { + m = 0; + break; + } + + m = m->next; + } + + n = sym->unds; + while (n) + { + if (m) + { + add_update ((char *) m->name, (char *) n->name, 0); + } + else + { + int r; + + r = strcmp (mod_name, n->name); + if (! r) + { + m = sym->defs; + while (m) + { + add_update ((char *) m->name, (char *) n->name, 0); + m = m->next; + } + + break; + } + + if (r < 0) + break; + } + + n = n->next; + } + + sym = sym->next; + } + + free (mod_name); + } +} + +static void +dump_update (void) +{ + struct grub_update_list *u; + + u = update_list; + while (u) + { + struct grub_named_list *n; + + printf ("%s:" , u->name); + n = u->add_mods; + while (n) + { + printf (" +%s", n->name); + n = n->next; + } + + n = u->del_mods; + while (n) + { + printf (" -%s", n->name); + n = n->next; + } + + printf ("\n"); + u = u->next; + } +} + +static void +update_deps (struct grub_update_list *u, char *path) +{ + struct grub_named_list *n; + int modified; + + modified = 0; + n = u->del_mods; + while (n) + { + modified |= remove_string (&u->cur_mods, (char *) n->name); + n = n->next; + } + n = u->add_mods; + while (n) + { + modified |= insert_string (&u->cur_mods, (char *) n->name); + n = n->next; + } + + if (modified) + { + char *image, *p; + struct grub_obj_header *hdr; + int size; + FILE *fp; + + image = grub_util_read_image (path); + hdr = (struct grub_obj_header *) image; + + size = hdr->mod_deps; + size += strlen (image + size) + 1; + + fp = fopen (path, "wb"); + if (! fp) + grub_util_error ("Can\'t write to %s", path); + + grub_util_write_image (image, size, fp); + + p = image; + n = u->cur_mods; + while (n) + { + strcpy (p, n->name); + p += strlen (p) + 1; + n = n->next; + } + *(p++) = 0; + + grub_util_write_image (image, p - image, fp); + + fclose (fp); + free (image); + } +} + +static void +write_moddep (struct grub_update_list *u, FILE *fp) +{ + struct grub_named_list *n; + + if (! u->cur_mods) + return; + + fprintf (fp, "%s:", u->name); + n = u->cur_mods; + while (n) + { + fprintf (fp, " %s", n->name); + n = n->next; + } + + fprintf (fp, "\n"); + free_named_list (&u->cur_mods); +} + +static void +update_moddep (char *dir) +{ + FILE *fp; + struct stat st; + char *path, *image; + struct grub_update_list *u; + + path = grub_util_get_path (dir, "moddep.lst"); + image = (stat (path, &st) == 0) ? grub_util_read_image (path) : 0; + + fp = fopen (path, "w"); + if (! fp) + grub_util_error ("Can\'t write to ", path); + + if (image) + { + char *line; + + line = image; + while (*line) + { + char *p, *c; + int n; + + n = strcspn (line, "\r\n"); + p = line; + + line += n; + while ((*line == '\r') || (*line == '\n')) + line++; + + *(p + n) = 0; + + c = strchr (p, ':'); + if (! c) + continue; + + *c = 0; + u = update_list; + while (u) + { + int r; + + r = strcmp (p, u->name); + if (! r) + break; + + if (r < 0) + { + u = 0; + break; + } + + u = u->next; + } + *c = ':'; + + if (u) + write_moddep (u, fp); + else + fprintf (fp, "%s\n", p); + } + } + + u = update_list; + while (u) + { + write_moddep (u, fp); + u = u->next; + } + + fclose (fp); + free (path); + free (image); +} + +static void +apply_update (char *dir) +{ + struct grub_update_list *u; + + u = update_list; + while (u) + { + char *mod_path; + + mod_path = grub_util_get_module_path (dir, u->name); + update_deps (u, mod_path); + free (mod_path); + u = u->next; + } + + update_moddep (dir); +} + +static struct option options[] = + { + {"directory", required_argument, 0, 'd'}, + {"test", no_argument, 0, 't'}, + {"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-symdb --help'' for more information.\n"); + else + printf ("\ +Usage: grub-symdb [OPTION]... COMMAND\n\ +\n\ +Manage the symbol database of GRUB.\n\ +\nCommands:\n\ + update MODULES add/update modules to the symbol database\n\ + remove MODULES remove modules from the symbol databsae\n\ + check check for duplicate and unresolved symbols\n\ +\n\ + -d, --directory=DIR use images and modules under DIR [default=%s]\n\ + -t, --test test mode\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\ +", GRUB_LIBDIR, PACKAGE_BUGREPORT); + + exit (status); +} + +int +main (int argc, char *argv[]) +{ + char *dir = NULL; + char *path; + int test_mode = 0; + + progname = "grub-symdb"; + + while (1) + { + int c = getopt_long (argc, argv, "d:thVv", options, 0); + + if (c == -1) + break; + else + switch (c) + { + case 'd': + if (dir) + free (dir); + + dir = xstrdup (optarg); + break; + + case 't': + test_mode++; + break; + + case 'h': + usage (0); + break; + + case 'V': + printf ("grub-mkimage (%s) %s\n", PACKAGE_NAME, PACKAGE_VERSION); + return 0; + + case 'v': + verbosity++; + break; + + default: + usage (1); + break; + } + } + + if (! dir) + dir = xstrdup (GRUB_LIBDIR); + + path = grub_util_get_path (dir, "modsym.lst"); + + argv += optind; + argc -= optind; + if (argc == 0) + grub_util_error ("No command specified."); + + read_symdb (path); + if (! strcmp (argv[0], "update")) + { + remove_mods (argv + 1); + update_mods (argv + 1, dir); + if (test_mode) + dump_update (); + else + { + apply_update (dir); + write_symdb (path); + } + } + else if (! strcmp (argv[0], "remove")) + { + remove_mods (argv + 1); + if (test_mode) + dump_update (); + else + { + apply_update (dir); + write_symdb (path); + } + } + else if (! strcmp (argv[0], "check")) + { + check_symdb (); + } + else + grub_util_error ("Unkown command %s.", argv[0]); + + free (path); + free (dir); + + return 0; +} diff --git a/util/misc.c b/util/misc.c index f615a42..955a184 100644 --- a/util/misc.c +++ b/util/misc.c @@ -143,6 +143,36 @@ xstrdup (const char *str) return dup; } +void * +xmalloc_zero (size_t size) +{ + void *p; + + p = xmalloc (size); + memset (p, 0, size); + + return p; +} + +void * +grub_list_reverse (grub_list_t head) +{ + grub_list_t prev; + + prev = 0; + while (head) + { + grub_list_t temp; + + temp = head->next; + head->next = prev; + prev = head; + head = temp; + } + + return prev; +} + char * grub_util_get_path (const char *dir, const char *file) { @@ -251,6 +281,58 @@ grub_util_write_image (const char *img, size_t size, FILE *out) grub_util_error ("write failed"); } +char * +grub_util_get_module_name (const char *str) +{ + char *base; + char *ext; + + base = strrchr (str, '/'); + if (! base) + base = (char *) str; + else + base++; + + ext = strrchr (base, '.'); + if (ext && strcmp (ext, ".mod") == 0) + { + char *name; + + name = xmalloc (ext - base + 1); + memcpy (name, base, ext - base); + name[ext - base] = '\0'; + return name; + } + + return xstrdup (base); +} + +char * +grub_util_get_module_path (const char *prefix, const char *str) +{ + char *dir; + char *base; + char *ext; + char *ret; + + ext = strrchr (str, '.'); + if (ext && strcmp (ext, ".mod") == 0) + base = xstrdup (str); + else + { + base = xmalloc (strlen (str) + 4 + 1); + sprintf (base, "%s.mod", str); + } + + dir = strchr (str, '/'); + if (dir) + return base; + + ret = grub_util_get_path (prefix, base); + free (base); + return ret; +} + void * grub_malloc (grub_size_t size) { diff --git a/util/obj.c b/util/obj.c new file mode 100644 index 0000000..2a76dd6 --- /dev/null +++ b/util/obj.c @@ -0,0 +1,634 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void +grub_obj_reverse (struct grub_util_obj *obj) +{ + obj->segments = grub_list_reverse (GRUB_AS_LIST (obj->segments)); + obj->symbols = grub_list_reverse (GRUB_AS_LIST (obj->symbols)); + obj->relocs = grub_list_reverse (GRUB_AS_LIST (obj->relocs)); +} + +void +grub_obj_sort_segments (struct grub_util_obj *obj) +{ + grub_list_t n; + int i; + + n = 0; + for (i = GRUB_OBJ_SEG_TEXT; i <= GRUB_OBJ_SEG_BSS; i++) + { + struct grub_util_obj_segment **p, *q; + + for (p = &obj->segments, q = *p; q; q = *p) + if (q->segment.type == i) + { + *p = q->next; + grub_list_push (&n, GRUB_AS_LIST (q)); + } + else + p = &(q->next); + } + + obj->segments = grub_list_reverse (n); +} + +static int +check_merge (struct grub_util_obj_segment *s1, + struct grub_util_obj_segment *s2, + int merge) +{ + if (! s2) + return 0; + + switch (merge) + { + case GRUB_OBJ_MERGE_NONE: + return (s1 == s2); + + case GRUB_OBJ_MERGE_SAME: + return (s1->segment.type == s2->segment.type); + + case GRUB_OBJ_MERGE_ALL: + return 1; + } + + return 0; +} + +void +grub_obj_merge_segments (struct grub_util_obj *obj, int merge) +{ + struct grub_util_obj_segment *p, *first; + grub_uint32_t offset; + + if (merge == GRUB_OBJ_MERGE_NONE) + return; + + first = 0; + offset = 0; + p = obj->segments; + while (p) + { + if (check_merge (p, first, merge)) + { + grub_uint32_t mask; + + if (p->segment.align > first->segment.align) + first->segment.align = p->segment.align; + + mask = p->segment.align - 1; + offset = (offset + mask) & ~mask; + p->segment.offset = offset; + offset += p->segment.size; + } + else + { + first = p; + offset = p->segment.size; + } + + p = p->next; + } +} + +void +grub_obj_reloc_symbols (struct grub_util_obj *obj, int merge) +{ + struct grub_util_obj_reloc *rel; + + for (rel = obj->relocs; rel; rel = rel->next) + { + char *addr; + + if (! rel->segment) + continue; + + if (! rel->segment->data) + grub_util_error ("can\'t relocate in .bss segment"); + + addr = rel->segment->data + rel->reloc.offset; + + if (! rel->symbol_segment) + { + struct grub_util_obj_symbol *sym; + + sym = grub_named_list_find (GRUB_AS_NAMED_LIST (obj->symbols), + rel->symbol_name); + if (sym) + { + if (rel->reloc.type & GRUB_OBJ_REL_64BIT) + *((grub_uint64_t *) addr) += sym->symbol.offset; + else + *((grub_uint32_t *) addr) += sym->symbol.offset; + + rel->symbol_segment = sym->segment; + } + } + + if (rel->symbol_segment) + { + grub_uint64_t delta; + + delta = rel->symbol_segment->segment.offset; + if ((check_merge (rel->segment, rel->symbol_segment, merge)) && + (rel->reloc.type & GRUB_OBJ_REL_ISREL)) + { + delta -= rel->segment->segment.offset + rel->reloc.offset; + rel->segment = 0; + } + + if (rel->reloc.type & GRUB_OBJ_REL_64BIT) + *((grub_uint64_t *) addr) += delta; + else + *((grub_uint32_t *) addr) += delta; + } + } +} + +struct grub_strtab +{ + struct grub_strtab *next; + char *name; + int len; +}; +typedef struct grub_strtab *grub_strtab_t; + +static int +grub_strtab_find (grub_strtab_t head, char *name) +{ + int index = 1; + int len = strlen (name); + + auto int scan_str (grub_strtab_t item); + int scan_str (grub_strtab_t item) + { + if (item->len >= len) + { + int ofs; + + ofs = item->len - len; + if (! strcmp (item->name + ofs, name)) + { + index += ofs; + return 1; + } + } + + index += item->len + 1; + return 0; + } + + if (! grub_list_iterate (GRUB_AS_LIST (head), (grub_list_hook_t) scan_str)) + index = -index; + + return index; +} + +static void +grub_strtab_insert (grub_strtab_t *head, char *name) +{ + auto int test (grub_strtab_t new_item, grub_strtab_t item); + int test (grub_strtab_t new_item, grub_strtab_t item) + { + return (strcmp (new_item->name, item->name) < 0); + } + + grub_strtab_t nitem; + + if (grub_strtab_find (*head, name) > 0) + return; + + nitem = xmalloc (sizeof (*nitem)); + nitem->name = name; + nitem->len = strlen (name); + + grub_list_insert (GRUB_AS_LIST_P (head), GRUB_AS_LIST (nitem), + (grub_list_test_t) test); +} + +#define GRUB_OBJ_HEADER_MAX 0xffff + +void +grub_obj_save (struct grub_util_obj *obj, char *mod_name, FILE *fp) +{ + char *buf, *p; + struct grub_obj_header *hdr; + struct grub_util_obj_segment *seg; + struct grub_util_obj_symbol *sym; + struct grub_util_obj_reloc *rel; + int idx; + grub_uint32_t offset, raw_size; + grub_strtab_t strtab; + int strtab_size; + int mod_name_len = strlen (mod_name); + char mod_init[mod_name_len + 11]; + char mod_fini[mod_name_len + 11]; + + if ((! obj->segments) || (obj->segments->segment.offset)) + grub_util_error ("invalid segment"); + + buf = xmalloc (GRUB_OBJ_HEADER_MAX); + hdr = (struct grub_obj_header *) buf; + + hdr->magic = GRUB_OBJ_HEADER_MAGIC; + hdr->version = GRUB_OBJ_HEADER_VERSION; + hdr->init_func = GRUB_OBJ_FUNC_NONE; + hdr->fini_func = GRUB_OBJ_FUNC_NONE; + + idx = 0; + offset = 0; + raw_size = 0; + hdr->segments[0].offset = 0; + seg = obj->segments; + while (seg) + { + struct grub_util_obj_segment *cur; + grub_uint32_t mask; + int is_last; + + cur = seg; + seg = seg->next; + + if (! cur->segment.offset) + { + if (idx >= GRUB_OBJ_SEGMENT_END) + grub_util_error ("too many segments"); + + hdr->segments[idx].type = cur->segment.type; + hdr->segments[idx].align = cur->segment.align; + hdr->segments[idx].size = 0; + raw_size = 0; + } + + cur->index = idx; + mask = cur->segment.align - 1; + hdr->segments[idx].size = (hdr->segments[idx].size + mask) & ~mask; + hdr->segments[idx].size += cur->segment.size; + + is_last = ((! seg) || (! seg->segment.offset)); + + if (cur->segment.type != GRUB_OBJ_SEG_BSS) + { + raw_size = (raw_size + mask) & ~mask; + raw_size += (is_last) ? cur->raw_size : cur->segment.size; + } + + if (is_last) + { + offset += raw_size; + idx++; + hdr->segments[idx].offset = offset; + } + } + + hdr->segments[idx].type = GRUB_OBJ_SEGMENT_END; + p = ((char *) &hdr->segments[idx]) + 5; + + sprintf (mod_init, "grub_%s_init", mod_name); + sprintf (mod_fini, "grub_%s_fini", mod_name); + + strtab = 0; + sym = obj->symbols; + while (sym) + { + if (sym->segment) + { + grub_uint32_t ofs; + + ofs = sym->symbol.offset + sym->segment->segment.offset; + if (! strcmp (sym->name, "grub_mod_init")) + { + if ((ofs >= GRUB_OBJ_HEADER_MAX) || (sym->segment->index)) + grub_util_error ("init function too far"); + + hdr->init_func = ofs; + sym->segment = 0; + } + else if (! strcmp (sym->name, "grub_mod_fini")) + { + if ((ofs >= GRUB_OBJ_HEADER_MAX) || (sym->segment->index)) + grub_util_error ("fini function too far"); + + hdr->fini_func = ofs; + sym->segment = 0; + } + else if ((! strcmp (sym->name, mod_init)) || + (! strcmp (sym->name, mod_fini))) + { + sym->segment = 0; + } + else + grub_strtab_insert (&strtab, sym->name); + } + sym = sym->next; + } + + rel = obj->relocs; + while (rel) + { + if ((rel->segment) && (! rel->symbol_segment)) + grub_strtab_insert (&strtab, rel->symbol_name); + rel = rel->next; + } + + strtab_size = - grub_strtab_find (strtab, "?"); + if (strtab_size >= GRUB_OBJ_HEADER_MAX) + grub_util_error ("string table too large"); + + hdr->symbol_table = (p - buf); + sym = obj->symbols; + while (sym) + { + if (sym->segment) + { + struct grub_obj_symbol *s; + + s = (struct grub_obj_symbol *) p; + p += sizeof (struct grub_obj_symbol); + if (p - buf >= GRUB_OBJ_HEADER_MAX) + grub_util_error ("symbol table too large"); + + s->segment = sym->segment->index; + s->name = grub_strtab_find (strtab, sym->name); + s->offset = sym->symbol.offset + sym->segment->segment.offset; + } + sym = sym->next; + } + *(p++) = GRUB_OBJ_SEGMENT_END; + if (p - buf >= GRUB_OBJ_HEADER_MAX) + grub_util_error ("symbol table too large"); + + hdr->reloc_table = (p - buf); + rel = obj->relocs; + while (rel) + { + if (rel->segment) + { + struct grub_obj_reloc_extern *r; + + r = (struct grub_obj_reloc_extern *) p; + p += ((rel->symbol_segment) ? sizeof (struct grub_obj_reloc) : + sizeof (struct grub_obj_reloc_extern)); + if (p - buf >= GRUB_OBJ_HEADER_MAX) + grub_util_error ("symbol table too large"); + + r->segment = rel->segment->index; + r->type = rel->reloc.type; + r->offset = rel->reloc.offset + rel->segment->segment.offset; + if (rel->symbol_segment) + { + r->symbol_segment = rel->symbol_segment->index; + } + else + { + r->symbol_segment = GRUB_OBJ_SEGMENT_END; + r->symbol_name = grub_strtab_find (strtab, rel->symbol_name); + } + } + rel = rel->next; + } + *(p++) = GRUB_OBJ_SEGMENT_END; + if (p - buf >= GRUB_OBJ_HEADER_MAX) + grub_util_error ("symbol table too large"); + + hdr->string_table = (p - buf); + offset = strtab_size + hdr->string_table; + idx = 0; + while (1) + { + hdr->segments[idx].offset += offset; + if (hdr->segments[idx].type == GRUB_OBJ_SEGMENT_END) + break; + idx++; + } + hdr->mod_deps = hdr->segments[idx].offset; + + grub_util_write_image (buf, hdr->string_table, fp); + free (buf); + + buf = xmalloc (strtab_size); + p = buf; + *(p++) = 0; + + while (strtab) + { + grub_strtab_t cur; + + cur = strtab; + strtab = strtab->next; + + strcpy (p, cur->name); + p += cur->len + 1; + free (cur); + } + + grub_util_write_image (buf, strtab_size, fp); + free (buf); + + buf = xmalloc_zero (256); + + seg = obj->segments; + raw_size = 0; + while (seg) + { + struct grub_util_obj_segment *cur; + + cur = seg; + seg = seg->next; + + if (! cur->segment.offset) + raw_size = 0; + + if (cur->segment.type != GRUB_OBJ_SEG_BSS) + { + grub_uint32_t mask, size; + int is_last; + + mask = cur->segment.align - 1; + size = (raw_size + mask) & ~mask; + if (size != raw_size) + { + if (size - raw_size > 256) + grub_util_error ("alignment too large"); + + grub_util_write_image (buf, size - raw_size, fp); + } + + raw_size = size; + is_last = ((! seg) || (! seg->segment.offset)); + size = (is_last) ? cur->raw_size : cur->segment.size; + grub_util_write_image (cur->data, size, fp); + raw_size += size; + } + else + break; + } + + strcpy (buf, mod_name); + grub_util_write_image (buf, mod_name_len + 2, fp); + free (buf); +} + +struct grub_util_obj * +grub_obj_load (char *image, int size, int load_data) +{ + struct grub_util_obj *obj; + struct grub_obj_header *hdr; + struct grub_obj_symbol *sym; + struct grub_obj_reloc_extern *rel; + char *strtab; + struct grub_util_obj_segment **segments; + int i; + + hdr = (struct grub_obj_header *) image; + + if ((size <= (int) sizeof (*hdr)) || (hdr->magic != GRUB_OBJ_HEADER_MAGIC)) + grub_util_error ("invalid module file"); + + if (hdr->version != GRUB_OBJ_HEADER_VERSION) + grub_util_error ("version number not match"); + + obj = xmalloc_zero (sizeof (*obj)); + segments = xmalloc_zero (256 * sizeof (segments[0])); + + for (i = 0; hdr->segments[i].type != GRUB_OBJ_SEGMENT_END; i++) + { + struct grub_util_obj_segment *p; + + p = xmalloc_zero (sizeof (*p)); + p->segment.type = hdr->segments[i].type; + p->segment.align = hdr->segments[i].align; + p->segment.size = hdr->segments[i].size; + p->file_off = hdr->segments[i].offset; + p->raw_size = hdr->segments[i + 1].offset - p->file_off; + p->index = i; + + if ((p->raw_size) && (load_data)) + { + p->data = xmalloc_zero (p->segment.size); + memcpy (p->data, image + p->file_off, p->raw_size); + } + + segments[i] = p; + grub_list_push (GRUB_AS_LIST_P (&obj->segments), GRUB_AS_LIST (p)); + } + + obj->mod_attr = hdr->segments[i].offset; + + strtab = image + hdr->string_table; + for (sym = (struct grub_obj_symbol *) (image + hdr->symbol_table); + sym->segment != GRUB_OBJ_SEGMENT_END; sym++) + { + struct grub_util_obj_symbol *p; + + p = xmalloc_zero (sizeof (*p)); + p->name = xstrdup (strtab + sym->name); + p->segment = segments[sym->segment]; + p->symbol.offset = sym->offset; + + grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (p)); + } + + for (rel = (struct grub_obj_reloc_extern *) (image + hdr->reloc_table); + rel->segment != GRUB_OBJ_SEGMENT_END;) + { + struct grub_util_obj_reloc *p; + + p = xmalloc_zero (sizeof (*p)); + p->segment = segments[rel->segment]; + p->reloc.type = rel->type; + p->reloc.offset = rel->offset; + if (rel->symbol_segment == GRUB_OBJ_SEGMENT_END) + { + p->symbol_name = xstrdup (strtab + rel->symbol_name); + rel++; + } + else + { + p->symbol_segment = segments[rel->symbol_segment]; + rel = (struct grub_obj_reloc_extern *) + ((char *) rel + sizeof (struct grub_obj_reloc)); + } + + grub_list_push (GRUB_AS_LIST_P (&obj->relocs), GRUB_AS_LIST (p)); + } + + free (segments); + grub_obj_reverse (obj); + return obj; +} + +void +grub_obj_free (struct grub_util_obj *obj) +{ + struct grub_util_obj_segment *seg; + struct grub_util_obj_symbol *sym; + struct grub_util_obj_reloc *rel; + + seg = obj->segments; + while (seg) + { + struct grub_util_obj_segment *p; + + p = seg; + seg = seg->next; + + if (p->data) + free (p->data); + + free (p); + } + + sym = obj->symbols; + while (sym) + { + struct grub_util_obj_symbol *p; + + p = sym; + sym = sym->next; + + if (p->name) + free (p->name); + + free (p); + } + + rel = obj->relocs; + while (sym) + { + struct grub_util_obj_reloc *p; + + p = rel; + rel = rel->next; + + if (p->symbol_name) + free (p->symbol_name); + + free (p); + } +} diff --git a/util/obj_dump.c b/util/obj_dump.c new file mode 100644 index 0000000..4bfab89 --- /dev/null +++ b/util/obj_dump.c @@ -0,0 +1,140 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static char * +get_segment_name (int type) +{ + switch (type) + { + case GRUB_OBJ_SEG_TEXT: + return ".text"; + + case GRUB_OBJ_SEG_DATA: + return ".data"; + + case GRUB_OBJ_SEG_RDATA: + return ".rdata"; + + case GRUB_OBJ_SEG_BSS: + return ".bss"; + } + + return "unknown"; +} + +static char * +get_reloc_type (int type) +{ + switch (type) + { + case GRUB_OBJ_REL_DIR32: + return "dir32"; + + case GRUB_OBJ_REL_REL32: + return "rel32"; + + case GRUB_OBJ_REL_DIR64: + return "dir64"; + + case GRUB_OBJ_REL_REL64: + return "rel64"; + } + + return "unknown"; +} + +static int +dump_segments_hook (struct grub_util_obj_segment *obj) +{ + printf ("%-10s%08x %08x %08x %08x %d\n", + get_segment_name (obj->segment.type), + obj->segment.offset, obj->segment.size, obj->raw_size, + obj->file_off, obj->segment.align); + + return 0; +} + +void +grub_obj_dump_segments (struct grub_util_obj *obj) +{ + printf ("Segments:\n" + "Segment Offset Size Raw Size File Off Align\n"); + grub_list_iterate (GRUB_AS_LIST (obj->segments), + (grub_list_hook_t) dump_segments_hook); +} + +static int +dump_symbols_hook (struct grub_util_obj_symbol *obj) +{ + if (obj->segment) + printf ("%-10s%08x %s\n", + get_segment_name (obj->segment->segment.type), + obj->symbol.offset + obj->segment->segment.offset, obj->name); + + return 0; +} + +void +grub_obj_dump_symbols (struct grub_util_obj *obj) +{ + printf ("Symbols:\n" + "Segment Offset Name\n"); + grub_list_iterate (GRUB_AS_LIST (obj->symbols), + (grub_list_hook_t) dump_symbols_hook); +} + +static int +dump_reloc_hook (struct grub_util_obj_reloc *obj) +{ + if (obj->segment) + { + grub_uint32_t value; + + if (obj->segment->data) + value = *((grub_uint32_t *) (obj->segment->data + obj->reloc.offset)); + else + value = 0; + + printf ("%-10s%08x %08x %-10s%s\n", + get_segment_name (obj->segment->segment.type), + obj->reloc.offset + obj->segment->segment.offset, value, + get_reloc_type (obj->reloc.type), + ((! obj->symbol_segment) ? obj->symbol_name : + get_segment_name (obj->symbol_segment->segment.type))); + } + + return 0; +} + +void +grub_obj_dump_relocs (struct grub_util_obj *obj) +{ + printf ("Relocs:\n" + "Segment Offset Value Type Name\n"); + grub_list_iterate (GRUB_AS_LIST (obj->relocs), + (grub_list_hook_t) dump_reloc_hook); +} diff --git a/util/obj_elf.c b/util/obj_elf.c new file mode 100644 index 0000000..4056c06 --- /dev/null +++ b/util/obj_elf.c @@ -0,0 +1,365 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> +#include <grub/elf.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#if GRUB_TARGET_SIZEOF_VOID_P == 4 + +#define grub_target_to_host grub_target_to_host32 +#define grub_host_to_target grub_host_to_target32 + +#elif GRUB_TARGET_SIZEOF_VOID_P == 8 + +#define grub_target_to_host grub_target_to_host64 +#define grub_host_to_target grub_host_to_target64 + +#endif + +static int +check_elf_header (Elf_Ehdr *e, size_t size) +{ + if (size < sizeof (*e) + || e->e_ident[EI_MAG0] != ELFMAG0 + || e->e_ident[EI_MAG1] != ELFMAG1 + || e->e_ident[EI_MAG2] != ELFMAG2 + || e->e_ident[EI_MAG3] != ELFMAG3 + || e->e_ident[EI_VERSION] != EV_CURRENT + || e->e_version != EV_CURRENT) + return 0; + + return 1; +} + +/* Return the symbol table section, if any. */ +static Elf_Shdr * +find_symtab_section (Elf_Shdr *sections, + Elf_Half section_entsize, Elf_Half num_sections) +{ + int i; + Elf_Shdr *s; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if (s->sh_type == grub_cpu_to_le32 (SHT_SYMTAB)) + return s; + + return 0; +} + +static void +add_segments (struct grub_util_obj *obj, + struct grub_util_obj_segment **segments, + char *image, + Elf_Shdr *sections, int section_entsize, int num_sections) +{ + Elf_Shdr *s; + int i; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + { + int type; + + if ((s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)) + == grub_cpu_to_le32 (SHF_EXECINSTR | SHF_ALLOC)) + type = GRUB_OBJ_SEG_TEXT; + else if (s->sh_flags & grub_cpu_to_le32 (SHF_ALLOC) + && ! (s->sh_flags & grub_cpu_to_le32 (SHF_EXECINSTR))) + { + if (! (s->sh_flags & grub_cpu_to_le32 (SHF_WRITE))) + type = GRUB_OBJ_SEG_RDATA; + else if (s->sh_type == grub_cpu_to_le32 (SHT_NOBITS)) + type = GRUB_OBJ_SEG_BSS; + else + type = GRUB_OBJ_SEG_DATA; + } + else + type = 0; + + + if ((type) && ((type == GRUB_OBJ_SEG_BSS) || (s->sh_size))) + { + struct grub_util_obj_segment *p; + + p = xmalloc_zero (sizeof (*p)); + p->segment.type = type; + p->segment.align = grub_le_to_cpu32 (s->sh_addralign); + p->segment.size = grub_le_to_cpu32 (s->sh_size); + segments[i] = p; + + if (type == GRUB_OBJ_SEG_BSS) + { + p->raw_size = p->segment.size; + if (segments[0]) + grub_util_error ("mutiple .bss segment"); + segments[0] = p; + } + else + { + p->raw_size = p->segment.size; + p->data = xmalloc (p->raw_size); + memcpy (p->data, image + grub_le_to_cpu32 (s->sh_offset), + p->raw_size); + segments[i] = p; + grub_list_push (GRUB_AS_LIST_P (&obj->segments), + GRUB_AS_LIST (p)); + + } + } + } + + if (! segments[0]) + grub_util_error ("no .bss segment"); +} + +static void +add_symbols (struct grub_util_obj *obj, + struct grub_util_obj_segment **segments, + char *image, + Elf_Shdr *sections, int section_entsize, int num_sections) +{ + int i; + Elf_Shdr *symtab_section, *str_sec; + Elf_Sym *sym; + int num_syms, sym_size; + char *strtab; + + symtab_section = find_symtab_section (sections, + section_entsize, num_sections); + sym = (Elf_Sym *) (image + grub_target_to_host (symtab_section->sh_offset)); + sym_size = grub_target_to_host32 (symtab_section->sh_entsize); + num_syms = grub_target_to_host32 (symtab_section->sh_size) / sym_size; + str_sec = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (symtab_section->sh_link) + * section_entsize)); + strtab = image + grub_target_to_host32 (str_sec->sh_offset); + + for (i = 0; i < num_syms; + i++, sym = (Elf_Sym *) ((char *) sym + sym_size)) + { + Elf_Section index; + char *name; + + name = strtab + grub_target_to_host32 (sym->st_name); + + if ((ELF_ST_BIND (sym->st_info) == STB_LOCAL) && + (strcmp (name, "grub_mod_init")) && + (strcmp (name, "grub_mod_fini"))) + continue; + + index = grub_target_to_host16 (sym->st_shndx); + + if (index == STN_UNDEF) + continue; + + if (index == STN_COMMON) + { + if (! sym->st_value) + continue; + index = 0; + } + + if ((index < num_sections) && (segments[index])) + { + struct grub_util_obj_symbol *p; + + p = xmalloc_zero (sizeof (*p)); + p->name = xstrdup (name); + p->segment = segments[index]; + if (! index) + { + p->symbol.offset = p->segment->segment.size; + p->segment->segment.size += grub_target_to_host (sym->st_value); + } + else + p->symbol.offset = grub_target_to_host (sym->st_value); + + grub_list_push (GRUB_AS_LIST_P (&obj->symbols), + GRUB_AS_LIST (p)); + } + } +} + +static void +add_relocs (struct grub_util_obj *obj, + struct grub_util_obj_segment **segments, + char *image, + Elf_Shdr *sections, int section_entsize, int num_sections) +{ + int i; + Elf_Shdr *s; + + for (i = 0, s = sections; + i < num_sections; + i++, s = (Elf_Shdr *) ((char *) s + section_entsize)) + if ((s->sh_type == grub_cpu_to_le32 (SHT_REL)) || + (s->sh_type == grub_cpu_to_le32 (SHT_RELA))) + { + Elf_Rela *r; + Elf_Shdr *sym_sec, *str_sec; + int sym_size; + char *strtab; + Elf_Word r_size, num_rs, j; + Elf_Word target_index; + + sym_sec = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (s->sh_link) + * section_entsize)); + sym_size = grub_target_to_host32 (sym_sec->sh_entsize); + + str_sec = (Elf_Shdr *) ((char *) sections + + (grub_target_to_host32 (sym_sec->sh_link) + * section_entsize)); + strtab = image + grub_target_to_host32 (str_sec->sh_offset); + + target_index = grub_target_to_host32 (s->sh_info); + if (! segments[target_index]) + continue; + + r_size = grub_target_to_host32 (s->sh_entsize); + num_rs = grub_target_to_host32 (s->sh_size) / r_size; + + r = (Elf_Rela *) (image + grub_target_to_host32 (s->sh_offset)); + for (j = 0; + j < num_rs; + j++, r = (Elf_Rela *) ((char *) r + r_size)) + { + struct grub_util_obj_reloc *p; + Elf_Addr info, offset; + Elf_Sym *sym; + int sym_idx; + char *addr; + int type; + + offset = grub_target_to_host (r->r_offset); + if (! segments[target_index]->data) + grub_util_error ("can\'t relocate in .bss segment"); + + addr = segments[target_index]->data + offset; + info = grub_target_to_host (r->r_info); + + type = -1; + switch (ELF_R_TYPE (info)) + { + case R_386_NONE: + break; + + case R_386_32: + type = GRUB_OBJ_REL_DIR32; + break; + + case R_386_PC32: + type = GRUB_OBJ_REL_REL32; + break; + + default: + grub_util_error ("unknown relocation type %d", + ELF_R_TYPE (info)); + } + + if (type < 0) + continue; + + if ((grub_target_to_host32 (s->sh_type) == SHT_RELA) && + (r->r_addend)) + { + if (type & GRUB_OBJ_REL_64BIT) + *((grub_uint64_t *) addr) += r->r_addend; + else + *((grub_uint32_t *) addr) += r->r_addend; + } + + p = xmalloc_zero (sizeof (*p)); + p->segment = segments[target_index]; + p->reloc.type = type; + p->reloc.offset = offset; + + sym = (Elf_Sym *) (image + + grub_target_to_host32 (sym_sec->sh_offset) + + (ELF_R_SYM (info) * sym_size)); + sym_idx = grub_target_to_host16 (sym->st_shndx); + if (sym_idx == STN_ABS) + grub_util_error ("can\'t relocate absolute symbol"); + + if ((sym_idx != STN_UNDEF) && (sym_idx != STN_COMMON)) + { + if (! segments[sym_idx]) + grub_util_error ("no symbol segment"); + + p->symbol_segment = segments[sym_idx]; + } + p->symbol_name = xstrdup (strtab + + grub_target_to_host32 (sym->st_name)); + + if (type & GRUB_OBJ_REL_64BIT) + *((grub_uint64_t *) addr) += grub_target_to_host (sym->st_value); + else + *((grub_uint32_t *) addr) += grub_target_to_host (sym->st_value); + + grub_list_push (GRUB_AS_LIST_P (&obj->relocs), + GRUB_AS_LIST (p)); + } + } +} + +int +elf_add_file (struct grub_util_obj *obj, char *image, int size) +{ + Elf_Ehdr *e; + Elf_Shdr *sections; + Elf_Off section_offset; + Elf_Half section_entsize; + Elf_Half num_sections; + struct grub_util_obj_segment **segments; + + e = (Elf_Ehdr *) image; + if (! check_elf_header (e, size)) + return 0; + + section_offset = grub_target_to_host (e->e_shoff); + section_entsize = grub_target_to_host16 (e->e_shentsize); + num_sections = grub_target_to_host16 (e->e_shnum); + + if (size < (int) (section_offset + section_entsize * num_sections)) + grub_util_error ("invalid ELF format"); + + sections = (Elf_Shdr *) (image + section_offset); + segments = xmalloc_zero (num_sections * sizeof (segments[0])); + add_segments (obj, segments, image, sections, section_entsize, num_sections); + add_symbols (obj, segments, image, sections, section_entsize, num_sections); + add_relocs (obj, segments, image, sections, section_entsize, num_sections); + + if (segments[0]->segment.size) + grub_list_push (GRUB_AS_LIST_P (&obj->segments), + GRUB_AS_LIST (segments[0])); + else + free (segments[0]); + + free (segments); + return 1; +} diff --git a/util/obj_pe.c b/util/obj_pe.c new file mode 100644 index 0000000..e168fb1 --- /dev/null +++ b/util/obj_pe.c @@ -0,0 +1,272 @@ +/* + * GRUB -- GRand Unified Bootloader + * Copyright (C) 2009 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/obj.h> +#include <grub/util/misc.h> +#include <grub/efi/pe32.h> + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +static void +add_segments (struct grub_util_obj *obj, + struct grub_util_obj_segment **segments, + char *image, + struct grub_pe32_section_table *pe_shdr, int num_secs) +{ + int i; + + for (i = 0; i < num_secs; i++, pe_shdr++) + { + int type; + + if (! strcmp (pe_shdr->name, ".text")) + type = GRUB_OBJ_SEG_TEXT; + else if (! strcmp (pe_shdr->name, ".data")) + type = GRUB_OBJ_SEG_DATA; + else if (! strcmp (pe_shdr->name, ".rdata")) + type = GRUB_OBJ_SEG_RDATA; + else if (! strcmp (pe_shdr->name, ".bss")) + type = GRUB_OBJ_SEG_BSS; + else + type = 0; + + if ((type) && ((type == GRUB_OBJ_SEG_BSS) || (pe_shdr->raw_data_size))) + { + struct grub_util_obj_segment *p; + + p = xmalloc_zero (sizeof (*p)); + p->segment.type = type; + p->segment.align = 1 << (((pe_shdr->characteristics >> + GRUB_PE32_SCN_ALIGN_SHIFT) & + GRUB_PE32_SCN_ALIGN_MASK) - 1); + p->segment.size = pe_shdr->raw_data_size; + segments[i + 1] = p; + + if (type == GRUB_OBJ_SEG_BSS) + { + p->raw_size = p->segment.size; + if (segments[0]) + grub_util_error ("mutiple .bss segment"); + segments[0] = p; + } + else + { + p->raw_size = p->segment.size; + p->data = xmalloc (pe_shdr->raw_data_size); + memcpy (p->data, image + pe_shdr->raw_data_offset, + pe_shdr->raw_data_size); + + grub_list_push (GRUB_AS_LIST_P (&obj->segments), + GRUB_AS_LIST (p)); + } + } + } + + if (! segments[0]) + grub_util_error ("no .bss segment"); +} + +static char * +get_symbol_name (struct grub_pe32_symbol *pe_sym, char *pe_strtab) +{ + char short_name[9]; + char *name; + + if (pe_sym->long_name[0]) + { + strncpy (short_name, pe_sym->short_name, 8); + short_name[8] = 0; + name = short_name; + } + else + name = pe_strtab + pe_sym->long_name[1]; + + if (*name == '_') + name++; + + return xstrdup (name); +} + +static void +add_symbols (struct grub_util_obj *obj, + struct grub_util_obj_segment **segments, + struct grub_pe32_symbol *pe_symtab, int num_syms, + char *pe_strtab) +{ + int i; + + for (i = 0; i < num_syms; + i += pe_symtab->num_aux + 1, pe_symtab += pe_symtab->num_aux + 1) + { + struct grub_util_obj_symbol *p; + char *name; + + name = get_symbol_name (pe_symtab, pe_strtab); + + if ((pe_symtab->section > num_syms) || + (! segments[pe_symtab->section]) || + ((pe_symtab->storage_class != GRUB_PE32_SYM_CLASS_EXTERNAL) && + (strcmp (name, "grub_mod_init")) && + (strcmp (name, "grub_mod_fini")))) + { + free (name); + continue; + } + + if ((! pe_symtab->section) && (! pe_symtab->value)) + { + free (name); + continue; + } + + p = xmalloc_zero (sizeof (*p)); + p->name = name; + p->segment = segments[pe_symtab->section]; + + if (! pe_symtab->section) + { + p->symbol.offset = p->segment->segment.size; + p->segment->segment.size += pe_symtab->value; + } + else + p->symbol.offset = pe_symtab->value; + + grub_list_push (GRUB_AS_LIST_P (&obj->symbols), GRUB_AS_LIST (p)); + } +} + +static void +add_relocs (struct grub_util_obj *obj, + struct grub_util_obj_segment **segments, + char *image, + struct grub_pe32_section_table *pe_sec, int num_secs, + struct grub_pe32_symbol *pe_symtab, int num_syms, + char *pe_strtab) +{ + int i; + + for (i = 0; i < num_secs; i++, pe_sec++) + { + struct grub_pe32_reloc *pe_rel; + int j; + + if (! segments[i + 1]) + continue; + + pe_rel = (struct grub_pe32_reloc *) (image + pe_sec->relocations_offset); + for (j = 0; j < pe_sec->num_relocations; j++, pe_rel++) + { + struct grub_util_obj_reloc *p; + struct grub_pe32_symbol *pe_sym; + int type; + + pe_sym = pe_symtab + pe_rel->symtab_index; + + if (((int) pe_rel->symtab_index >= num_syms) || + ((pe_sym->section) && (! segments[pe_sym->section]))) + grub_util_error ("invalid symbol index"); + + if (pe_rel->type == GRUB_PE32_REL_I386_DIR32) + type = GRUB_OBJ_REL_DIR32; + else if (pe_rel->type == GRUB_PE32_REL_I386_REL32) + type = GRUB_OBJ_REL_REL32; + else + grub_util_error ("unknown pe relocation type %d\n", pe_rel->type); + + p = xmalloc_zero (sizeof (*p)); + p->segment = segments[i + 1]; + p->reloc.type = type; + p->reloc.offset = pe_rel->offset - pe_sec->virtual_address; + if (pe_sym->section) + p->symbol_segment = segments[pe_sym->section]; + p->symbol_name = get_symbol_name (pe_sym, pe_strtab); + + if (! p->segment->data) + grub_util_error ("can\'t relocate in .bss segment"); + + if (type & GRUB_OBJ_REL_ISREL) + { + grub_uint8_t code; + grub_uint32_t *addr; + + addr = (grub_uint32_t *) (p->segment->data + p->reloc.offset); + code = p->segment->data[p->reloc.offset - 1]; + if (((code != 0xe8) && (code != 0xe9)) || (*addr)) + grub_util_error ("invalid relocation (%x %x)", code, *addr); + + if (p->reloc.type & GRUB_OBJ_REL_64BIT) + *((grub_uint64_t *) addr) = -4; + else + *((grub_uint32_t *) addr) = -4; + } + + grub_list_push (GRUB_AS_LIST_P (&obj->relocs), GRUB_AS_LIST (p)); + } + } +} + +static int +check_pe_header (struct grub_pe32_coff_header *c, size_t size) +{ + if ((size < sizeof (*c) || + (grub_le_to_cpu16 (c->machine) != GRUB_PE32_MACHINE_I386))) + return 0; + + return 1; +} + +int +pe_add_file (struct grub_util_obj *obj, char *image, int size) +{ + struct grub_pe32_coff_header *pe_chdr; + struct grub_pe32_section_table *pe_shdr; + struct grub_pe32_symbol *pe_symtab; + int num_secs, num_syms; + char *pe_strtab; + struct grub_util_obj_segment **segments; + + pe_chdr = (struct grub_pe32_coff_header *) image; + if (! check_pe_header (pe_chdr, size)) + return 0; + + pe_shdr = (struct grub_pe32_section_table *) (pe_chdr + 1); + num_secs = pe_chdr->num_sections; + segments = xmalloc_zero ((num_secs + 1) * sizeof (segments[0])); + add_segments (obj, segments, image, pe_shdr, num_secs); + + pe_symtab = (struct grub_pe32_symbol *) (image + pe_chdr->symtab_offset); + num_syms = pe_chdr->num_symbols; + pe_strtab = (char *) (pe_symtab + pe_chdr->num_symbols); + + add_symbols (obj, segments, pe_symtab, num_syms, pe_strtab); + add_relocs (obj, segments, image, pe_shdr, num_secs, + pe_symtab, num_syms, pe_strtab); + + if (segments[0]->segment.size) + grub_list_push (GRUB_AS_LIST_P (&obj->segments), + GRUB_AS_LIST (segments[0])); + else + free (segments[0]); + + free (segments); + return 1; +} diff --git a/util/resolve.c b/util/resolve.c index 8b33beb..32c9e82 100644 --- a/util/resolve.c +++ b/util/resolve.c @@ -126,58 +126,6 @@ read_dep_list (FILE *fp) return dep_list; } -static char * -get_module_name (const char *str) -{ - char *base; - char *ext; - - base = strrchr (str, '/'); - if (! base) - base = (char *) str; - else - base++; - - ext = strrchr (base, '.'); - if (ext && strcmp (ext, ".mod") == 0) - { - char *name; - - name = xmalloc (ext - base + 1); - memcpy (name, base, ext - base); - name[ext - base] = '\0'; - return name; - } - - return xstrdup (base); -} - -static char * -get_module_path (const char *prefix, const char *str) -{ - char *dir; - char *base; - char *ext; - char *ret; - - ext = strrchr (str, '.'); - if (ext && strcmp (ext, ".mod") == 0) - base = xstrdup (str); - else - { - base = xmalloc (strlen (str) + 4 + 1); - sprintf (base, "%s.mod", str); - } - - dir = strchr (str, '/'); - if (dir) - return base; - - ret = grub_util_get_path (prefix, base); - free (base); - return ret; -} - static void add_module (const char *dir, struct dep_list *dep_list, @@ -190,7 +138,7 @@ add_module (const char *dir, struct mod_list *mod; struct dep_list *dep; - mod_name = get_module_name (name); + mod_name = grub_util_get_module_name (name); /* Check if the module has already been added. */ for (mod = *mod_head; mod; mod = mod->next) @@ -218,7 +166,7 @@ add_module (const char *dir, /* Add this path. */ path = (struct grub_util_path_list *) xmalloc (sizeof (*path)); - path->name = get_module_path (dir, name); + path->name = grub_util_get_module_path (dir, name); path->next = *path_head; *path_head = path; } ^ permalink raw reply related [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-14 15:49 [PATCH] New object format Bean 2009-07-14 17:57 ` please stop this Robert Millan 2009-07-14 21:02 ` [PATCH] New object format Bean @ 2009-07-19 1:52 ` Isaac Dupree 2009-07-19 10:03 ` Bean 2 siblings, 1 reply; 25+ messages in thread From: Isaac Dupree @ 2009-07-19 1:52 UTC (permalink / raw) To: The development of GRUB 2 Bean wrote: > Hi, > > This patch implement a new object format, the advantages are: > > Reduce size dramatically, some result: > > Size of all modules: > > original: 645575 > new: 519093 [I thought I sent this message a few days ago, guess not?] What are the compressed-size comparisons? -Isaac ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-19 1:52 ` Isaac Dupree @ 2009-07-19 10:03 ` Bean 2009-07-21 20:55 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-19 10:03 UTC (permalink / raw) To: The development of GRUB 2 On Sun, Jul 19, 2009 at 9:52 AM, Isaac Dupree<ml@isaac.cedarswampstudios.org> wrote: > Bean wrote: >> >> Hi, >> >> This patch implement a new object format, the advantages are: >> >> Reduce size dramatically, some result: >> >> Size of all modules: >> >> original: 645575 >> new: 519093 > > [I thought I sent this message a few days ago, guess not?] > > What are the compressed-size comparisons? Hi, An example (reiserfs on lvm on raid) grub-mkimage -d . -o core.img pc biosdisk reiserfs lvm raid mdraid raid5rec raid6rec old: 33248 new: 31939 -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-19 10:03 ` Bean @ 2009-07-21 20:55 ` Bean 2009-07-22 11:12 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-21 20:55 UTC (permalink / raw) To: The development of GRUB 2 Update: Various bug fix Support EFI platform, i386-efi: both elf and pe are ok x86_64-efi: elf ok BTW, it's very closed to build x86_64-efi using pe64. In order to build it, you need to download mingw-w64, and link x86_64-w64-mingw32-gcc.exe to x86_64-gcc.exe, etc, then: ./configure CC=x86_64-gcc --with-platform=efi --target=x86_64 compile ok, grub-mkimage also generate the efi image, but it crash when loading. The source code have been pushed to my git repository: http://github.com/bean123/grub lib branch -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-21 20:55 ` Bean @ 2009-07-22 11:12 ` Bean 2009-07-22 11:47 ` Javier Martín 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-22 11:12 UTC (permalink / raw) To: The development of GRUB 2 Update: Now fully support mingw-w64, the configure line is this: ./configure --with-platform=efi --target=x86_64-w64-mingw32 Compile ok in both XP64 and linux with mingw-w64 cross compiler, the generated grub.efi tested all right on macbook. Fix some wrong assumption in types.h and efi header files. For example, grub_efi_uint_t is defined as unsigned long, but it should be grub_uint64_t in 64-bit EFI, this problem won't show previously as unsigned long is 64-bit in elf64 gcc, but it's 32-bit in mingw-w64 gcc. Fix a bug in grub-symdb. New code updated to http://github.com/bean123/grub. On Wed, Jul 22, 2009 at 4:55 AM, Bean<bean123ch@gmail.com> wrote: > Update: > > Various bug fix > Support EFI platform, > i386-efi: both elf and pe are ok > x86_64-efi: elf ok > > BTW, it's very closed to build x86_64-efi using pe64. In order to > build it, you need to download mingw-w64, and link > x86_64-w64-mingw32-gcc.exe to x86_64-gcc.exe, etc, then: > > ./configure CC=x86_64-gcc --with-platform=efi --target=x86_64 > > compile ok, grub-mkimage also generate the efi image, but it crash when loading. > > The source code have been pushed to my git repository: > > http://github.com/bean123/grub > > lib branch > -- > Bean > -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-22 11:12 ` Bean @ 2009-07-22 11:47 ` Javier Martín 2009-07-22 13:34 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Javier Martín @ 2009-07-22 11:47 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 989 bytes --] El mié, 22-07-2009 a las 19:12 +0800, Bean escribió: > Fix some wrong assumption in types.h and efi header files. For > example, grub_efi_uint_t is defined as unsigned long, but it should be > grub_uint64_t in 64-bit EFI, this problem won't show previously as > unsigned long is 64-bit in elf64 gcc, but it's 32-bit in mingw-w64 > gcc. I think you haven't corrected _all_ such assumptions. For example, in your grub/types.h: #if GRUB_CPU_SIZEOF_VOID_P == 8 # define GRUB_ULONG_MAX 18446744073709551615UL # define GRUB_LONG_MAX 9223372036854775807L # define GRUB_LONG_MIN (-9223372036854775807L - 1) #else # define GRUB_ULONG_MAX 4294967295UL # define GRUB_LONG_MAX 2147483647L # define GRUB_LONG_MIN (-2147483647L - 1) #endif In mingw64, sizeof(void*) = 8, but ULONG_MAX = 2^32-1. grub/machine/types.h defines a GRUB_TARGET_SIZEOF_LONG that might be suitable for this. Or am I mixing "target" with "host"? -- -- Lazy, Oblivious, Recurrent Disaster -- Habbit [-- Attachment #2: Esto es una parte de mensaje firmado digitalmente --] [-- Type: application/pgp-signature, Size: 835 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-22 11:47 ` Javier Martín @ 2009-07-22 13:34 ` Bean 2009-07-22 13:42 ` Javier Martín 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-22 13:34 UTC (permalink / raw) To: The development of GRUB 2 2009/7/22 Javier Martín <lordhabbit@gmail.com>: > El mié, 22-07-2009 a las 19:12 +0800, Bean escribió: >> Fix some wrong assumption in types.h and efi header files. For >> example, grub_efi_uint_t is defined as unsigned long, but it should be >> grub_uint64_t in 64-bit EFI, this problem won't show previously as >> unsigned long is 64-bit in elf64 gcc, but it's 32-bit in mingw-w64 >> gcc. > I think you haven't corrected _all_ such assumptions. For example, in > your grub/types.h: > > #if GRUB_CPU_SIZEOF_VOID_P == 8 > # define GRUB_ULONG_MAX 18446744073709551615UL > # define GRUB_LONG_MAX 9223372036854775807L > # define GRUB_LONG_MIN (-9223372036854775807L - 1) > #else > # define GRUB_ULONG_MAX 4294967295UL > # define GRUB_LONG_MAX 2147483647L > # define GRUB_LONG_MIN (-2147483647L - 1) > #endif > > In mingw64, sizeof(void*) = 8, but ULONG_MAX = 2^32-1. > grub/machine/types.h defines a GRUB_TARGET_SIZEOF_LONG that might be > suitable for this. Or am I mixing "target" with "host"? Hi, Oh, thanks for the note. In fact, we can use GRUB_CPU_SIZEOF_LONG, its value is GRUB_TARGET_SIZEOF_LONG when building target, and SIZEOF_LONG when building utilities. For example, I now define grub_uint64_t as: #if GRUB_CPU_SIZEOF_LONG == 8 typedef unsigned long grub_uint64_t; #else typedef unsigned long long grub_uint64_t; #endif The previous definition is not correct: #if GRUB_CPU_SIZEOF_VOID_P == 8 typedef unsigned long grub_uint64_t; #else typedef unsigned long long grub_uint64_t; #endif As GRUB_CPU_SIZEOF_LONG doesn't necessary equal to GRUB_CPU_SIZEOF_VOID_P. (It actually avoid this by generating an #errror message when GRUB_CPU_SIZEOF_VOID_P != GRUB_CPU_SIZEOF_LONG). -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-22 13:34 ` Bean @ 2009-07-22 13:42 ` Javier Martín 2009-07-22 14:52 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Javier Martín @ 2009-07-22 13:42 UTC (permalink / raw) To: The development of GRUB 2 [-- Attachment #1: Type: text/plain, Size: 2028 bytes --] El mié, 22-07-2009 a las 21:34 +0800, Bean escribió: > 2009/7/22 Javier Martín <lordhabbit@gmail.com>: > > El mié, 22-07-2009 a las 19:12 +0800, Bean escribió: > >> Fix some wrong assumption in types.h and efi header files. For > >> example, grub_efi_uint_t is defined as unsigned long, but it should be > >> grub_uint64_t in 64-bit EFI, this problem won't show previously as > >> unsigned long is 64-bit in elf64 gcc, but it's 32-bit in mingw-w64 > >> gcc. > > I think you haven't corrected _all_ such assumptions. For example, in > > your grub/types.h: > > > > #if GRUB_CPU_SIZEOF_VOID_P == 8 > > # define GRUB_ULONG_MAX 18446744073709551615UL > > # define GRUB_LONG_MAX 9223372036854775807L > > # define GRUB_LONG_MIN (-9223372036854775807L - 1) > > #else > > # define GRUB_ULONG_MAX 4294967295UL > > # define GRUB_LONG_MAX 2147483647L > > # define GRUB_LONG_MIN (-2147483647L - 1) > > #endif > > > > In mingw64, sizeof(void*) = 8, but ULONG_MAX = 2^32-1. > > grub/machine/types.h defines a GRUB_TARGET_SIZEOF_LONG that might be > > suitable for this. Or am I mixing "target" with "host"? > > Hi, > > Oh, thanks for the note. In fact, we can use GRUB_CPU_SIZEOF_LONG, > its value is GRUB_TARGET_SIZEOF_LONG when building target, and > SIZEOF_LONG when building utilities. Wonderful idea. I'm researching this for a possible implementation of a GRUB equivalent to the C99 fixed-length integers print specifiers like PRIx64. It would most likely go into <grub/types.h>, so I'm paying special attention to anyone working on that file. > As GRUB_CPU_SIZEOF_LONG doesn't necessary equal to > GRUB_CPU_SIZEOF_VOID_P. (It actually avoid this by generating an > #errror message when GRUB_CPU_SIZEOF_VOID_P != GRUB_CPU_SIZEOF_LONG). I think you lost me here. This check is in the trunk GRUB, but not in your "lib" branch, and actually it would make it impossible to build on mingw64, where void* is 64-bit and long is 32-bit. -- -- Lazy, Oblivious, Recurrent Disaster -- Habbit [-- Attachment #2: Esto es una parte de mensaje firmado digitalmente --] [-- Type: application/pgp-signature, Size: 835 bytes --] ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-22 13:42 ` Javier Martín @ 2009-07-22 14:52 ` Bean 2009-07-25 19:33 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-22 14:52 UTC (permalink / raw) To: The development of GRUB 2 Hi, >> Oh, thanks for the note. In fact, we can use GRUB_CPU_SIZEOF_LONG, >> its value is GRUB_TARGET_SIZEOF_LONG when building target, and >> SIZEOF_LONG when building utilities. > Wonderful idea. I'm researching this for a possible implementation of a > GRUB equivalent to the C99 fixed-length integers print specifiers like > PRIx64. It would most likely go into <grub/types.h>, so I'm paying > special attention to anyone working on that file. Yeah, that would be very useful, most warning message from mingw64 is caused by grub_printf format. > >> As GRUB_CPU_SIZEOF_LONG doesn't necessary equal to >> GRUB_CPU_SIZEOF_VOID_P. (It actually avoid this by generating an >> #errror message when GRUB_CPU_SIZEOF_VOID_P != GRUB_CPU_SIZEOF_LONG). > I think you lost me here. This check is in the trunk GRUB, but not in > your "lib" branch, and actually it would make it impossible to build on > mingw64, where void* is 64-bit and long is 32-bit. The check is in svn trunk so that you can't compile at all, I remove it in my lib branch so that it can be compiled in mingw64. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-22 14:52 ` Bean @ 2009-07-25 19:33 ` Bean 2009-07-27 18:41 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-25 19:33 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: New tool grub-mkrawimage, used to generate img file from object files directly, no need for ld and objcopy anymore. It inject the grub_bss_start and grub_bss_end symbol, so no need to check for them in configure.ac. Remove the memcpy alias in kern/misc.c, instead, it map memcpy to grub_memmove when generating the module file. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-25 19:33 ` Bean @ 2009-07-27 18:41 ` Bean 2009-07-28 11:00 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-27 18:41 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Now the attributes are stored inside mod file, for example, "fs:", "command:ls", etc. grub-symdb uses it to generate the list files automatically (fs.lst, partmap.lst, parttool.lst, command.lst, handler.lst). Don't use sed to scan source file, and eliminate the fs-*.lst, partmap-*.lst, parttool-*.lst, command-*.lst and handler-*.lst. grub-objdump can show the mod attributes, for example: # grub-objdump gfxterm.mod filename: gfxterm.mod mod name: gfxterm mod deps: bitmap font video mod attr: handler:terminal_output.gfxterm command:background_image init func: 0xcad fini func: 0xce6 -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-27 18:41 ` Bean @ 2009-07-28 11:00 ` Bean 2009-07-30 14:51 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-28 11:00 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Now global symbol must be defined using GRUB_EXPORT macro, otherwise it'd be removed from the module symbol list. I also add GRUB_EXPORT to modules in i386-pc platform. Some reason to define global symbols explicitly: For modules that consists of multiple files, some external function is used to communicate with each other, they should not be exported, for example, sh.mod and lua.mod all have many function that's not static. It'd be nice to distinguish between function we want to export and those used by other files in the same module. For normal module, exported function is not common, for those that consist of functions mainly, we can move it to the library, which export all external function so that we don't need GRUB_EXPORT anyway. The export symbol is not cheap, by exporting only the symbols we need, we can save some space. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-28 11:00 ` Bean @ 2009-07-30 14:51 ` Bean 2009-07-31 18:10 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-30 14:51 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Now change kernel.img to kernel.mod, and export symbol using GRUB_EXPORT instead of EXPORT_FUNC and EXPORT_VAR. grub-mkimage would link all modules files to generate core.img. The symbol list is generated by grub-mkimage, no need for symlist.c anymore. Here are some test results using the latest lib branch and corresponding unpatched version (svn r2435). The test uses mingw in a windows host: Compile time: svn: real 3m52.625s user 1m9.647s sys 2m8.904s lib: real 1m13.282s user 0m11.365s sys 0m22.748s Files generated in the compile process: (not counting include/machine and include/cpu) svn: Files 2599 (24308485 bytes) lib: Files 1007 (20610273 bytes) Size of all modules: svn: 635991 lib: 549199 Size of core.img using modules: pc biosdisk reiserfs raid raid6rec mdraid lvm svn: 33035 lib: 29822 -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-30 14:51 ` Bean @ 2009-07-31 18:10 ` Bean 2009-08-05 17:59 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-07-31 18:10 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Fix for i386-efi and x86_64-efi platform, now grub-mkimage works just like i386-pc, it linked the modules to form the runtime image instead of embedding them. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-07-31 18:10 ` Bean @ 2009-08-05 17:59 ` Bean 2009-08-07 17:18 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-08-05 17:59 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Support mach-o object file, now you can compile grub2 in OSX using gcc 4.0 from Xcode. No other tool is needed except gcc and as. Tested ok with i386-pc and i386-efi. BTW, here are a list of issues of apple gcc 4.0: Local jumps with more that one digit (such as 10f, 10b) doesn't work, this affect the lzma decoder. I change it with symbol label like lzma_10. Relocation in code16 segment is trouble, apple cc generate wrong information sometimes. So use local symbol (L_xx) in 16-bit code. Line asm volatile ("jmp *%2" : : "b" (0), "S" (real_mode_mem), "g" (params->code32_start)); in loader/i386/linux.c generate an error message, i comment it out so that compilation can continue, so the linux loader would be broken for the time being. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-08-05 17:59 ` Bean @ 2009-08-07 17:18 ` Bean 2009-08-09 19:10 ` Bean 0 siblings, 1 reply; 25+ messages in thread From: Bean @ 2009-08-07 17:18 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Support 64-bit mach-o object files, now you can build i386-pc, i386-efi and x86_64-efi in OSX. Use PIC in x86_64-efi. Relocation R_X86_64_32S would cause problem in machine with 2G or more memory, the only way to get rid of it is to use large memory model, or use PIC. Large model is only available in gcc-4.3 or later, and the generated image is quite large as all address is 8 bytes long. PIC is always enabled in mingw-w64 and apple's gcc, it just need a little work to support PIC in elf platform. Now all system uses PIC instead of large memory model. As with this version, it's possible to build i386-pc, i386-efi and x86_64-efi in Linux/OSX/Windows, using the native build tool, no cross compiler. Only gcc and as is needed to generated object file *.o from source code, linker (ld) and converter (objcopy, objconv, grub-pe2elf, grub-macho2img) are not needed as the conversion is handled by grub-mkrawimage and grub-mkmod. -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
* Re: [PATCH] New object format 2009-08-07 17:18 ` Bean @ 2009-08-09 19:10 ` Bean 0 siblings, 0 replies; 25+ messages in thread From: Bean @ 2009-08-09 19:10 UTC (permalink / raw) To: The development of GRUB 2 Hi, Update: Add support for i386-ieee1275, i386-qemu and i386-coreboot, now the x86 platform is complete, you can build either one of it in Linux/OSX/Windows: Note: grub-mkfont doesn't compile in OSX, so you should add --disable-grub-mkfont, grub-emu could also cause problem in OSX/Windows, you can use --disable-grub-emu to disable it. Here are some information on how to compile them: i386-pc: (Linux/OSX/Windows) ./configure --with-platform=pc make . i386-efi: (Linux/OSX/Windows) ./configure --with-platform=efi make i386-ieee1275 (Linux/OSX/Windows) ./configure --with-platform=ieee1275 make i386-qemu (Linux/OSX/Windows) ./configure --with-platform=qemu make i386-coreboot (Linux/OSX/Windows) ./configure --with-platform=coreboot make x86_64-efi Linux: (needs gcc-multilib on 32-bit system) ./configure --with-platform=efi --target=x86_64 make OSX: ./configure --with-platform=efi --target=x86_64 make Windows: (needs mingw-w64) ./configure --with-platform=efi --target=x86_64-w64-mingw32 make -- Bean ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2009-08-09 19:10 UTC | newest] Thread overview: 25+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-07-14 15:49 [PATCH] New object format Bean 2009-07-14 17:57 ` please stop this Robert Millan 2009-07-14 18:09 ` Pavel Roskin 2009-07-14 18:17 ` Bean 2009-07-16 15:23 ` Robert Millan 2009-07-16 16:10 ` Vladimir 'phcoder' Serbinenko 2009-07-18 18:15 ` Robert Millan 2009-07-18 18:53 ` Vladimir 'phcoder' Serbinenko 2009-07-14 21:02 ` [PATCH] New object format Bean 2009-07-19 1:52 ` Isaac Dupree 2009-07-19 10:03 ` Bean 2009-07-21 20:55 ` Bean 2009-07-22 11:12 ` Bean 2009-07-22 11:47 ` Javier Martín 2009-07-22 13:34 ` Bean 2009-07-22 13:42 ` Javier Martín 2009-07-22 14:52 ` Bean 2009-07-25 19:33 ` Bean 2009-07-27 18:41 ` Bean 2009-07-28 11:00 ` Bean 2009-07-30 14:51 ` Bean 2009-07-31 18:10 ` Bean 2009-08-05 17:59 ` Bean 2009-08-07 17:18 ` Bean 2009-08-09 19:10 ` 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.