Blame SOURCES/0001-relocs-Move-stop-to-the-end.patch

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