From 08278452325454027c6d42bc2d687dc8dd518006 Mon Sep 17 00:00:00 2001 From: "H. Peter Anvin" Date: Tue, 29 May 2012 14:08:11 -0700 Subject: [PATCH] relocs: Move stop to the end The Linux kernel puts the stop word at the beginning of the relocation list (the list is processed backwards); Syslinux puts the stop word at the beginning of the relocation list (the list is processed forwards.) Missed that change when syncing with the kernel version. (plus everything to actually make this get built... -- pjones) Signed-off-by: H. Peter Anvin --- diff --git a/com32/Makefile b/com32/Makefile index da632a1..b59fd3f 100644 --- a/com32/Makefile +++ b/com32/Makefile @@ -1,5 +1,5 @@ SUBDIRS = libupload tools lib gpllib libutil modules mboot menu samples rosh cmenu \ - hdt gfxboot sysdump lua/src + hdt gfxboot sysdump lua/src chain all tidy dist clean spotless install: set -e; for d in $(SUBDIRS); do $(MAKE) -C $$d $@; done diff --git a/com32/chain/Makefile b/com32/chain/Makefile new file mode 100644 index 0000000..9d398a8 --- /dev/null +++ b/com32/chain/Makefile @@ -0,0 +1,39 @@ +## ----------------------------------------------------------------------- +## +## Copyright 2001-2010 H. Peter Anvin - All Rights Reserved +## Copyright 2010 Michal Soltys +## +## This program 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, Inc., 53 Temple Place Ste 330, +## Boston MA 02111-1307, USA; either version 2 of the License, or +## (at your option) any later version; incorporated herein by reference. +## +## ----------------------------------------------------------------------- + + +topdir = ../.. +MAKEDIR = $(topdir)/mk +include $(MAKEDIR)/com32.mk + +OBJS = chain.o partiter.o utility.o options.o mangle.o + +all: + +%.o: %.c + $(CC) $(MAKEDEPS) $(CFLAGS) $(CHAINEXTOPT) -c -o $@ $< + +tidy dist: + rm -f *.o *.lo *.a *.lst .*.d *.tmp + +clean: tidy + rm -f *.lnx + +spotless: clean + rm -f *.lss *.c32 *.com + rm -f *~ \#* + +install: + + +-include .*.d diff --git a/com32/hdt/Makefile b/com32/hdt/Makefile index f187346..ea9ddfe 100644 --- a/com32/hdt/Makefile +++ b/com32/hdt/Makefile @@ -45,7 +45,7 @@ FLOPPY_DIR ?= floppy PCI_IDS_FILE ?= $(PWD)/$(FLOPPY_DIR)/pci.ids GZ_PCI_IDS_FILE ?= $(PCI_IDS_FILE).gz MENU_COM32 ?= $(com32)/menu/menu.c32 -CHAIN_COM32 ?= $(com32)/modules/chain.c32 +CHAIN_COM32 ?= $(com32)/modules/chain.c32 ART_DIR ?= art/ QEMU ?= qemu-kvm @@ -110,10 +110,16 @@ hdt.iso: hdt.c32 $(topdir)/core/isolinux.bin $(FLOPPY_DIR)/hdt.cfg memtest mv hdt.iso hdt-$(VERSION).iso ln -sf hdt-$(VERSION).iso hdt.iso -release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso +hdt-hybrid.iso: hdt.iso ../../utils/isohybrid + cp hdt-$(VERSION).iso hdt-hybrid-$(VERSION).iso + ../../utils/isohybrid --partok hdt-hybrid-$(VERSION).iso + ln -sf hdt-hybrid-$(VERSION).iso hdt-hybrid.iso + +release: spotless hdt.c32 hdt.img hdt.img.gz hdt.iso hdt-hybrid.iso mv hdt.c32 hdt_$(NODASH_VERSION).c32 md5sum hdt_$(NODASH_VERSION).c32 >$(SUM_FILE) md5sum hdt-$(VERSION).iso >>$(SUM_FILE) + md5sum hdt-hybrid-$(VERSION).iso >>$(SUM_FILE) md5sum hdt-$(VERSION).img >>$(SUM_FILE) md5sum hdt-$(VERSION).img.gz >>$(SUM_FILE) diff --git a/com32/lib/com32.ld b/com32/lib/com32.ld index 37ee46c..008e4ce 100644 --- a/com32/lib/com32.ld +++ b/com32/lib/com32.ld @@ -36,36 +36,23 @@ SECTIONS .rodata1 : { *(.rodata1) } __rodata_end = .; - /* Ensure the __preinit_array_start label is properly aligned. We - could instead move the label definition inside the section, but - the linker would then create the section even if it turns out to - be empty, which isn't pretty. */ + /* + * The difference betwee .ctors/.dtors and .init_array/.fini_array + * is the ordering, but we don't use prioritization for libcom32, so + * just lump them all together and hope that's okay. + */ . = ALIGN(4); - .preinit_array : { - PROVIDE (__preinit_array_start = .); - *(.preinit_array) - PROVIDE (__preinit_array_end = .); - } - .init_array : { - PROVIDE (__init_array_start = .); - *(.init_array) - PROVIDE (__init_array_end = .); - } - .fini_array : { - PROVIDE (__fini_array_start = .); - *(.fini_array) - PROVIDE (__fini_array_end = .); - } .ctors : { PROVIDE (__ctors_start = .); - KEEP (*(SORT(.ctors.*))) - KEEP (*(.ctors)) + KEEP (*(SORT(.preinit_array*))) + KEEP (*(SORT(.init_array*))) + KEEP (*(SORT(.ctors*))) PROVIDE (__ctors_end = .); } .dtors : { PROVIDE (__dtors_start = .); - KEEP (*(SORT(.dtors.*))) - KEEP (*(.dtors)) + KEEP (*(SORT(.fini_array*))) + KEEP (*(SORT(.dtors*))) PROVIDE (__dtors_end = .); } diff --git a/com32/modules/Makefile b/com32/modules/Makefile index e9ce1d1..d8861c4 100644 --- a/com32/modules/Makefile +++ b/com32/modules/Makefile @@ -19,11 +19,12 @@ topdir = ../.. MAKEDIR = $(topdir)/mk include $(MAKEDIR)/com32.mk -MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ +MODULES = chain.c32 config.c32 ethersel.c32 dmitest.c32 cpuidtest.c32 \ disk.c32 pcitest.c32 elf.c32 linux.c32 reboot.c32 pmload.c32 \ meminfo.c32 sdi.c32 sanboot.c32 ifcpu64.c32 vesainfo.c32 \ kbdmap.c32 cmd.c32 vpdtest.c32 host.c32 ls.c32 gpxecmd.c32 \ - ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 whichsys.c32 + ifcpu.c32 cpuid.c32 cat.c32 pwd.c32 ifplop.c32 zzjson.c32 \ + whichsys.c32 TESTFILES = diff --git a/com32/tools/Makefile b/com32/tools/Makefile index 7badabd..0161baf 100644 --- a/com32/tools/Makefile +++ b/com32/tools/Makefile @@ -15,6 +15,8 @@ include $(MAKEDIR)/build.mk BINS = relocs +INCLUDES += -I./include + all : $(BINS) relocs : relocs.o diff --git a/com32/tools/include/tools/le_byteshift.h b/com32/tools/include/tools/le_byteshift.h new file mode 100644 index 0000000..c99d45a --- /dev/null +++ b/com32/tools/include/tools/le_byteshift.h @@ -0,0 +1,70 @@ +#ifndef _TOOLS_LE_BYTESHIFT_H +#define _TOOLS_LE_BYTESHIFT_H + +#include + +static inline __u16 __get_unaligned_le16(const __u8 *p) +{ + return p[0] | p[1] << 8; +} + +static inline __u32 __get_unaligned_le32(const __u8 *p) +{ + return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24; +} + +static inline __u64 __get_unaligned_le64(const __u8 *p) +{ + return (__u64)__get_unaligned_le32(p + 4) << 32 | + __get_unaligned_le32(p); +} + +static inline void __put_unaligned_le16(__u16 val, __u8 *p) +{ + *p++ = val; + *p++ = val >> 8; +} + +static inline void __put_unaligned_le32(__u32 val, __u8 *p) +{ + __put_unaligned_le16(val >> 16, p + 2); + __put_unaligned_le16(val, p); +} + +static inline void __put_unaligned_le64(__u64 val, __u8 *p) +{ + __put_unaligned_le32(val >> 32, p + 4); + __put_unaligned_le32(val, p); +} + +static inline __u16 get_unaligned_le16(const void *p) +{ + return __get_unaligned_le16((const __u8 *)p); +} + +static inline __u32 get_unaligned_le32(const void *p) +{ + return __get_unaligned_le32((const __u8 *)p); +} + +static inline __u64 get_unaligned_le64(const void *p) +{ + return __get_unaligned_le64((const __u8 *)p); +} + +static inline void put_unaligned_le16(__u16 val, void *p) +{ + __put_unaligned_le16(val, p); +} + +static inline void put_unaligned_le32(__u32 val, void *p) +{ + __put_unaligned_le32(val, p); +} + +static inline void put_unaligned_le64(__u64 val, void *p) +{ + __put_unaligned_le64(val, p); +} + +#endif /* _TOOLS_LE_BYTESHIFT_H */ diff --git a/com32/tools/relocs.c b/com32/tools/relocs.c index 2474206..86fc7c5 100644 --- a/com32/tools/relocs.c +++ b/com32/tools/relocs.c @@ -13,12 +13,16 @@ #define USE_BSD #include #include -#include +#include + +static void die(char *fmt, ...); #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static Elf32_Ehdr ehdr; static unsigned long reloc_count, reloc_idx; static unsigned long *relocs; +static unsigned long reloc16_count, reloc16_idx; +static unsigned long *relocs16; struct section { Elf32_Shdr shdr; @@ -29,60 +33,87 @@ struct section { }; static struct section *secs; -static void die(char *fmt, ...) -{ - va_list ap; - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - exit(1); -} +enum symtype { + S_ABS, + S_REL, + S_SEG, + S_LIN, + S_NSYMTYPES +}; +static const char * const sym_regex_kernel[S_NSYMTYPES] = { /* * Following symbols have been audited. Don't warn user about * absolute relocations present w.r.t these symbols. */ + [S_ABS] = + "^(__.*_len|__.*_dwords)$", -/* True absolute relocations */ +/* + * These symbols are known to be relative, even if the linker marks them + * as absolute (typically defined outside any section in the linker script.) + */ + [S_REL] = + "^(__.*_start|__.*_end|_end|_[se](text|data))$", +}; -static const char safe_abs_regex[] = -"^(__.*_len|__.*_dwords)$"; -static regex_t safe_abs_regex_c; -static int is_safe_abs_reloc(const char *sym_name) -{ - return !regexec(&safe_abs_regex_c, sym_name, 0, NULL, 0); -} +static const char * const sym_regex_realmode[S_NSYMTYPES] = { +/* + * These are 16-bit segment symbols when compiling 16-bit code. + */ + [S_SEG] = + "^real_mode_seg$", -/* These are relative even though the linker marks them absolute */ +/* + * These are offsets belonging to segments, as opposed to linear addresses, + * when compiling 16-bit code. + */ + [S_LIN] = + "^pa_", +}; -static const char safe_rel_regex[] = -"^(__.*_start|__.*_end|_end|_[se](text|data))$"; -static regex_t safe_rel_regex_c; +static const char * const *sym_regex; -static int is_safe_rel_reloc(const char *sym_name) +static regex_t sym_regex_c[S_NSYMTYPES]; +static int is_reloc(enum symtype type, const char *sym_name) { - return !regexec(&safe_rel_regex_c, sym_name, 0, NULL, 0); + return sym_regex[type] && + !regexec(&sym_regex_c[type], sym_name, 0, NULL, 0); } -static void regex_init(void) +static void regex_init(int use_real_mode) { - char errbuf[128]; - int err; + char errbuf[128]; + int err; + int i; - err = regcomp(&safe_abs_regex_c, safe_abs_regex, - REG_EXTENDED|REG_NOSUB); - if (err) { - regerror(err, &safe_abs_regex_c, errbuf, sizeof errbuf); - die("%s", errbuf); - } + if (use_real_mode) + sym_regex = sym_regex_realmode; + else + sym_regex = sym_regex_kernel; - err = regcomp(&safe_rel_regex_c, safe_rel_regex, - REG_EXTENDED|REG_NOSUB); - if (err) { - regerror(err, &safe_rel_regex_c, errbuf, sizeof errbuf); - die("%s", errbuf); - } + for (i = 0; i < S_NSYMTYPES; i++) { + if (!sym_regex[i]) + continue; + + err = regcomp(&sym_regex_c[i], sym_regex[i], + REG_EXTENDED|REG_NOSUB); + + if (err) { + regerror(err, &sym_regex_c[i], errbuf, sizeof errbuf); + die("%s", errbuf); + } + } +} + +static void die(char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + exit(1); } static const char *sym_type(unsigned type) @@ -153,13 +184,16 @@ static const char *rel_type(unsigned type) REL_TYPE(R_386_RELATIVE), REL_TYPE(R_386_GOTOFF), REL_TYPE(R_386_GOTPC), + REL_TYPE(R_386_8), + REL_TYPE(R_386_PC8), + REL_TYPE(R_386_16), + REL_TYPE(R_386_PC16), #undef REL_TYPE }; - const char *name = NULL; - if (type < ARRAY_SIZE(type_name)) + const char *name = "unknown type rel type name"; + if (type < ARRAY_SIZE(type_name) && type_name[type]) { name = type_name[type]; - if (!name) - name = "unknown"; + } return name; } @@ -189,7 +223,7 @@ static const char *sym_name(const char *sym_strtab, Elf32_Sym *sym) name = sym_strtab + sym->st_name; } else { - name = sec_name(secs[sym->st_shndx].shdr.sh_name); + name = sec_name(sym->st_shndx); } return name; } @@ -428,7 +462,7 @@ static void print_absolute_symbols(void) printf("\n"); } -static int print_absolute_relocs(FILE *f) +static void print_absolute_relocs(void) { int i, printed = 0; @@ -472,17 +506,18 @@ static int print_absolute_relocs(FILE *f) * Before warning check if this absolute symbol * relocation is harmless. */ - if (is_safe_abs_reloc(name) || - is_safe_rel_reloc(name)) + if (is_reloc(S_ABS, name) || is_reloc(S_REL, name)) continue; if (!printed) { - fprintf(f, "Unknown absolute relocations present\n"); - fprintf(f, "Offset Info Type Sym.Value Sym.Name\n"); + printf("WARNING: Absolute relocations" + " present\n"); + printf("Offset Info Type Sym.Value " + "Sym.Name\n"); printed = 1; } - fprintf(f, "%08x %08x %10s %08x %s\n", + printf("%08x %08x %10s %08x %s\n", rel->r_offset, rel->r_info, rel_type(ELF32_R_TYPE(rel->r_info)), @@ -492,12 +527,11 @@ static int print_absolute_relocs(FILE *f) } if (printed) - fputc('\n', f); - - return printed; + printf("\n"); } -static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) +static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym), + int use_real_mode) { int i; /* Walk through the relocations */ @@ -522,31 +556,71 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) Elf32_Rel *rel; Elf32_Sym *sym; unsigned r_type; + const char *symname; + int shn_abs; + rel = &sec->reltab[j]; sym = &sh_symtab[ELF32_R_SYM(rel->r_info)]; r_type = ELF32_R_TYPE(rel->r_info); - /* Don't visit relocations to absolute symbols */ - if (sym->st_shndx == SHN_ABS && - !is_safe_rel_reloc(sym_name(sym_strtab, sym))) - continue; + + shn_abs = sym->st_shndx == SHN_ABS; switch (r_type) { case R_386_NONE: case R_386_PC32: + case R_386_PC16: + case R_386_PC8: case R_386_GOTPC: case R_386_GOTOFF: case R_386_GOT32: case R_386_PLT32: - /* Relative relocations don't need to - be adjusted */ + /* + * NONE can be ignored and and PC relative + * relocations don't need to be adjusted. + */ break; + + case R_386_16: + symname = sym_name(sym_strtab, sym); + if (!use_real_mode) + goto bad; + if (shn_abs) { + if (is_reloc(S_ABS, symname)) + break; + else if (!is_reloc(S_SEG, symname)) + goto bad; + } else { + if (is_reloc(S_LIN, symname)) + goto bad; + else + break; + } + visit(rel, sym); + break; + case R_386_32: - /* Visit relocations that need adjustment */ + symname = sym_name(sym_strtab, sym); + if (shn_abs) { + if (is_reloc(S_ABS, symname)) + break; + else if (!is_reloc(S_REL, symname)) + goto bad; + } else { + if (use_real_mode && + !is_reloc(S_LIN, symname)) + break; + } visit(rel, sym); break; default: die("Unsupported relocation type: %s (%d)\n", rel_type(r_type), r_type); + break; + bad: + symname = sym_name(sym_strtab, sym); + die("Invalid %s %s relocation: %s\n", + shn_abs ? "absolute" : "relative", + rel_type(r_type), symname); } } } @@ -554,8 +628,12 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) static void count_reloc(Elf32_Rel *rel, Elf32_Sym *sym) { - (void)rel; (void)sym; - reloc_count += 1; + (void)sym; + + if (ELF32_R_TYPE(rel->r_info) == R_386_16) + reloc16_count++; + else + reloc_count++; } static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) @@ -563,7 +641,10 @@ static void collect_reloc(Elf32_Rel *rel, Elf32_Sym *sym) (void)sym; /* Remember the address that needs to be adjusted. */ - relocs[reloc_idx++] = rel->r_offset; + if (ELF32_R_TYPE(rel->r_info) == R_386_16) + relocs16[reloc16_idx++] = rel->r_offset; + else + relocs[reloc_idx++] = rel->r_offset; } static int cmp_relocs(const void *va, const void *vb) @@ -573,23 +654,41 @@ static int cmp_relocs(const void *va, const void *vb) return (*a == *b)? 0 : (*a > *b)? 1 : -1; } -static void emit_relocs(int as_text) +static int write32(unsigned int v, FILE *f) +{ + unsigned char buf[4]; + + put_unaligned_le32(v, buf); + return fwrite(buf, 1, 4, f) == 4 ? 0 : -1; +} + +static void emit_relocs(int as_text, int use_real_mode) { int i; /* Count how many relocations I have and allocate space for them. */ reloc_count = 0; - walk_relocs(count_reloc); + walk_relocs(count_reloc, use_real_mode); relocs = malloc(reloc_count * sizeof(relocs[0])); if (!relocs) { die("malloc of %d entries for relocs failed\n", reloc_count); } + + relocs16 = malloc(reloc16_count * sizeof(relocs[0])); + if (!relocs16) { + die("malloc of %d entries for relocs16 failed\n", + reloc16_count); + } /* Collect up the relocations */ reloc_idx = 0; - walk_relocs(collect_reloc); + walk_relocs(collect_reloc, use_real_mode); + + if (reloc16_count && !use_real_mode) + die("Segment relocations found but --realmode not specified\n"); /* Order the relocations for more efficient processing */ qsort(relocs, reloc_count, sizeof(relocs[0]), cmp_relocs); + qsort(relocs16, reloc16_count, sizeof(relocs16[0]), cmp_relocs); /* Print the relocations */ if (as_text) { @@ -598,61 +697,83 @@ static void emit_relocs(int as_text) */ printf(".section \".data.reloc\",\"a\"\n"); printf(".balign 4\n"); - for (i = 0; i < reloc_count; i++) { - printf("\t .long 0x%08lx\n", relocs[i]); + if (use_real_mode) { + printf("\t.long %lu\n", reloc16_count); + for (i = 0; i < reloc16_count; i++) + printf("\t.long 0x%08lx\n", relocs16[i]); + printf("\t.long %lu\n", reloc_count); + for (i = 0; i < reloc_count; i++) { + printf("\t.long 0x%08lx\n", relocs[i]); + } + } else { + for (i = 0; i < reloc_count; i++) { + printf("\t.long 0x%08lx\n", relocs[i]); + } + /* Print a stop */ + printf("\t.long 0x%08lx\n", (unsigned long)0); } + printf("\n"); } else { - unsigned char buf[4]; - /* Now print each relocation */ - for (i = 0; i < reloc_count; i++) { - buf[0] = (relocs[i] >> 0) & 0xff; - buf[1] = (relocs[i] >> 8) & 0xff; - buf[2] = (relocs[i] >> 16) & 0xff; - buf[3] = (relocs[i] >> 24) & 0xff; - fwrite(buf, 4, 1, stdout); + if (use_real_mode) { + write32(reloc16_count, stdout); + for (i = 0; i < reloc16_count; i++) + write32(relocs16[i], stdout); + write32(reloc_count, stdout); + + /* Now print each relocation */ + for (i = 0; i < reloc_count; i++) + write32(relocs[i], stdout); + } else { + /* Now print each relocation */ + for (i = 0; i < reloc_count; i++) { + write32(relocs[i], stdout); + } + + /* Print a stop */ + write32(0, stdout); } - /* Print a stop */ - memset(buf, 0, sizeof buf); - fwrite(buf, 4, 1, stdout); } } static void usage(void) { - die("relocs [--abs-syms |--abs-relocs | --text] vmlinux\n"); + die("relocs [--abs-syms|--abs-relocs|--text|--realmode] vmlinux\n"); } int main(int argc, char **argv) { int show_absolute_syms, show_absolute_relocs; - int as_text; + int as_text, use_real_mode; const char *fname; FILE *fp; int i; - int err = 0; show_absolute_syms = 0; show_absolute_relocs = 0; as_text = 0; + use_real_mode = 0; fname = NULL; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (*arg == '-') { - if (strcmp(argv[1], "--abs-syms") == 0) { + if (strcmp(arg, "--abs-syms") == 0) { show_absolute_syms = 1; continue; } - - if (strcmp(argv[1], "--abs-relocs") == 0) { + if (strcmp(arg, "--abs-relocs") == 0) { show_absolute_relocs = 1; continue; } - else if (strcmp(argv[1], "--text") == 0) { + if (strcmp(arg, "--text") == 0) { as_text = 1; continue; } + if (strcmp(arg, "--realmode") == 0) { + use_real_mode = 1; + continue; + } } else if (!fname) { fname = arg; @@ -663,10 +784,7 @@ int main(int argc, char **argv) if (!fname) { usage(); } - - - regex_init(); - + regex_init(use_real_mode); fp = fopen(fname, "r"); if (!fp) { die("Cannot open %s: %s\n", @@ -682,10 +800,9 @@ int main(int argc, char **argv) return 0; } if (show_absolute_relocs) { - print_absolute_relocs(stdout); + print_absolute_relocs(); return 0; } - err = print_absolute_relocs(stderr); - emit_relocs(as_text); - return err; + emit_relocs(as_text, use_real_mode); + return 0; }