Added dumping of NE segments and relocations.
diff --git a/tools/winedump/ne.c b/tools/winedump/ne.c
index 5ad66af..02af56b 100644
--- a/tools/winedump/ne.c
+++ b/tools/winedump/ne.c
@@ -33,6 +33,36 @@
#include "wine/winbase16.h"
#include "winedump.h"
+struct ne_segtable_entry
+{
+ WORD seg_data_offset; /* Sector offset of segment data */
+ WORD seg_data_length; /* Length of segment data */
+ WORD seg_flags; /* Flags associated with this segment */
+ WORD min_alloc; /* Minimum allocation size for this */
+};
+
+struct relocation_entry
+{
+ BYTE address_type; /* Relocation address type */
+ BYTE relocation_type; /* Relocation type */
+ WORD offset; /* Offset in segment to fixup */
+ WORD target1; /* Target specification */
+ WORD target2; /* Target specification */
+};
+
+#define NE_RADDR_LOWBYTE 0
+#define NE_RADDR_SELECTOR 2
+#define NE_RADDR_POINTER32 3
+#define NE_RADDR_OFFSET16 5
+#define NE_RADDR_POINTER48 11
+#define NE_RADDR_OFFSET32 13
+
+#define NE_RELTYPE_INTERNAL 0
+#define NE_RELTYPE_ORDINAL 1
+#define NE_RELTYPE_NAME 2
+#define NE_RELTYPE_OSFIXUP 3
+#define NE_RELFLAG_ADDITIVE 4
+
static inline WORD get_word( const BYTE *ptr )
{
return ptr[0] | (ptr[1] << 8);
@@ -228,8 +258,125 @@
}
}
+static const char *get_reloc_name( BYTE addr_type, int additive )
+{
+ switch(addr_type & 0x7f)
+ {
+ case NE_RADDR_LOWBYTE: return additive ? "byte add" : "byte";
+ case NE_RADDR_OFFSET16: return additive ? "off16 add" : "off16";
+ case NE_RADDR_POINTER32: return additive ? "ptr32 add" : "ptr32";
+ case NE_RADDR_SELECTOR: return additive ? "sel add" : "sel";
+ case NE_RADDR_POINTER48: return additive ? "ptr48 add" : "ptr48";
+ case NE_RADDR_OFFSET32: return additive ? "off32 add" : "off32";
+ }
+ return "???";
+}
+
+static const char *get_seg_flags( WORD flags )
+{
+ static char buffer[256];
+
+ buffer[0] = 0;
+#define ADD_FLAG(x) if (flags & NE_SEGFLAGS_##x) strcat( buffer, " " #x );
+ ADD_FLAG(DATA);
+ ADD_FLAG(ALLOCATED);
+ ADD_FLAG(LOADED);
+ ADD_FLAG(ITERATED);
+ ADD_FLAG(MOVEABLE);
+ ADD_FLAG(SHAREABLE);
+ ADD_FLAG(PRELOAD);
+ ADD_FLAG(EXECUTEONLY);
+ ADD_FLAG(READONLY);
+ ADD_FLAG(RELOC_DATA);
+ ADD_FLAG(SELFLOAD);
+ ADD_FLAG(DISCARDABLE);
+ ADD_FLAG(32BIT);
+#undef ADD_FLAG
+ if (buffer[0])
+ {
+ buffer[0] = '(';
+ strcat( buffer, ")" );
+ }
+ return buffer;
+}
+
+static void dump_relocations( const void *base, const IMAGE_OS2_HEADER *ne, WORD count,
+ const struct relocation_entry *rep )
+{
+ const WORD *modref = (const WORD *)((const BYTE *)ne + ne->ne_modtab);
+ const BYTE *mod_name, *func_name;
+ WORD i;
+
+ for (i = 0; i < count; i++, rep++)
+ {
+ int additive = rep->relocation_type & NE_RELFLAG_ADDITIVE;
+ switch (rep->relocation_type & 3)
+ {
+ case NE_RELTYPE_ORDINAL:
+ mod_name = (const BYTE *)ne + ne->ne_imptab + modref[rep->target1 - 1];
+ printf( "%6d: %s = %*.*s.%d\n", i + 1, get_reloc_name( rep->address_type, additive ),
+ *mod_name, *mod_name, mod_name + 1, rep->target2 );
+ break;
+ case NE_RELTYPE_NAME:
+ mod_name = (const BYTE *)ne + ne->ne_imptab + modref[rep->target1 - 1];
+ func_name = (const BYTE *)ne + ne->ne_imptab + rep->target2;
+ printf( "%6d: %s = %*.*s.%*.*s\n", i + 1, get_reloc_name( rep->address_type, additive ),
+ *mod_name, *mod_name, mod_name + 1,
+ *func_name, *func_name, func_name + 1 );
+ break;
+ case NE_RELTYPE_INTERNAL:
+ if ((rep->target1 & 0xff) == 0xff)
+ {
+ /* the module itself */
+ mod_name = (const BYTE *)ne + ne->ne_restab;
+ printf( "%6d: %s = %*.*s.%d\n", i + 1, get_reloc_name( rep->address_type, additive ),
+ *mod_name, *mod_name, mod_name + 1, rep->target2 );
+ }
+ else
+ printf( "%6d: %s = %d:%04x\n", i + 1, get_reloc_name( rep->address_type, additive ),
+ rep->target1, rep->target2 );
+ break;
+ case NE_RELTYPE_OSFIXUP:
+ /* Relocation type 7:
+ *
+ * These appear to be used as fixups for the Windows
+ * floating point emulator. Let's just ignore them and
+ * try to use the hardware floating point. Linux should
+ * successfully emulate the coprocessor if it doesn't
+ * exist.
+ */
+ printf( "%6d: %s = TYPE %d, OFFSET %04x, TARGET %04x %04x\n",
+ i + 1, get_reloc_name( rep->address_type, additive ),
+ rep->relocation_type, rep->offset,
+ rep->target1, rep->target2 );
+ break;
+ }
+ }
+}
+
+static void dump_ne_segment( const void *base, const IMAGE_OS2_HEADER *ne, int segnum )
+{
+ const struct ne_segtable_entry *table = (const struct ne_segtable_entry *)((const BYTE *)ne + ne->ne_segtab);
+ const struct ne_segtable_entry *seg = table + segnum - 1;
+
+ printf( "\nSegment %d:\n", segnum );
+ printf( " File offset: %08x\n", seg->seg_data_offset << ne->ne_align );
+ printf( " Length: %08x\n", seg->seg_data_length );
+ printf( " Flags: %08x %s\n", seg->seg_flags, get_seg_flags(seg->seg_flags) );
+ printf( " Alloc size: %08x\n", seg->min_alloc );
+ if (seg->seg_flags & NE_SEGFLAGS_RELOC_DATA)
+ {
+ const BYTE *ptr = (const BYTE *)base + (seg->seg_data_offset << ne->ne_align) + seg->seg_data_length;
+ WORD count = get_word(ptr);
+ ptr += sizeof(WORD);
+ printf( " Relocations:\n" );
+ dump_relocations( base, ne, count, (const struct relocation_entry *)ptr );
+ }
+}
+
void ne_dump( const void *exe, size_t exe_size )
{
+ unsigned int i;
const IMAGE_DOS_HEADER *dos = exe;
const IMAGE_OS2_HEADER *ne = (const IMAGE_OS2_HEADER *)((const char *)dos + dos->e_lfanew);
@@ -237,4 +384,5 @@
dump_ne_names( exe, ne );
dump_ne_resources( exe, ne );
dump_ne_exports( exe, ne );
+ for (i = 1; i <= ne->ne_cseg; i++) dump_ne_segment( exe, ne, i );
}