This is the mail archive of the
binutils@sourceware.org
mailing list for the binutils project.
[PATCH] OMF support for BFD
- From: Bernd Jendrissek <bernd dot jendrissek at gmail dot com>
- To: binutils <binutils at sourceware dot org>
- Date: Sun, 18 Sep 2011 03:05:18 +0200
- Subject: [PATCH] OMF support for BFD
It's about time I submitted this. Somewhere in the world it must
still be Software Freedom Day. Sorry about the code-dumpish nature, I
only recently put in the time to get this useful enough to be worth
contributing. For the bored / sleepless, back story and sample output
at http://bpj-code.blogspot.com/2011/09/omf-support-for-binutils.html
bfd/ChangeLog (but I have a stream of a few dozen patch+ChangeLog
leading up to this bit by bit, if that is more useful? might help
bisections):
2011-09-18 Bernd Jendrissek <bernd.jendrissek@gmail.com>
* Makefile.am: Add files for OMF support.
* Makefile.in: Regenerate.
* bfd-in2.h (bfd_flavour): Add OMF flavour.
* i386omf.c: New file.
* strtab.c: New file.
* strtab.h: New file.
* targets.c: Add OMF target vector.
I'm not too happy about the name of strtab.[hc]; it started as a
growable array-of-strings, but by now it has mutated into polymorphism
- it's now a growable array-of-void*. Any suggestions on what to do
about the misleading name? Also, I'm unconvinced that the reloc names
I chose are particularly good ones.
I have aimed only to support objdump functionality; IMHO for this
anachronism of a file format that's where the bulk of the remaining
value for its support lies. I might one day be tempted to teach ld to
link OMF files into an MZ EXE, but that day is not today. And as for
gas, that looks like an awful lot of work just to do something that
NASM can already do. That does leave the question about what to do
about test cases for the testsuite - it would be rather icky to have
binary object files in the repository!
Does anybody have access to MASM? For that matter, Borland's Turbo
Assembler? These would be probably the most common tools generating
OMF objects from assembly, two decades ago. DJ has kindly send me a
few (simple) Turbo Assembler output files - I'm hoping someone can
send me something meatier. There are probably some corner cases /
interpretation issues lurking in my port. Any other tools' outputs
would be welcome too, of course - the more esoteric, the better!
diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index 9c454cc..0a14b78 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -52,7 +52,7 @@ BFD32_LIBS = \
archive.lo archures.lo bfd.lo bfdio.lo bfdwin.lo \
cache.lo coffgen.lo corefile.lo \
format.lo init.lo libbfd.lo opncls.lo reloc.lo \
- section.lo syms.lo targets.lo hash.lo linker.lo \
+ section.lo strtab.lo syms.lo targets.lo hash.lo linker.lo \
srec.lo binary.lo tekhex.lo ihex.lo stabs.lo stab-syms.lo \
merge.lo dwarf2.lo simple.lo compress.lo verilog.lo
@@ -62,7 +62,7 @@ BFD32_LIBS_CFILES = \
archive.c archures.c bfd.c bfdio.c bfdwin.c \
cache.c coffgen.c corefile.c \
format.c init.c libbfd.c opncls.c reloc.c \
- section.c syms.c targets.c hash.c linker.c \
+ section.c strtab.c syms.c targets.c hash.c linker.c \
srec.c binary.c tekhex.c ihex.c stabs.c stab-syms.c \
merge.c dwarf2.c simple.c compress.c verilog.c
@@ -341,6 +341,7 @@ BFD32_BACKENDS = \
i386mach3.lo \
i386msdos.lo \
i386netbsd.lo \
+ i386omf.lo \
i386os9k.lo \
ieee.lo \
m68k4knetbsd.lo \
@@ -522,6 +523,7 @@ BFD32_BACKENDS_CFILES = \
i386mach3.c \
i386msdos.c \
i386netbsd.c \
+ i386omf.c \
i386os9k.c \
ieee.c \
m68k4knetbsd.c \
@@ -710,7 +712,7 @@ SOURCE_HFILES = \
libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \
libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \
netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \
- pef.h pef-traceback.h peicode.h som.h version.h \
+ pef.h pef-traceback.h peicode.h som.h strtab.h version.h \
vms.h xcoff-target.h xsym.h
## ... and all .h files which are in the build tree.
diff --git a/bfd/Makefile.in b/bfd/Makefile.in
index 2cbf6a0..c808790 100644
--- a/bfd/Makefile.in
+++ b/bfd/Makefile.in
@@ -104,8 +104,8 @@ LTLIBRARIES = $(bfdlib_LTLIBRARIES) $(noinst_LTLIBRARIES)
am__DEPENDENCIES_1 =
am__objects_1 = archive.lo archures.lo bfd.lo bfdio.lo bfdwin.lo \
cache.lo coffgen.lo corefile.lo format.lo init.lo libbfd.lo \
- opncls.lo reloc.lo section.lo syms.lo targets.lo hash.lo \
- linker.lo srec.lo binary.lo tekhex.lo ihex.lo stabs.lo \
+ opncls.lo reloc.lo section.lo strtab.lo syms.lo targets.lo \
+ hash.lo linker.lo srec.lo binary.lo tekhex.lo ihex.lo stabs.lo \
stab-syms.lo merge.lo dwarf2.lo simple.lo compress.lo \
verilog.lo
am_libbfd_la_OBJECTS = $(am__objects_1)
@@ -352,7 +352,7 @@ BFD32_LIBS = \
archive.lo archures.lo bfd.lo bfdio.lo bfdwin.lo \
cache.lo coffgen.lo corefile.lo \
format.lo init.lo libbfd.lo opncls.lo reloc.lo \
- section.lo syms.lo targets.lo hash.lo linker.lo \
+ section.lo strtab.lo syms.lo targets.lo hash.lo linker.lo \
srec.lo binary.lo tekhex.lo ihex.lo stabs.lo stab-syms.lo \
merge.lo dwarf2.lo simple.lo compress.lo verilog.lo
@@ -361,7 +361,7 @@ BFD32_LIBS_CFILES = \
archive.c archures.c bfd.c bfdio.c bfdwin.c \
cache.c coffgen.c corefile.c \
format.c init.c libbfd.c opncls.c reloc.c \
- section.c syms.c targets.c hash.c linker.c \
+ section.c strtab.c syms.c targets.c hash.c linker.c \
srec.c binary.c tekhex.c ihex.c stabs.c stab-syms.c \
merge.c dwarf2.c simple.c compress.c verilog.c
@@ -641,6 +641,7 @@ BFD32_BACKENDS = \
i386mach3.lo \
i386msdos.lo \
i386netbsd.lo \
+ i386omf.lo \
i386os9k.lo \
ieee.lo \
m68k4knetbsd.lo \
@@ -822,6 +823,7 @@ BFD32_BACKENDS_CFILES = \
i386mach3.c \
i386msdos.c \
i386netbsd.c \
+ i386omf.c \
i386os9k.c \
ieee.c \
m68k4knetbsd.c \
@@ -1011,7 +1013,7 @@ SOURCE_HFILES = \
libaout.h libbfd.h libcoff.h libecoff.h libhppa.h libieee.h \
libnlm.h liboasys.h libpei.h libxcoff.h mach-o.h \
netbsd.h nlm-target.h nlmcode.h nlmswap.h ns32k.h \
- pef.h pef-traceback.h peicode.h som.h version.h \
+ pef.h pef-traceback.h peicode.h som.h strtab.h version.h \
vms.h xcoff-target.h xsym.h
BUILD_HFILES = \
@@ -1407,6 +1409,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386mach3.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386msdos.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386netbsd.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386omf.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/i386os9k.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ieee.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ihex.Plo@am__quote@
@@ -1477,6 +1480,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/srec.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stab-syms.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stabs.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/strtab.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sunos.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/syms.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/targets.Plo@am__quote@
diff --git a/bfd/bfd-in2.h b/bfd/bfd-in2.h
index 5f3a31f..c72ef1b 100644
--- a/bfd/bfd-in2.h
+++ b/bfd/bfd-in2.h
@@ -5513,6 +5513,7 @@ enum bfd_flavour
bfd_target_os9k_flavour,
bfd_target_versados_flavour,
bfd_target_msdos_flavour,
+ bfd_target_omf_flavour,
bfd_target_ovax_flavour,
bfd_target_evax_flavour,
bfd_target_mmo_flavour,
diff --git a/bfd/i386omf.c b/bfd/i386omf.c
new file mode 100644
index 0000000..2e2ed33
--- /dev/null
+++ b/bfd/i386omf.c
@@ -0,0 +1,2087 @@
+/* BFD back-end for ix86 OMF objects.
+ Copyright 2007 Free Software Foundation, Inc.
+ Written by Bernd Jendrissek <bernd.jendrissek@gmail.com>
+ Based on bfd/binary.c.
+
+ This file is part of BFD, the Binary File Descriptor library.
+
+ 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; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program 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 this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
+
+#include "bfd.h"
+#include "sysdep.h"
+#include "safe-ctype.h"
+#include "libbfd.h"
+#include "strtab.h"
+
+#define OMF_RECORD_THEADR 0x80
+#define OMF_RECORD_LHEADR 0x82
+#define OMF_RECORD_COMENT 0x88
+#define OMF_RECORD_MODEND 0x8a
+#define OMF_RECORD_EXTDEF 0x8c
+#define OMF_RECORD_TYPDEF 0x8e
+#define OMF_RECORD_PUBDEF 0x90
+#define OMF_RECORD_LINNUM 0x94
+#define OMF_RECORD_LNAMES 0x96
+#define OMF_RECORD_SEGDEF 0x98
+#define OMF_RECORD_GRPDEF 0x9a
+#define OMF_RECORD_FIXUPP 0x9c
+#define OMF_RECORD_LEDATA 0xa0
+#define OMF_RECORD_LIDATA 0xa2
+#define OMF_RECORD_COMDEF 0xb0
+#define OMF_RECORD_BAKPAT 0xb2
+#define OMF_RECORD_LEXTDEF 0xb4
+#define OMF_RECORD_LPUBDEF 0xb6
+#define OMF_RECORD_LCOMDEF 0xb8
+#define OMF_RECORD_CEXTDEF 0xbc
+#define OMF_RECORD_COMDAT 0xc2
+#define OMF_RECORD_LINSYM 0xc4
+#define OMF_RECORD_ALIAS 0xc6
+#define OMF_RECORD_NBKPAT 0xc8
+#define OMF_RECORD_LLNAMES 0xca
+#define OMF_RECORD_VERNUM 0xcc
+#define OMF_RECORD_VENDEXT 0xce
+
+#define OMF_COMENT_TRANSLATOR 0x00
+#define OMF_COMENT_INTEL_COPYRIGHT 0x01
+#define OMF_COMENT_DEFAULT_LIBRARY_OBS 0x81
+#define OMF_COMENT_MSDOS_VERSION 0x9c
+#define OMF_COMENT_MEMORY_MODEL 0x9d
+#define OMF_COMENT_DOSSEG 0x9e
+#define OMF_COMENT_DEFAULT_LIBRARY 0x9f
+#define OMF_COMENT_EXT 0xa0
+#define OMF_COMENT_EXT_IMPDEF 0x01
+#define OMF_COMENT_EXT_EXPDEF 0x02
+#define OMF_COMENT_EXT_INCDEF 0x03
+#define OMF_COMENT_EXT_PROTMEM 0x04
+#define OMF_COMENT_EXT_LNKDIR 0x05
+#define OMF_COMENT_EXT_BIGENDIAN 0x06
+#define OMF_COMENT_EXT_PRECOMP 0x07
+#define OMF_COMENT_NEWEXT 0xa1
+#define OMF_COMENT_PASS_SEPARATOR 0xa2
+#define OMF_COMENT_LIBMOD 0xa3
+#define OMF_COMENT_EXESTR 0xa4
+#define OMF_COMENT_INCERR 0xa6
+#define OMF_COMENT_NOPAD 0xa7
+#define OMF_COMENT_WKEXT 0xa8
+#define OMF_COMENT_LZEXT 0xa9
+#define OMF_COMENT_RANDOM_COMMENT 0xda
+#define OMF_COMENT_COMPILER 0xdb
+#define OMF_COMENT_DATE 0xdc
+#define OMF_COMENT_TIME 0xdd
+#define OMF_COMENT_USER 0xdf
+#define OMF_COMENT_SYMBOL_TYPE_EXTDEF 0xe0
+#define OMF_COMENT_SYMBOL_TYPE_PUBDEF 0xe1
+#define OMF_COMENT_STRUCT_MEMBER 0xe2
+#define OMF_COMENT_TYPDEF 0xe3
+#define OMF_COMENT_ENUM_MEMBER 0xe4
+#define OMF_COMENT_SCOPE_BEGIN 0xe5
+#define OMF_COMENT_LOCALS 0xe6
+#define OMF_COMENT_SCOPE_END 0xe7
+#define OMF_COMENT_SOURCE_FILE 0xe8
+#define OMF_COMENT_DEPENDENCIES 0xe9
+#define OMF_COMENT_COMPILE_PARAMETERS 0xea
+#define OMF_COMENT_MATCHED_TYPE_EXTDEF 0xeb
+#define OMF_COMENT_MATCHED_TYPE_PUBDEF 0xec
+#define OMF_COMENT_CLASSDEF 0xed
+#define OMF_COMENT_COVERAGE_OFFSET 0xee
+#define OMF_COMENT_LARGE_SCOPE_BEGIN 0xf5
+#define OMF_COMENT_LARGE_LOCALS 0xf6
+#define OMF_COMENT_LARGE_SCOPE_END 0xf7
+#define OMF_COMENT_MEMBER_FUNCTION 0xf8
+#define OMF_COMENT_DEBUG_VERSION 0xf9
+#define OMF_COMENT_OPT_FLAGS 0xfa
+#define OMF_COMENT_COMMAND_LINE 0xff
+#define OMF_COMENT_LIBRARY_COMMENT 0xff
+
+#define OMF_MODEND_MAIN_MODULE 0x80
+#define OMF_MODEND_START_ADDRESS 0x40
+
+#define OMF_PUBDEF_SEGMENT_ABSOLUTE OMF_SEGDEF_NONE
+
+#define OMF_LNAMES_NONE 0
+
+#define OMF_SEGDEF_NONE 0
+
+#define OMF_SEGDEF_ALIGNMENT_MASK 0xe0
+#define OMF_SEGDEF_ALIGNMENT_SHIFT 5
+#define OMF_SEGDEF_ALIGNMENT_ABSOLUTE 0
+#define OMF_SEGDEF_ALIGNMENT_RELOC_BYTE 1
+#define OMF_SEGDEF_ALIGNMENT_RELOC_WORD 2
+#define OMF_SEGDEF_ALIGNMENT_RELOC_PARA 3
+#define OMF_SEGDEF_ALIGNMENT_RELOC_PAGE 4
+#define OMF_SEGDEF_ALIGNMENT_RELOC_DWORD 5
+#define OMF_SEGDEF_ALIGNMENT_UNNAMED_ABSOLUTE OMF_SEGDEF_ALIGNMENT_RELOC_DWORD
+#define OMF_SEGDEF_ALIGNMENT_LTL_PARA 6
+#define OMF_SEGDEF_ALIGNMENT_UNDEFINED 7
+
+#define OMF_SEGDEF_COMBINATION_MASK 0x1c
+#define OMF_SEGDEF_COMBINATION_SHIFT 2
+#define OMF_SEGDEF_COMBINATION_PRIVATE 0
+#define OMF_SEGDEF_COMBINATION_RESERVED_1 1
+#define OMF_SEGDEF_COMBINATION_COMMON_INTEL OMF_SEGDEF_COMBINATION_RESERVED_1
+#define OMF_SEGDEF_COMBINATION_PUBLIC_2 2
+#define OMF_SEGDEF_COMBINATION_RESERVED_3 3
+#define OMF_SEGDEF_COMBINATION_PUBLIC_4 4
+#define OMF_SEGDEF_COMBINATION_STACK 5
+#define OMF_SEGDEF_COMBINATION_COMMON 6
+#define OMF_SEGDEF_COMBINATION_PUBLIC_7 7
+#define OMF_SEGDEF_COMBINATION_PUBLIC OMF_SEGDEF_COMBINATION_PUBLIC_2
+
+#define OMF_FIXUPP_FIXUP 0x80
+#define OMF_FIXUPP_TARGET_SEGDEF 0
+#define OMF_FIXUPP_TARGET_GRPDEF 1
+#define OMF_FIXUPP_TARGET_EXTDEF 2
+#define OMF_FIXUPP_TARGET_EXPLICIT 3
+#define OMF_FIXUPP_TARGET_NODISP 4
+#define OMF_FIXUPP_FRAME_SEGDEF 0
+#define OMF_FIXUPP_FRAME_GRPDEF 1
+#define OMF_FIXUPP_FRAME_EXTDEF 2
+#define OMF_FIXUPP_FRAME_EXPLICIT 3
+#define OMF_FIXUPP_FRAME_LEIDATA 4
+#define OMF_FIXUPP_FRAME_TARGET 5
+
+#define OMF_FIXUP_SEGREL 0x40
+#define OMF_FIXUP_LOCATION_MASK 0x3c
+#define OMF_FIXUP_LOCATION_SHIFT 2
+#define OMF_FIX_DATA_FRAME_THREAD 0x80
+#define OMF_FIX_DATA_FRAME_MASK 0x70
+#define OMF_FIX_DATA_FRAME_SHIFT 4
+#define OMF_FIX_DATA_TARGET_THREAD 0x08
+#define OMF_FIX_DATA_P_MASK 0x04
+#define OMF_FIX_DATA_TARGT_MASK 0x03
+#define OMF_FIX_DATA_TARGET_METHOD_MASK \
+ (OMF_FIX_DATA_TARGT_MASK | OMF_FIX_DATA_P_MASK)
+
+#define OMF_GRPDEF_NONE 0
+#define OMF_GRPDEF_COMPONENT_SEGMENT 0xff
+#define OMF_GRPDEF_COMPONENT_EXTERNAL 0xfe
+#define OMF_GRPDEF_COMPONENT_NAMES 0xfd
+#define OMF_GRPDEF_COMPONENT_LTL 0xfb
+#define OMF_GRPDEF_COMPONENT_ABSOLUTE 0xfa
+
+/* Some (few) record types have fixed minimum lengths. */
+#define OMF_RECORD_HEADER 3
+#define OMF_RECORD_HEADER_COMENT 2
+#define OMF_RECORD_HEADER_MODEND 1
+
+#define OMF_INDEX_LOWMASK 0x7f
+#define OMF_INDEX_2BYTES 0x80
+
+#define OMF_MSDOS_DATE_YEAR_WIDTH 7
+#define OMF_MSDOS_DATE_YEAR_SHIFT 9
+#define OMF_MSDOS_DATE_MONTH_WIDTH 4
+#define OMF_MSDOS_DATE_MONTH_SHIFT 5
+#define OMF_MSDOS_DATE_DAY_WIDTH 5
+#define OMF_MSDOS_DATE_DAY_SHIFT 0
+#define OMF_MSDOS_TIME_HOUR_WIDTH 5
+#define OMF_MSDOS_TIME_HOUR_SHIFT 11
+#define OMF_MSDOS_TIME_MINUTE_WIDTH 6
+#define OMF_MSDOS_TIME_MINUTE_SHIFT 5
+#define OMF_MSDOS_TIME_2SECOND_WIDTH 5
+#define OMF_MSDOS_TIME_2SECOND_SHIFT 0
+
+#define W2M(x) ((1 << (x)) - 1)
+
+struct i386omf_symbol;
+
+enum i386omf_offset_size {
+ I386OMF_OFFSET_SIZE_16,
+ I386OMF_OFFSET_SIZE_32,
+};
+
+struct counted_string {
+ bfd_size_type len;
+ char *data;
+};
+
+struct i386omf_segment {
+ struct bfd_section *asect;
+ struct strtab *relocs;
+ struct strtab *pubdef;
+ int combination;
+ int name_index;
+ int class_index;
+ int overlay_index;
+};
+
+struct i386omf_group_entry {
+ enum {
+ GRPDEF_ENTRY_SEGDEF = 0xff,
+ } type;
+ union {
+ int segdef;
+ } u;
+};
+
+struct i386omf_group {
+ int name_index;
+ struct strtab *entries;
+ struct strtab *pubdef;
+ struct i386omf_symbol *symbol;
+};
+
+struct i386omf_symbol {
+ asymbol base;
+ struct counted_string name;
+ int type_index;
+ struct i386omf_segment *seg;
+ struct i386omf_group *group;
+};
+
+struct i386omf_obj_data {
+ bfd_window window;
+ bfd_byte *image;
+ char *translator;
+ struct counted_string module_name;
+ bfd_boolean is_main_module;
+ bfd_boolean has_start_address;
+ struct strtab *lnames;
+ struct strtab *segdef;
+ struct strtab *grpdef;
+ struct strtab *externs;
+ struct strtab *abs_pubdef;
+ struct strtab *dependencies;
+ struct i386omf_segment *last_leidata;
+};
+
+struct i386omf_relent {
+ arelent base;
+ asymbol *symbol;
+};
+
+enum reloc_type
+ {
+ R_I386OMF_LO8, /* 0 */
+ R_I386OMF_OFF16, /* 1 */
+ R_I386OMF_SEG, /* 2 */
+ R_I386OMF_FAR16, /* 3 */
+ R_I386OMF_HI8, /* 4 */
+ R_I386OMF_OFF16_LOADER, /* 5; PharLap: OFF32 */
+ R_I386OMF_RESERVED_6, /* 6; PharLap: FAR32 */
+ R_I386OMF_RESERVED_7, /* 7 */
+ R_I386OMF_RESERVED_8, /* 8 */
+ R_I386OMF_OFF32, /* 9 */
+ R_I386OMF_RESERVED_10, /* 10 */
+ R_I386OMF_FAR32, /* 11 */
+ R_I386OMF_RESERVED_12, /* 12 */
+ R_I386OMF_OFF32_LOADER, /* 13 */
+
+ /* Some relocs to support other-than-target frames. */
+ R_I386OMF_WRT_FRAME,
+ };
+
+struct i386omf_borland_dependency {
+ struct counted_string filename;
+ int time;
+ int date;
+};
+
+static bfd_reloc_status_type
+i386omf_fix_wrt_frame (bfd *abfd,
+ arelent *reloc_entry,
+ asymbol *symbol,
+ void * data,
+ asection *input_section,
+ bfd *output_bfd,
+ char **error_message);
+
+/* There are no HOWTO entries for far pointer relocs, as we expand them to
+ a tuple of SEG and OFF relocs. Neither does gas generate FAR relocs. */
+reloc_howto_type howto_table_i386omf_pcrel[] =
+{
+ /* type rs size bsz pcrel bp ovrf sf
+ * name part_inpl readmask setmask pcdone */
+HOWTO(R_I386OMF_LO8, 0, 0, 8, TRUE, 0, complain_overflow_signed, 0,
+ "PC8LO", FALSE, 0xff, 0xff, FALSE), /* XXX Which overflow type? */
+HOWTO(R_I386OMF_OFF16, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, 0,
+ "OFFPC16", FALSE, 0xffff, 0xffff, FALSE),
+EMPTY_HOWTO(R_I386OMF_SEG), /* PC-relative SEG relocs don't make sense. */
+EMPTY_HOWTO(R_I386OMF_FAR16),
+HOWTO(R_I386OMF_HI8, 0, 0, 8, TRUE, 0, complain_overflow_dont, 0,
+ "PC8HI", FALSE, 0xff, 0xff, FALSE), /* XXX Which overflow type? */
+HOWTO(R_I386OMF_OFF16_LOADER, 0, 1, 16, TRUE, 0, complain_overflow_bitfield, 0,
+ "OFFPC16L", FALSE, 0xffff, 0xffff, FALSE),
+EMPTY_HOWTO(R_I386OMF_RESERVED_6),
+EMPTY_HOWTO(R_I386OMF_RESERVED_7),
+EMPTY_HOWTO(R_I386OMF_RESERVED_8),
+HOWTO(R_I386OMF_OFF32, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, 0,
+ "OFFPC32", FALSE, 0xffffffff, 0xffffffff, FALSE),
+EMPTY_HOWTO(R_I386OMF_RESERVED_10),
+EMPTY_HOWTO(R_I386OMF_FAR32),
+EMPTY_HOWTO(R_I386OMF_RESERVED_12),
+HOWTO(R_I386OMF_OFF32_LOADER, 0, 2, 32, TRUE, 0, complain_overflow_bitfield, 0,
+ "OFFPC32L", FALSE, 0xffffffff, 0xffffffff, FALSE),
+};
+reloc_howto_type howto_table_i386omf_segrel[] =
+{
+ /* type rs size bsz pcrel bp ovrf sf
+ * name part_inpl readmask setmask pcdone */
+HOWTO(R_I386OMF_LO8, 0, 0, 8, FALSE, 0, complain_overflow_signed, 0,
+ "8LO", FALSE, 0xff, 0xff, FALSE), /* XXX Which overflow type? */
+HOWTO(R_I386OMF_OFF16, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0,
+ "OFF16", FALSE, 0xffff, 0xffff, FALSE),
+HOWTO(R_I386OMF_SEG, 0, 1, 16, FALSE, 0, complain_overflow_unsigned, 0,
+ "SEG", FALSE, 0xffff, 0xffff, FALSE),
+EMPTY_HOWTO(R_I386OMF_FAR16),
+HOWTO(R_I386OMF_HI8, 0, 0, 8, FALSE, 0, complain_overflow_dont, 0,
+ "8HI", FALSE, 0xff, 0xff, FALSE), /* XXX Which overflow type? */
+HOWTO(R_I386OMF_OFF16_LOADER, 0, 1, 16, FALSE, 0, complain_overflow_bitfield, 0,
+ "OFF16L", FALSE, 0xffff, 0xffff, FALSE),
+EMPTY_HOWTO(R_I386OMF_RESERVED_6),
+EMPTY_HOWTO(R_I386OMF_RESERVED_7),
+EMPTY_HOWTO(R_I386OMF_RESERVED_8),
+HOWTO(R_I386OMF_OFF32, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0,
+ "OFF32", FALSE, 0xffffffff, 0xffffffff, FALSE),
+EMPTY_HOWTO(R_I386OMF_RESERVED_10),
+EMPTY_HOWTO(R_I386OMF_FAR32),
+EMPTY_HOWTO(R_I386OMF_RESERVED_12),
+HOWTO(R_I386OMF_OFF32_LOADER, 0, 2, 32, FALSE, 0, complain_overflow_bitfield, 0,
+ "OFF32L", FALSE, 0xffffffff, 0xffffffff, FALSE),
+};
+/*
+ * OMF supports relocations that are relative to things other than just the
+ * segment to which the reloc symbol belongs. To represent these in BFD,
+ * use two consecutive relocs at the same address:
+ * lea 0x0,%ax
+ * OFF16 foo
+ * WRTSEG bar
+ * This representation is more familiar to assembly-language programmers,
+ * compared with the alternative of a more stateless expression-like set of
+ * relocations. This nearly direct representation of OMF reloc info into
+ * BFD relocs also makes it easier to convert back from BFD to OMF format.
+ *
+ * A possible downside of this representation is that it requires the linker
+ * to remember previous relocations in order to make use of WRTSEG, but
+ * presumably any linker reading OMF input objects would have to keep track
+ * of which relocs act on a particular address anyway.
+ *
+ * To generate weird WRTSEG relocs with nasm:
+ * extern foo
+ * extern bar
+ * lea ax, foo wrt seg bar
+ *
+ * It *is* possible to represent absolute-frame-relative relocs in MZ EXE
+ * relocations: just add the PSP frame 65520 times! (It may break the DOS
+ * EXE loader though.)
+ */
+reloc_howto_type howto_wrt_segdef =
+HOWTO(R_I386OMF_WRT_FRAME, 0, 3, 16, FALSE, 0, complain_overflow_bitfield, &i386omf_fix_wrt_frame,
+ "WRTSEG", FALSE, 0xffff, 0xffff, FALSE);
+
+static void
+hexdump (bfd_byte const *p, bfd_size_type len)
+{
+ bfd_size_type i;
+ char *s;
+
+ /* XXX - 1000 is the size of _bfd_default_error_handler()'s buffer. */
+ if (len > 1000 / 3) {
+ (*_bfd_error_handler) ("(truncated hexdump)");
+ len = 1000 / 3;
+ }
+
+ s = bfd_malloc2 (len + 1, 3); /* +1 for NUL. */
+ if (s == NULL)
+ return;
+ for (i = 0; i < len; i++)
+ {
+ sprintf (s + i*3, " %02x", bfd_get_8 (abfd, p + i));
+ }
+ (*_bfd_error_handler) (s);
+ free (s);
+}
+
+static bfd_boolean
+i386omf_read_index (bfd *abfd,
+ int *idx,
+ bfd_byte const **p,
+ bfd_size_type *reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ int v;
+
+ if (*reclen < 1)
+ {
+ (*_bfd_error_handler) ("Index truncated at 0x%lx.", *p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ v = *(*p)++;
+ (*reclen)--;
+ if (v & OMF_INDEX_2BYTES)
+ {
+ if (*reclen < 1)
+ {
+ (*_bfd_error_handler) ("Index truncated at 0x%lx.",
+ *p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ v = (v & OMF_INDEX_LOWMASK) * 256 + *(*p)++;
+ (*reclen)--;
+ }
+
+ *idx = v;
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_offset (bfd *abfd,
+ bfd_vma *offset,
+ bfd_byte const **p,
+ bfd_size_type *reclen,
+ enum i386omf_offset_size sz)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ bfd_size_type offset_len = 0;
+
+ switch (sz)
+ {
+ case I386OMF_OFFSET_SIZE_16:
+ offset_len = 2;
+ break;
+ case I386OMF_OFFSET_SIZE_32:
+ offset_len = 4;
+ break;
+ }
+
+ /* TODO: Handle 32-bit OMF records. */
+ if (*reclen < offset_len)
+ {
+ (*_bfd_error_handler) ("Offset truncated at 0x%lx.", *p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ if (offset)
+ {
+ switch (sz)
+ {
+ case I386OMF_OFFSET_SIZE_16:
+ *offset = bfd_get_16 (abfd, *p);
+ break;
+ case I386OMF_OFFSET_SIZE_32:
+ *offset = bfd_get_32 (abfd, *p);
+ break;
+ }
+ }
+
+ *p += offset_len;
+ *reclen -= offset_len;
+
+ return TRUE;
+}
+
+static bfd_size_type
+i386omf_read_string (bfd *abfd,
+ struct counted_string *s,
+ bfd_byte const *p,
+ bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ bfd_size_type slen = *p;
+
+ if (slen + 1 > reclen) {
+ (*_bfd_error_handler) ("Counted string at 0x%lx overflows its record.",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+ s->len = slen;
+ s->data = bfd_alloc (abfd, slen + 1);
+ if (s->data == NULL)
+ return 0;
+ memcpy (s->data, p + 1, slen);
+ s->data[slen] = 0;
+
+ return (slen + 1);
+}
+
+static char const *
+i386omf_lookup_string (struct strtab *tab, int i, char const *def)
+{
+ struct counted_string *s;
+
+ if (i == 0)
+ return def;
+
+ s = strtab_lookup (tab, i);
+
+ if (s && s->data)
+ return s->data;
+
+ (*_bfd_error_handler) ("Bad name index requested from string table at %p",
+ tab);
+ bfd_set_error (bfd_error_wrong_format);
+
+ return NULL;
+}
+
+/* Create a binary object. Invoked via bfd_set_format. */
+
+static bfd_boolean
+binary_mkobject (bfd *abfd ATTRIBUTE_UNUSED)
+{
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_coment (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ int comment_type, comment_class;
+
+ if (reclen < OMF_RECORD_HEADER_COMENT)
+ {
+ (*_bfd_error_handler) ("Truncated COMENT record.");
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ comment_type = bfd_get_8 (abfd, p + 0);
+ comment_class = bfd_get_8 (abfd, p + 1);
+ p += OMF_RECORD_HEADER_COMENT;
+ reclen -= OMF_RECORD_HEADER_COMENT;
+
+ switch (comment_class)
+ {
+ case OMF_COMENT_TRANSLATOR:
+ if (tdata->translator)
+ (*_bfd_error_handler) ("Translator already set to %s",
+ tdata->translator);
+ if (reclen && !ISPRINT (bfd_get_8 (abfd, p))
+ && bfd_get_8 (abfd, p) == reclen - 1)
+ {
+ /* Looks like a length+data style string!
+ XXX The OMF specification wants a string whose length is
+ implicit in reclen, but NASM 0.92 and above seem deliberately
+ to generate a length+data string. If there appears to be a
+ length byte that happens to match the reclen-derived length,
+ omit it from the translator string. Remove ISPRINT if any
+ obscure tools turn up whose translator string length byte
+ happens to encode a printable ASCII character. */
+ p++;
+ reclen--;
+ }
+ tdata->translator = bfd_alloc (abfd, reclen + 1);
+ strncpy (tdata->translator, (char const *) p, reclen);
+ tdata->translator[reclen] = 0;
+ break;
+ case OMF_COMENT_PASS_SEPARATOR: /* We don't care about it. */
+ break;
+ case OMF_COMENT_SYMBOL_TYPE_EXTDEF:
+ case OMF_COMENT_SYMBOL_TYPE_PUBDEF:
+ case OMF_COMENT_STRUCT_MEMBER:
+ case OMF_COMENT_TYPDEF:
+ case OMF_COMENT_ENUM_MEMBER:
+ case OMF_COMENT_SCOPE_BEGIN:
+ case OMF_COMENT_LOCALS:
+ case OMF_COMENT_SCOPE_END:
+ case OMF_COMENT_SOURCE_FILE:
+ /* http://webster.cs.ucr.edu/Page_TechDocs/boa.txt has record formats. */
+ break;
+ case OMF_COMENT_DEPENDENCIES:
+ while (reclen)
+ {
+ struct i386omf_borland_dependency *dep;
+ bfd_size_type slen;
+
+ if (reclen < 5)
+ {
+ (*_bfd_error_handler) ("Truncated Borland dependency list at 0x%zx",
+ p - tdata->image);
+ break;
+ }
+
+ dep = bfd_alloc (abfd, sizeof (*dep));
+ if (dep == NULL)
+ return FALSE;
+
+ /* Some sort of timestamp. */
+ dep->time = bfd_get_16 (abfd, p + 0);
+ dep->date = bfd_get_16 (abfd, p + 2);
+ p += 4;
+ reclen -= 4;
+
+ /* Source filename. */
+ slen = i386omf_read_string (abfd, &dep->filename, p, reclen);
+ if (slen < 1)
+ break;
+
+ strtab_add (tdata->dependencies, dep);
+ p += slen;
+ reclen -= slen;
+ }
+ break;
+ case OMF_COMENT_COMPILE_PARAMETERS:
+ case OMF_COMENT_MATCHED_TYPE_EXTDEF:
+ case OMF_COMENT_MATCHED_TYPE_PUBDEF:
+ case OMF_COMENT_CLASSDEF:
+ case OMF_COMENT_COVERAGE_OFFSET:
+ case OMF_COMENT_LARGE_SCOPE_BEGIN:
+ case OMF_COMENT_LARGE_LOCALS:
+ case OMF_COMENT_LARGE_SCOPE_END:
+ case OMF_COMENT_MEMBER_FUNCTION:
+ case OMF_COMENT_DEBUG_VERSION:
+ case OMF_COMENT_OPT_FLAGS:
+ /* http://webster.cs.ucr.edu/Page_TechDocs/boa.txt has record formats. */
+ break;
+ default:
+ (*_bfd_error_handler) ("Unknown COMENT record 0x%02x:0x%02x at 0x%Zx",
+ comment_type, comment_class, p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_modend (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+
+ if (reclen < OMF_RECORD_HEADER_MODEND) {
+ (*_bfd_error_handler) ("Truncated MODEND record.");
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ tdata->is_main_module = *p & OMF_MODEND_MAIN_MODULE ? TRUE : FALSE;
+ tdata->has_start_address = *p & OMF_MODEND_START_ADDRESS ? TRUE : FALSE;
+
+ if (*p & ~(OMF_MODEND_MAIN_MODULE | OMF_MODEND_START_ADDRESS)) {
+ (*_bfd_error_handler) ("Too much cleverness in MODEND record.");
+ hexdump (p, reclen);
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_extdef (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+
+ while (reclen)
+ {
+ struct i386omf_symbol *extdef;
+ bfd_size_type slen;
+
+ extdef = bfd_alloc (abfd, sizeof (*extdef));
+ if (extdef == NULL)
+ return FALSE;
+
+ extdef = (struct i386omf_symbol *) bfd_make_empty_symbol (abfd);
+ abfd->flags |= HAS_SYMS;
+
+ slen = i386omf_read_string (abfd, &extdef->name, p, reclen);
+ if (slen < 1)
+ return FALSE;
+ p += slen;
+ reclen -= slen;
+
+ if (!i386omf_read_index (abfd, &extdef->type_index, &p, &reclen))
+ return FALSE;
+
+ extdef->base.name = extdef->name.data;
+ /* Maybe? extdef->base.flags |= BSF_WEAK; */
+ extdef->base.value = 0;
+ extdef->seg = NULL;
+ extdef->base.section = bfd_und_section_ptr;
+
+ strtab_add (tdata->externs, extdef);
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_pubdef (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ int base_group, base_segment;
+ bfd_vma base_frame = 0;
+
+ if (!i386omf_read_index (abfd, &base_group, &p, &reclen))
+ return FALSE;
+ if (!i386omf_read_index (abfd, &base_segment, &p, &reclen))
+ return FALSE;
+ if (base_segment == OMF_PUBDEF_SEGMENT_ABSOLUTE)
+ {
+ /* Rarely used absolute-address symbol. */
+ if (reclen < 2)
+ {
+ (*_bfd_error_handler) ("Truncated base frame in PUBDEF at 0x%Zx",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ base_frame = bfd_get_16 (abfd, p);
+ p += 2;
+ reclen -= 2;
+ (*_bfd_error_handler) ("PUBDEF with base frame 0x%04x",
+ (unsigned int) base_frame);
+ }
+
+ while (reclen)
+ {
+ struct i386omf_symbol *pubdef;
+ bfd_size_type slen;
+ bfd_vma offset;
+
+ pubdef = (struct i386omf_symbol *) bfd_make_empty_symbol (abfd);
+ abfd->flags |= HAS_SYMS;
+
+ slen = i386omf_read_string (abfd, &pubdef->name, p, reclen);
+ if (slen < 1)
+ return FALSE;
+ p += slen;
+ reclen -= slen;
+ if (!i386omf_read_offset (abfd, &offset, &p, &reclen,
+ I386OMF_OFFSET_SIZE_16))
+ return FALSE;
+ if (!i386omf_read_index (abfd, &pubdef->type_index, &p, &reclen))
+ return FALSE;
+
+ pubdef->base.name = pubdef->name.data;
+ pubdef->base.flags |= BSF_GLOBAL;
+ pubdef->base.value = base_frame * 16 + offset;
+ pubdef->seg = strtab_lookup (tdata->segdef, base_segment);
+ if (pubdef->seg)
+ pubdef->base.section = pubdef->seg->asect;
+ else
+ pubdef->base.section = bfd_und_section_ptr;
+ pubdef->group = strtab_lookup (tdata->grpdef, base_group);
+
+ if (base_segment != OMF_PUBDEF_SEGMENT_ABSOLUTE)
+ {
+ /* Normal segment-relative exported symbol. */
+ struct i386omf_segment *seg;
+
+ seg = strtab_lookup (tdata->segdef, base_segment);
+ if (seg == NULL)
+ {
+ (*_bfd_error_handler) ("PUBDEF %s in unknown SEGDEF %d",
+ pubdef->base.name, base_segment);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ strtab_add (seg->pubdef, pubdef);
+ }
+ else if (base_group != OMF_GRPDEF_NONE)
+ {
+ /* Rather more weird: relative to a group, but no segment? */
+ struct i386omf_group *group;
+
+ group = strtab_lookup (tdata->grpdef, base_group);
+ if (group == NULL)
+ {
+ (*_bfd_error_handler) ("PUBDEF %s in unknown GRPDEF %d",
+ pubdef->base.name, base_group);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ strtab_add (group->pubdef, pubdef);
+
+ if (base_frame)
+ {
+ (*_bfd_error_handler) ("PUBDEF %s has nonzero base frame 0x%04x",
+ pubdef->base.name, base_frame);
+ }
+ }
+ else
+ {
+ /* Absolute exported symbol. */
+ strtab_add (tdata->abs_pubdef, pubdef);
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_lnames (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+
+ while (reclen)
+ {
+ struct counted_string *lname;
+ bfd_size_type slen;
+
+ lname = bfd_alloc (abfd, sizeof (*lname));
+ if (lname == NULL)
+ return FALSE;
+ slen = i386omf_read_string (abfd, lname, p, reclen);
+ if (slen < 1)
+ return FALSE;
+ strtab_add (tdata->lnames, lname);
+
+ /* Advance to next string. */
+ reclen -= slen;
+ p += slen;
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_segdef (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ int segdefs_seen = 0;
+
+ while (reclen)
+ {
+ const unsigned int alignment_powers[] = { 0, 0, 1, 4, 8, 2, 12, -1 };
+ int alignment, combination;
+ int name_index, class_index, overlay_index;
+ struct i386omf_segment *seg;
+ struct i386omf_symbol *seg_sym;
+ char const *segment_name;
+ bfd_vma absolute_addr, seglen;
+ bfd_byte attr;
+
+ attr = *p;
+
+ alignment = (attr & OMF_SEGDEF_ALIGNMENT_MASK) >> OMF_SEGDEF_ALIGNMENT_SHIFT;
+ combination = (attr & OMF_SEGDEF_COMBINATION_MASK) >> OMF_SEGDEF_COMBINATION_SHIFT;
+
+ if (alignment == OMF_SEGDEF_ALIGNMENT_ABSOLUTE)
+ {
+ /* Absolute segment; get frame number and offset. */
+ absolute_addr = (bfd_vma) bfd_get_16 (abfd, p + 1) * 16;
+ absolute_addr += bfd_get_8 (abfd, p + 3);
+
+ if (reclen < 4)
+ {
+ (*_bfd_error_handler) ("SEGDEF at 0x%lx is truncated.",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ p += 4;
+ reclen -= 4;
+ }
+ else
+ {
+ p += 1;
+ reclen--;
+ }
+
+ if (!i386omf_read_offset (abfd, &seglen, &p, &reclen,
+ I386OMF_OFFSET_SIZE_16))
+ return FALSE;
+ if (!i386omf_read_index (abfd, &name_index, &p, &reclen))
+ return FALSE;
+ if (!i386omf_read_index (abfd, &class_index, &p, &reclen))
+ return FALSE;
+ if (!i386omf_read_index (abfd, &overlay_index, &p, &reclen))
+ return FALSE;
+
+ if (alignment == OMF_SEGDEF_ALIGNMENT_UNDEFINED)
+ {
+ (*_bfd_error_handler) ("Segment %d (%s) wants alignment = 7",
+ name_index,
+ strtab_lookup (tdata->lnames, name_index));
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ seg = bfd_alloc (abfd, sizeof (*seg));
+ if (seg == NULL)
+ return FALSE;
+ seg->combination = combination;
+ seg->name_index = name_index;
+ seg->class_index = class_index;
+ seg->overlay_index = overlay_index;
+
+ seg->pubdef = strtab_new (abfd);
+ if (seg->pubdef == NULL)
+ return FALSE;
+
+ seg->relocs = strtab_new (abfd);
+ if (seg->relocs == NULL)
+ return FALSE;
+
+ strtab_add (tdata->segdef, seg);
+
+ segment_name = i386omf_lookup_string (tdata->lnames,
+ name_index,
+ "UNNAMED");
+ if (segment_name == NULL)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ seg->asect = bfd_make_section_anyway (abfd, segment_name);
+ seg_sym = (struct i386omf_symbol *) seg->asect->symbol;
+ seg_sym->name.len = strlen (segment_name);
+ seg_sym->name.data = bfd_alloc (abfd, seg_sym->name.len + 1);
+ if (seg_sym->name.data == NULL)
+ return FALSE;
+ strcpy (seg_sym->name.data, segment_name);
+ seg_sym->type_index = 0;
+ seg_sym->seg = seg;
+ seg_sym->group = NULL;
+ seg->asect->used_by_bfd = seg;
+ seg->asect->size = seglen;
+
+ /* Use class name to guess if section should be SEC_CODE or SEC_DATA. */
+ if (strstr (i386omf_lookup_string (tdata->lnames, class_index, ""),
+ "CODE"))
+ seg->asect->flags |= SEC_CODE;
+ if (strstr (i386omf_lookup_string (tdata->lnames, class_index, ""),
+ "DATA"))
+ {
+ if (seg->asect->flags & SEC_CODE)
+ seg->asect->flags &= ~SEC_CODE;
+ else
+ seg->asect->flags |= SEC_DATA;
+ }
+
+ seg->asect->alignment_power = alignment_powers[alignment];
+
+ segdefs_seen++;
+ }
+
+ if (reclen || segdefs_seen != 1)
+ (*_bfd_error_handler) ("SEGDEF record doesn't contain exactly one segment definition");
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_grpdef (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct i386omf_group *grpdef;
+ struct counted_string *s;
+
+ grpdef = bfd_alloc (abfd, sizeof (*grpdef));
+ if (grpdef == NULL)
+ return FALSE;
+
+ if (!i386omf_read_index (abfd, &grpdef->name_index, &p, &reclen))
+ return FALSE;
+
+ grpdef->entries = strtab_new (abfd);
+ if (grpdef->entries == NULL)
+ return FALSE;
+ grpdef->pubdef = strtab_new (abfd);
+ if (grpdef->pubdef == NULL)
+ return FALSE;
+
+ while (reclen)
+ {
+ struct i386omf_group_entry *entry;
+
+ entry = bfd_alloc (abfd, sizeof (*entry));
+ if (entry == NULL)
+ return FALSE;
+
+ switch (*p)
+ {
+ case OMF_GRPDEF_COMPONENT_SEGMENT:
+ p++;
+ reclen--;
+ entry->type = GRPDEF_ENTRY_SEGDEF;
+ if (!i386omf_read_index (abfd, &entry->u.segdef, &p, &reclen))
+ return FALSE;
+ strtab_add (grpdef->entries, entry);
+ break;
+ default:
+ (*_bfd_error_handler) ("Unknown GRPDEF component type 0x%02x", *p);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ }
+
+ s = strtab_lookup (tdata->lnames, grpdef->name_index);
+ if (s == NULL)
+ {
+ (*_bfd_error_handler) ("GRPDEF name is not an LNAME");
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ grpdef->symbol = (struct i386omf_symbol *) bfd_make_empty_symbol (abfd);
+ grpdef->symbol->name = *s;
+ grpdef->symbol->base.name = grpdef->symbol->name.data;
+ grpdef->symbol->base.value = 0;
+ grpdef->symbol->base.flags |= BSF_SECTION_SYM;
+ grpdef->symbol->base.section = bfd_und_section_ptr;
+ abfd->flags |= HAS_SYMS;
+
+ strtab_add (tdata->grpdef, grpdef);
+
+ return TRUE;
+}
+
+static bfd_reloc_status_type
+i386omf_fix_wrt_frame (bfd *abfd ATTRIBUTE_UNUSED,
+ arelent *reloc_entry ATTRIBUTE_UNUSED,
+ asymbol *symbol ATTRIBUTE_UNUSED,
+ void * data ATTRIBUTE_UNUSED,
+ asection *input_section ATTRIBUTE_UNUSED,
+ bfd *output_bfd ATTRIBUTE_UNUSED,
+ char **error_message ATTRIBUTE_UNUSED)
+{
+ return bfd_reloc_continue;
+}
+
+static bfd_boolean
+i386omf_read_fixupp (bfd *abfd, bfd_byte const *p, bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ bfd_byte const *q;
+
+ while (reclen)
+ {
+ int subrec;
+
+ subrec = bfd_get_8 (abfd, p);
+ if (subrec & OMF_FIXUPP_FIXUP)
+ {
+ int location, fixdata;
+ int frame_method, frame = 0, target_method, target = 0;
+ bfd_size_type offset, displacement = 0;
+ struct i386omf_relent *target_relent, *frame_relent;
+ struct i386omf_symbol *sym, *frame_sym;
+ reloc_howto_type *howto;
+
+ if (tdata->last_leidata == NULL)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ if (reclen < 3)
+ {
+ (*_bfd_error_handler) ("FIXUP subrecord truncated at 0x%lx.",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ /* Read then skip first 3 bytes that must always be present. */
+ location = (subrec & OMF_FIXUP_LOCATION_MASK)
+ >> OMF_FIXUP_LOCATION_SHIFT;
+ offset = bfd_get_8 (abfd, p + 1) + 256 * (subrec & 3);
+ fixdata = bfd_get_8 (abfd, p + 2);
+ p += 3;
+ reclen -= 3;
+
+ if (fixdata & OMF_FIX_DATA_FRAME_THREAD)
+ {
+ // XXX Look it up from the FRAME thread.
+ frame_method = 0;
+ frame = 0;
+ }
+ else
+ frame_method = (fixdata & OMF_FIX_DATA_FRAME_MASK)
+ >> OMF_FIX_DATA_FRAME_SHIFT;
+
+ switch (frame_method)
+ {
+ struct i386omf_segment *segdef;
+ struct i386omf_group *grp;
+
+ case OMF_FIXUPP_FRAME_SEGDEF:
+ if (!(fixdata & OMF_FIX_DATA_FRAME_THREAD)
+ && !i386omf_read_index (abfd, &frame, &p, &reclen))
+ return FALSE;
+ segdef = strtab_lookup (tdata->segdef, frame);
+ frame_sym = (struct i386omf_symbol *) segdef->asect->symbol;
+ break;
+ case OMF_FIXUPP_FRAME_GRPDEF:
+ if (!(fixdata & OMF_FIX_DATA_FRAME_THREAD)
+ && !i386omf_read_index (abfd, &frame, &p, &reclen))
+ return FALSE;
+ grp = strtab_lookup (tdata->grpdef, frame);
+ frame_sym = grp->symbol;
+ break;
+ case OMF_FIXUPP_FRAME_EXTDEF:
+ if (!(fixdata & OMF_FIX_DATA_FRAME_THREAD)
+ && !i386omf_read_index (abfd, &frame, &p, &reclen))
+ return FALSE;
+ frame_sym = strtab_lookup (tdata->externs, frame);
+ break;
+ case OMF_FIXUPP_FRAME_EXPLICIT:
+ frame = (int) bfd_get_16 (abfd, p);
+ p += 2;
+ reclen -= 2;
+ frame_sym = NULL; /* TODO: Make an absolute symbol. */
+ break;
+ case OMF_FIXUPP_FRAME_LEIDATA:
+ frame_sym = (struct i386omf_symbol *) tdata->last_leidata->asect->symbol;
+ break;
+ case OMF_FIXUPP_FRAME_TARGET:
+ frame_sym = NULL;
+ break;
+ default:
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ if (fixdata & OMF_FIX_DATA_TARGET_THREAD)
+ {
+ // XXX Look it up from the TARGET thread.
+ target_method = 0;
+ target = 0;
+ }
+ else
+ target_method = fixdata & OMF_FIX_DATA_TARGET_METHOD_MASK;
+
+ target_relent = bfd_alloc (abfd, sizeof (*target_relent));
+ if (target_relent == NULL)
+ return FALSE;
+
+ q = p;
+ switch (target_method)
+ {
+ struct i386omf_segment *segdef;
+ struct i386omf_group *grpdef;
+
+ case OMF_FIXUPP_TARGET_SEGDEF:
+ case OMF_FIXUPP_TARGET_NODISP | OMF_FIXUPP_TARGET_SEGDEF:
+ if (!i386omf_read_index (abfd, &target, &p, &reclen))
+ return FALSE;
+ segdef = strtab_lookup (tdata->segdef, target);
+ if (segdef == NULL)
+ {
+ (*_bfd_error_handler) ("FIXUP at 0x%zx wants phantom segment [%d]",
+ q - tdata->image, target);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ target_relent->symbol = segdef->asect->symbol;
+ break;
+ case OMF_FIXUPP_TARGET_GRPDEF:
+ case OMF_FIXUPP_TARGET_NODISP | OMF_FIXUPP_TARGET_GRPDEF:
+ if (!i386omf_read_index (abfd, &target, &p, &reclen))
+ return FALSE;
+ grpdef = strtab_lookup (tdata->grpdef, target);
+ if (grpdef == NULL)
+ {
+ (*_bfd_error_handler) ("FIXUP at 0x%zx wants phantom group [%d]",
+ q - tdata->image, target);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ target_relent->symbol = NULL;
+ break;
+ case OMF_FIXUPP_TARGET_EXTDEF:
+ case OMF_FIXUPP_TARGET_NODISP | OMF_FIXUPP_TARGET_EXTDEF:
+ if (!i386omf_read_index (abfd, &target, &p, &reclen))
+ return FALSE;
+ sym = strtab_lookup (tdata->externs, target);
+ if (sym == NULL)
+ {
+ (*_bfd_error_handler) ("FIXUP at 0x%zx wants phantom extern [%d]",
+ q - tdata->image, target);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+ target_relent->symbol = &sym->base;
+ break;
+ case OMF_FIXUPP_TARGET_EXPLICIT:
+ case OMF_FIXUPP_TARGET_NODISP | OMF_FIXUPP_TARGET_EXPLICIT:
+ target = (int) bfd_get_16 (abfd, p);
+ p += 2;
+ reclen -= 2;
+ target_relent->symbol = NULL;
+ break;
+ }
+
+ if (!(target_method & OMF_FIXUPP_TARGET_NODISP))
+ if (!i386omf_read_offset (abfd, &displacement, &p, &reclen,
+ I386OMF_OFFSET_SIZE_16))
+ return FALSE;
+
+ target_relent->base.sym_ptr_ptr = &target_relent->symbol;
+ target_relent->base.address = offset;
+ howto = &(subrec & OMF_FIXUP_SEGREL
+ ? howto_table_i386omf_segrel
+ : howto_table_i386omf_pcrel)[location];
+ target_relent->base.addend
+ = displacement + (subrec & OMF_FIXUP_SEGREL
+ ? 0
+ : -bfd_get_reloc_size (howto));
+ target_relent->base.howto = howto;
+
+ strtab_add (tdata->last_leidata->relocs, target_relent);
+
+ switch (frame_method)
+ {
+ case OMF_FIXUPP_FRAME_TARGET:
+ break;
+ default:
+ frame_relent = bfd_alloc (abfd, sizeof (*frame_relent));
+ if (frame_relent == NULL)
+ return FALSE;
+ frame_relent->symbol = &frame_sym->base;
+ frame_relent->base.sym_ptr_ptr = &frame_relent->symbol;
+ frame_relent->base.address = offset;
+ frame_relent->base.addend = 0;
+ frame_relent->base.howto = &howto_wrt_segdef;
+ strtab_add (tdata->last_leidata->relocs, frame_relent);
+ break;
+ }
+
+ abfd->flags |= HAS_SYMS;
+ tdata->last_leidata->asect->flags |= SEC_RELOC;
+ }
+ else
+ {
+ (*_bfd_error_handler) ("THREAD subrecords not yet supported");
+ p++;
+ reclen--;
+ }
+ }
+
+ return TRUE;
+}
+
+static bfd_size_type
+i386omf_add_section_lidata (bfd *abfd, struct bfd_section *asect,
+ bfd_vma *offset, bfd_byte const *p,
+ bfd_size_type reclen)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ bfd_size_type repeat_count, block_count;
+ bfd_size_type eaten = 0;
+
+ if (reclen < 2 + 2)
+ {
+ (*_bfd_error_handler) ("LIDATA data block truncated at 0x%lx.",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ repeat_count = bfd_get_16 (abfd, p);
+ eaten += 2;
+ block_count = bfd_get_16 (abfd, p + eaten);
+ eaten += 2;
+
+ p += eaten;
+ reclen -= eaten;
+
+ if (block_count == 0)
+ {
+ /* Recursive exit condition. */
+ int licount;
+
+ licount = bfd_get_8 (abfd, p);
+
+ if ((asect->size < *offset)
+ || (asect->size - *offset < (bfd_size_type) licount))
+ {
+ (*_bfd_error_handler) ("LIDATA at 0x%lx overflows section %A",
+ asect, p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+ memcpy (asect->contents + *offset, p + 1, licount);
+ *offset += licount;
+ eaten += licount + 1;
+ }
+ else
+ {
+ /* Recursive definition: data block contains other data blocks. */
+ while (block_count--)
+ {
+ bfd_size_type subeaten;
+
+ subeaten = i386omf_add_section_lidata (abfd, asect, offset,
+ p, reclen);
+ if (!subeaten)
+ return 0;
+
+ if (subeaten > reclen)
+ {
+ (*_bfd_error_handler) ("LIDATA at 0x%lx overflows section %A",
+ asect, p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return 0;
+ }
+
+ p += subeaten;
+ reclen -= subeaten;
+ }
+ if (reclen)
+ (*_bfd_error_handler) ("Leftover LIDATA at 0x%lx in section %A",
+ asect, p - tdata->image);
+ }
+
+ return eaten;
+}
+
+static bfd_boolean
+i386omf_add_section_data (bfd *abfd,
+ struct bfd_section *asect,
+ bfd_vma offset,
+ bfd_byte const *p,
+ bfd_size_type reclen, int rectype)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+
+ /* Lazily allocate memory for section data. */
+ if ((asect->flags & SEC_IN_MEMORY) == 0)
+ {
+ asect->contents = bfd_zalloc (abfd, asect->size);
+ if (asect->contents == NULL)
+ {
+ (*_bfd_error_handler) ("Out of memory for %A section contents",
+ asect);
+ return FALSE;
+ }
+ asect->flags |= SEC_IN_MEMORY;
+ }
+
+ if (rectype & (OMF_RECORD_LEDATA ^ OMF_RECORD_LIDATA))
+ {
+ /* LIDATA, 0xa2 or 0xa3. */
+ if (!i386omf_add_section_lidata (abfd, asect, &offset,
+ p, reclen))
+ return FALSE;
+ }
+ else
+ {
+ /* LEDATA, 0xa2 or 0xa3. */
+ if ((asect->size < offset) || (asect->size - offset < reclen))
+ {
+ (*_bfd_error_handler) ("LEDATA at 0x%lx overflows section %A",
+ asect, p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ memcpy (asect->contents + offset, p, reclen);
+ }
+
+ return TRUE;
+}
+
+static bfd_boolean
+i386omf_read_leidata (bfd *abfd, bfd_byte const *p,
+ bfd_size_type reclen, int rectype)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct i386omf_segment *segdef;
+ bfd_vma offset;
+ int seg_index;
+
+ if (!i386omf_read_index (abfd, &seg_index, &p, &reclen))
+ return FALSE;
+
+ if (seg_index <= OMF_SEGDEF_NONE)
+ {
+ (*_bfd_error_handler) ("LEDATA at 0x%lx has no segment",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ segdef = strtab_lookup (tdata->segdef, seg_index);
+ if (segdef == NULL)
+ {
+ (*_bfd_error_handler) ("LEDATA at 0x%lx wants phantom segment [%d]",
+ p - tdata->image, seg_index);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ /* We'll need to know which section FIXUP records refer to. */
+ tdata->last_leidata = segdef;
+
+ if (!i386omf_read_offset (abfd, &offset, &p, &reclen,
+ I386OMF_OFFSET_SIZE_16))
+ return FALSE;
+
+ if (!i386omf_add_section_data (abfd, segdef->asect, offset,
+ p, reclen, rectype))
+ return FALSE;
+
+ segdef->asect->flags |= (SEC_HAS_CONTENTS |
+ SEC_LOAD |
+ SEC_ALLOC);
+
+ return TRUE;
+}
+
+static bfd_boolean
+process_record (bfd *abfd,
+ int rectype,
+ bfd_size_type reclen,
+ bfd_byte const *p)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ bfd_boolean record_ok;
+
+ switch (rectype)
+ {
+ case OMF_RECORD_THEADR: /* Translator header. */
+ record_ok = i386omf_read_string (abfd, &tdata->module_name,
+ p, reclen);
+ break;
+ case OMF_RECORD_COMENT:
+ record_ok = i386omf_read_coment (abfd, p, reclen);
+ break;
+ case OMF_RECORD_MODEND:
+ record_ok = i386omf_read_modend (abfd, p, reclen);
+ break;
+ case OMF_RECORD_EXTDEF:
+ record_ok = i386omf_read_extdef (abfd, p, reclen);
+ break;
+ case OMF_RECORD_PUBDEF:
+ record_ok = i386omf_read_pubdef (abfd, p, reclen);
+ break;
+ case OMF_RECORD_LINNUM:
+ record_ok = TRUE; /* Line numbers record. Too lazy now. */
+ break;
+ case OMF_RECORD_LNAMES: /* List of names. */
+ record_ok = i386omf_read_lnames (abfd, p, reclen);
+ break;
+ case OMF_RECORD_SEGDEF:
+ record_ok = i386omf_read_segdef (abfd, p, reclen);
+ break;
+ case OMF_RECORD_GRPDEF:
+ record_ok = i386omf_read_grpdef (abfd, p, reclen);
+ break;
+ case OMF_RECORD_FIXUPP:
+ record_ok = i386omf_read_fixupp (abfd, p, reclen);
+ break;
+ case OMF_RECORD_LEDATA:
+ case OMF_RECORD_LIDATA:
+ record_ok = i386omf_read_leidata (abfd, p, reclen, rectype);
+ break;
+ default:
+ bfd_set_error (bfd_error_wrong_format);
+ record_ok = FALSE;
+ }
+
+ return record_ok;
+}
+
+static bfd_boolean
+i386omf_setup_tdata (bfd *abfd)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct strtab **strtabs[] = {
+ &tdata->lnames,
+ &tdata->segdef,
+ &tdata->grpdef,
+ &tdata->externs,
+ &tdata->abs_pubdef,
+ &tdata->dependencies,
+ NULL
+ };
+ signed int i;
+
+ for (i = 0; strtabs[i] != NULL; i++)
+ {
+ *strtabs[i] = strtab_new (abfd);
+ if (*strtabs[i] == NULL)
+ {
+ /* Unwind all the allocated strtabs, but no others. */
+ while (i >= 0)
+ {
+ strtab_free (*strtabs[i]);
+ i--;
+ }
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+static void
+i386omf_teardown_tdata (bfd *abfd)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct strtab **strtabs[] = {
+ &tdata->lnames,
+ &tdata->segdef,
+ &tdata->grpdef,
+ &tdata->externs,
+ &tdata->abs_pubdef,
+ &tdata->dependencies,
+ NULL
+ };
+ int i;
+
+ /* SEGDEF records refer to sub-strtab objects. Free them. */
+ for (i = 0; i < strtab_size (tdata->segdef); i++)
+ {
+ struct i386omf_segment *seg = strtab_lookup (tdata->segdef, i);
+ if (seg != NULL)
+ {
+ strtab_free (seg->relocs);
+ strtab_free (seg->pubdef);
+ }
+ }
+
+ for (i = 0; strtabs[i] != NULL; i++)
+ {
+ strtab_free (*strtabs[i]);
+ }
+
+ bfd_free_window (&tdata->window);
+}
+
+static bfd_boolean
+i386omf_readobject (bfd *abfd, bfd_size_type osize)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ bfd_byte const *p;
+
+ bfd_init_window (&tdata->window);
+ if (!bfd_get_file_window (abfd, 0, osize, &tdata->window, FALSE))
+ return FALSE;
+
+ tdata->image = tdata->window.data;
+ strtab_add (tdata->lnames, NULL);
+ strtab_add (tdata->segdef, NULL);
+ strtab_add (tdata->grpdef, NULL);
+ strtab_add (tdata->externs, NULL);
+
+ /* A quick cheap check for the right file format. */
+ if (!osize || bfd_get_8 (abfd, tdata->image) != OMF_RECORD_THEADR)
+ {
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ for (p = tdata->image; osize > OMF_RECORD_HEADER; )
+ {
+ int rectype;
+ bfd_size_type reclen;
+
+ rectype = bfd_get_8 (abfd, p);
+ reclen = bfd_get_16 (abfd, p + 1);
+
+ if (reclen + OMF_RECORD_HEADER > osize)
+ {
+ (*_bfd_error_handler) ("Record at 0x%lx overruns input file",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ if (!process_record (abfd, rectype,
+ reclen ? reclen - 1 : 0, p + OMF_RECORD_HEADER))
+ {
+ switch (bfd_get_error ())
+ {
+ case bfd_error_no_error:
+ break;
+ case bfd_error_wrong_format:
+ /* Silent exit. */
+ return FALSE;
+ default:
+ (*_bfd_error_handler) ("process_record() failed at 0x%lx",
+ p - tdata->image);
+ hexdump (p, reclen + OMF_RECORD_HEADER);
+ (*_bfd_error_handler) ("BFD error = %d", bfd_get_error());
+ return FALSE;
+ }
+ }
+
+ osize -= reclen + OMF_RECORD_HEADER;
+ p += reclen + OMF_RECORD_HEADER;
+ }
+
+ if (osize > 0)
+ {
+ (*_bfd_error_handler) ("input file has trailing garbage at 0x%lx",
+ p - tdata->image);
+ bfd_set_error (bfd_error_wrong_format);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static const bfd_target *
+i386omf_object_p (bfd *abfd)
+{
+ struct bfd_preserve preserve;
+ struct stat statbuf;
+
+ abfd->symcount = 0;
+
+ /* Find the file size. */
+ if (bfd_stat (abfd, &statbuf) < 0)
+ {
+ bfd_set_error (bfd_error_system_call);
+ return NULL;
+ }
+
+ if (!bfd_preserve_save (abfd, &preserve))
+ return NULL;
+
+ preserve.marker = bfd_zalloc (abfd, sizeof (struct i386omf_obj_data));
+ if (preserve.marker == NULL)
+ {
+ bfd_preserve_restore (abfd, &preserve);
+ bfd_set_error (bfd_error_no_memory);
+ return NULL;
+ }
+
+ abfd->tdata.any = preserve.marker;
+ if (!i386omf_setup_tdata (abfd))
+ {
+ bfd_preserve_restore (abfd, &preserve);
+ return NULL;
+ }
+ if (!i386omf_readobject (abfd, statbuf.st_size))
+ {
+ /* Tear tdata down before bfd_preserve_restore invalidates it. */
+ i386omf_teardown_tdata (abfd);
+
+ bfd_preserve_restore (abfd, &preserve);
+ return NULL;
+ }
+
+ bfd_preserve_finish (abfd, &preserve);
+
+ if (bfd_get_arch_info (abfd) == NULL
+ || bfd_get_arch_info (abfd)->arch == bfd_arch_unknown)
+ bfd_set_arch_info (abfd, bfd_lookup_arch
+ (bfd_arch_i386, bfd_mach_i386_i8086));
+
+ return abfd->xvec;
+}
+
+static bfd_boolean
+i386omf_close_and_cleanup (bfd *abfd)
+{
+ i386omf_teardown_tdata (abfd);
+ return TRUE;
+}
+
+#define i386omf_bfd_free_cached_info _bfd_generic_bfd_free_cached_info
+#define i386omf_new_section_hook _bfd_generic_new_section_hook
+
+static bfd_boolean
+i386omf_get_section_contents (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *section,
+ void * location,
+ file_ptr offset,
+ bfd_size_type count)
+{
+ if (section->flags & SEC_IN_MEMORY)
+ memcpy (location, section->contents + offset, count);
+ else
+ memset (location, 0, count);
+
+ return TRUE;
+}
+
+/* Return the amount of memory needed to read the symbol table. */
+
+static long
+i386omf_get_symtab_upper_bound (bfd *abfd)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct i386omf_segment *seg;
+ long n = 0;
+ int i;
+
+ for (i = 1; (seg = strtab_lookup (tdata->segdef, i)) != NULL; i++)
+ n += strtab_size (seg->pubdef);
+ n += strtab_size (tdata->externs) - 1;
+
+ return n * sizeof (asymbol *);
+}
+
+/* Return the symbol table. */
+
+static long
+i386omf_canonicalize_symtab (bfd *abfd, asymbol **alocation)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct i386omf_segment *seg;
+ struct i386omf_symbol *sym;
+ int j;
+ long n = 0;
+
+ for (j = 1; (seg = strtab_lookup (tdata->segdef, j)) != NULL; j++)
+ {
+ int i;
+
+ for (i = 0; (sym = strtab_lookup (seg->pubdef, i)) != NULL; i++)
+ alocation[n++] = &sym->base;
+ }
+
+ for (j = 1; (sym = strtab_lookup (tdata->externs, j)) != NULL; j++)
+ alocation[n++] = &sym->base;
+
+ abfd->symcount += n;
+
+ return n;
+}
+
+#define i386omf_bfd_copy_private_bfd_data \
+ _bfd_generic_bfd_copy_private_bfd_data
+#define i386omf_bfd_merge_private_bfd_data \
+ _bfd_generic_bfd_merge_private_bfd_data
+#define i386omf_bfd_copy_private_section_data \
+ _bfd_generic_bfd_copy_private_section_data
+#define i386omf_bfd_copy_private_symbol_data \
+ _bfd_generic_bfd_copy_private_symbol_data
+#define i386omf_bfd_copy_private_header_data \
+ _bfd_generic_bfd_copy_private_header_data
+#define i386omf_bfd_set_private_flags \
+ _bfd_generic_bfd_set_private_flags
+
+static bfd_boolean
+i386omf_bfd_print_private_bfd_data (bfd *abfd, void *farg)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct i386omf_segment *seg;
+ struct i386omf_group *grp;
+ FILE *f = farg;
+ struct counted_string const *s;
+ int i;
+
+ fprintf (f, "\nModule name: %s\n", tdata->module_name.data);
+ if (tdata->is_main_module) {
+ fprintf (f, "Main module\n");
+ }
+ if (tdata->has_start_address) {
+ fprintf (f, "Has start address\n");
+ }
+ if (tdata->translator)
+ fprintf (f, "Translator: %s\n", tdata->translator);
+ if (strtab_size (tdata->dependencies))
+ {
+ struct i386omf_borland_dependency *dep;
+
+ fprintf (f, "Dependencies:\n");
+ for (i = 0; (dep = strtab_lookup (tdata->dependencies, i)); i++)
+ {
+ fprintf (f, " %04d-%02d-%02d %02d:%02d:%02d %s\n",
+ ((dep->date >> OMF_MSDOS_DATE_YEAR_SHIFT)
+ & W2M(OMF_MSDOS_DATE_YEAR_WIDTH)) + 1980,
+ (dep->date >> OMF_MSDOS_DATE_MONTH_SHIFT)
+ & W2M(OMF_MSDOS_DATE_MONTH_WIDTH),
+ dep->date & W2M(OMF_MSDOS_DATE_DAY_WIDTH),
+ (dep->time >> OMF_MSDOS_TIME_HOUR_SHIFT)
+ & W2M(OMF_MSDOS_TIME_HOUR_WIDTH),
+ (dep->time >> OMF_MSDOS_TIME_MINUTE_SHIFT)
+ & W2M(OMF_MSDOS_TIME_MINUTE_WIDTH),
+ (dep->time & W2M(OMF_MSDOS_TIME_2SECOND_WIDTH)) * 2,
+ dep->filename.data);
+ }
+ }
+ fprintf (f, "LNAMES:\n");
+ for (i = OMF_LNAMES_NONE + 1; (s = strtab_lookup (tdata->lnames, i)); i++)
+ {
+ fprintf (f, " %d %s\n", i, s->data);
+ }
+ fprintf (f, "SEGDEF:\n");
+ for (i = OMF_SEGDEF_NONE + 1; (seg = strtab_lookup (tdata->segdef, i)); i++)
+ {
+ fprintf (f, " %s (%d)\n",
+ i386omf_lookup_string(tdata->lnames, seg->name_index,
+ "UNNAMED"),
+ seg->name_index);
+ }
+ fprintf (f, "GRPDEF:\n");
+ for (i = OMF_GRPDEF_NONE + 1; (grp = strtab_lookup (tdata->grpdef, i)); i++)
+ {
+ struct i386omf_group_entry *entry;
+ int j;
+
+ fprintf (f, " %s (%d)",
+ i386omf_lookup_string (tdata->lnames, grp->name_index,
+ "UNNAMED"),
+ grp->name_index);
+
+ for (j = 0; (entry = strtab_lookup (grp->entries, j)); j++)
+ {
+ switch (entry->type)
+ {
+ case GRPDEF_ENTRY_SEGDEF:
+ fprintf (f, " (%d)", entry->u.segdef);
+ break;
+ default:
+ fprintf (f, " ??? (type=0x%02x)", entry->type);
+ break;
+ }
+ }
+
+ fprintf (f, "\n");
+ }
+
+ return FALSE;
+}
+
+static asymbol *
+i386omf_make_empty_symbol (bfd *abfd)
+{
+ bfd_size_type amt = sizeof (struct i386omf_symbol);
+ asymbol *new = bfd_zalloc (abfd, amt);
+ if (new)
+ new->the_bfd = abfd;
+ return new;
+}
+
+static void
+i386omf_print_symbol (bfd *abfd, void *afile, struct bfd_symbol *sym, bfd_print_symbol_type how)
+{
+ struct i386omf_obj_data *tdata = abfd->tdata.any;
+ struct i386omf_symbol *bigsym = (struct i386omf_symbol *) sym;
+ char const *groupname;
+ FILE *f = afile;
+
+ switch (how)
+ {
+ case bfd_print_symbol_name:
+ default:
+ if (sym->name)
+ fprintf (f, "%s%s", sym->name, tdata->has_start_address ? "" : "");
+ break;
+ case bfd_print_symbol_more:
+ fprintf (f, "%3d", bigsym->type_index);
+ break;
+ case bfd_print_symbol_all:
+ bfd_print_symbol_vandf (abfd, (void *) f, sym);
+ if (bigsym->group)
+ groupname = i386omf_lookup_string (tdata->lnames,
+ bigsym->group->name_index, "");
+ else
+ groupname = "";
+ fprintf (f, " %-16s %-10s %3d", sym->name, groupname,
+ bigsym->type_index);
+ break;
+ }
+
+ /* TODO: Check that base group is sane. */
+}
+
+/* Get information about a symbol. */
+
+static void
+i386omf_get_symbol_info (bfd *ignore_abfd ATTRIBUTE_UNUSED,
+ asymbol *symbol,
+ symbol_info *ret)
+{
+ bfd_symbol_info (symbol, ret);
+}
+
+#define i386omf_bfd_is_local_label_name bfd_generic_is_local_label_name
+#define i386omf_get_lineno _bfd_nosymbols_get_lineno
+#define i386omf_find_nearest_line _bfd_nosymbols_find_nearest_line
+#define i386omf_find_inliner_info _bfd_nosymbols_find_inliner_info
+#define i386omf_bfd_make_debug_symbol _bfd_nosymbols_bfd_make_debug_symbol
+#define i386omf_read_minisymbols _bfd_generic_read_minisymbols
+#define i386omf_minisymbol_to_symbol _bfd_generic_minisymbol_to_symbol
+#define i386omf_bfd_is_target_special_symbol ((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
+
+static long
+i386omf_get_reloc_upper_bound (bfd *abfd ATTRIBUTE_UNUSED, asection *sec)
+{
+ struct i386omf_segment *seg = sec->used_by_bfd;
+ long n = strtab_size (seg->relocs);
+
+ return n * sizeof (arelent *);
+}
+
+static long
+i386omf_canonicalize_reloc (bfd *abfd ATTRIBUTE_UNUSED,
+ asection *sec,
+ arelent **relptr,
+ asymbol **symbols ATTRIBUTE_UNUSED)
+{
+ struct i386omf_segment *seg = sec->used_by_bfd;
+ struct i386omf_relent *relent;
+ long n = 0;
+ int i;
+
+ for (i = 0; (relent = strtab_lookup (seg->relocs, i)) != NULL; i++)
+ relptr[n++] = &relent->base;
+
+ return n;
+}
+
+#define i386omf_bfd_reloc_type_lookup bfd_default_reloc_type_lookup
+#define i386omf_bfd_reloc_name_lookup _bfd_norelocs_bfd_reloc_name_lookup
+
+/* Set the architecture of a binary file. */
+#define binary_set_arch_mach _bfd_generic_set_arch_mach
+
+/* Write section contents of a binary file. */
+
+static bfd_boolean
+binary_set_section_contents (bfd *abfd,
+ asection *sec,
+ const void * data,
+ file_ptr offset,
+ bfd_size_type size)
+{
+ if (size == 0)
+ return TRUE;
+
+ if (! abfd->output_has_begun)
+ {
+ bfd_boolean found_low;
+ bfd_vma low;
+ asection *s;
+
+ /* The lowest section LMA sets the virtual address of the start
+ of the file. We use this to set the file position of all the
+ sections. */
+ found_low = FALSE;
+ low = 0;
+ for (s = abfd->sections; s != NULL; s = s->next)
+ if (((s->flags
+ & (SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC | SEC_NEVER_LOAD))
+ == (SEC_HAS_CONTENTS | SEC_LOAD | SEC_ALLOC))
+ && (s->size > 0)
+ && (! found_low || s->lma < low))
+ {
+ low = s->lma;
+ found_low = TRUE;
+ }
+
+ for (s = abfd->sections; s != NULL; s = s->next)
+ {
+ s->filepos = s->lma - low;
+
+ /* Skip following warning check for sections that will not
+ occupy file space. */
+ if ((s->flags
+ & (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_NEVER_LOAD))
+ != (SEC_HAS_CONTENTS | SEC_ALLOC)
+ || (s->size == 0))
+ continue;
+
+ /* If attempting to generate a binary file from a bfd with
+ LMA's all over the place, huge (sparse?) binary files may
+ result. This condition attempts to detect this situation
+ and print a warning. Better heuristics would be nice to
+ have. */
+
+ if (s->filepos < 0)
+ (*_bfd_error_handler)
+ (_("Warning: Writing section `%s' to huge (ie negative) file offset 0x%lx."),
+ bfd_get_section_name (abfd, s),
+ (unsigned long) s->filepos);
+ }
+
+ abfd->output_has_begun = TRUE;
+ }
+
+ /* We don't want to output anything for a section that is neither
+ loaded nor allocated. The contents of such a section are not
+ meaningful in the binary format. */
+ if ((sec->flags & (SEC_LOAD | SEC_ALLOC)) == 0)
+ return TRUE;
+ if ((sec->flags & SEC_NEVER_LOAD) != 0)
+ return TRUE;
+
+ return _bfd_generic_set_section_contents (abfd, sec, data, offset, size);
+}
+
+/* No space is required for header information. */
+
+static int
+binary_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
+ struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+#define binary_bfd_get_relocated_section_contents bfd_generic_get_relocated_section_contents
+#define binary_bfd_relax_section bfd_generic_relax_section
+#define binary_bfd_gc_sections bfd_generic_gc_sections
+#define binary_bfd_merge_sections bfd_generic_merge_sections
+#define binary_bfd_is_group_section bfd_generic_is_group_section
+#define binary_bfd_discard_group bfd_generic_discard_group
+#define binary_section_already_linked _bfd_generic_section_already_linked
+#define binary_bfd_define_common_symbol bfd_generic_define_common_symbol
+#define binary_bfd_link_hash_table_create _bfd_generic_link_hash_table_create
+#define binary_bfd_link_hash_table_free _bfd_generic_link_hash_table_free
+#define binary_bfd_link_just_syms _bfd_generic_link_just_syms
+#define binary_bfd_copy_link_hash_symbol_type \
+ _bfd_generic_copy_link_hash_symbol_type
+#define binary_bfd_link_add_symbols _bfd_generic_link_add_symbols
+#define binary_bfd_final_link _bfd_generic_final_link
+#define binary_bfd_link_split_section _bfd_generic_link_split_section
+#define i386omf_get_section_contents_in_window _bfd_generic_get_section_contents_in_window
+
+const bfd_target i386omf_vec =
+{
+ "i386omf", /* name */
+ bfd_target_omf_flavour, /* flavour */
+ BFD_ENDIAN_LITTLE, /* byteorder */
+ BFD_ENDIAN_LITTLE, /* header_byteorder */
+ (HAS_RELOC | HAS_SYMS | HAS_LOCALS), /* object_flags */
+ (SEC_ALLOC | SEC_LOAD | SEC_LOAD | SEC_RELOC | SEC_READONLY
+ | SEC_CODE | SEC_DATA | SEC_ROM | SEC_HAS_CONTENTS
+ | SEC_IN_MEMORY | SEC_GROUP), /* section_flags */
+ 0, /* symbol_leading_char */
+ ' ', /* ar_pad_char */
+ 16, /* ar_max_namelen */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* data */
+ bfd_getl64, bfd_getl_signed_64, bfd_putl64,
+ bfd_getl32, bfd_getl_signed_32, bfd_putl32,
+ bfd_getl16, bfd_getl_signed_16, bfd_putl16, /* hdrs */
+ { /* bfd_check_format */
+ _bfd_dummy_target,
+ i386omf_object_p,
+ _bfd_dummy_target,
+ _bfd_dummy_target,
+ },
+ { /* bfd_set_format */
+ bfd_false,
+ binary_mkobject,
+ bfd_false,
+ bfd_false,
+ },
+ { /* bfd_write_contents */
+ bfd_false,
+ bfd_true,
+ bfd_false,
+ bfd_false,
+ },
+
+ BFD_JUMP_TABLE_GENERIC (i386omf),
+ BFD_JUMP_TABLE_COPY (i386omf),
+ BFD_JUMP_TABLE_CORE (_bfd_nocore),
+ BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+ BFD_JUMP_TABLE_SYMBOLS (i386omf),
+ BFD_JUMP_TABLE_RELOCS (i386omf),
+ BFD_JUMP_TABLE_WRITE (binary),
+ BFD_JUMP_TABLE_LINK (binary),
+ BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+ NULL,
+
+ NULL
+};
diff --git a/bfd/strtab.c b/bfd/strtab.c
new file mode 100644
index 0000000..a745acc
--- /dev/null
+++ b/bfd/strtab.c
@@ -0,0 +1,80 @@
+#include "bfd.h"
+#include "strtab.h"
+#include "sysdep.h"
+#include "libbfd.h"
+#include "strtab.h"
+
+#define STRTAB_INIT_SIZE 256
+
+struct strtab {
+ bfd *owner;
+ void **strings;
+ int strings_used;
+ int strings_size;
+};
+
+struct strtab *
+strtab_new(bfd *abfd)
+{
+ struct strtab *st;
+
+ st = bfd_malloc (sizeof (*st));
+ if (st == NULL)
+ return NULL;
+ st->owner = abfd;
+ st->strings = bfd_malloc2 (STRTAB_INIT_SIZE, sizeof (*st->strings));
+ if (st->strings == NULL)
+ {
+ free (st);
+ return NULL;
+ }
+ st->strings_used = 0;
+ st->strings_size = STRTAB_INIT_SIZE;
+
+ return st;
+}
+
+void
+strtab_free (struct strtab *st ATTRIBUTE_UNUSED)
+{
+ free (st->strings);
+ free (st);
+}
+
+int strtab_size(struct strtab const *st)
+{
+ return (st->strings_used);
+}
+
+int strtab_add(struct strtab *st, void *s)
+{
+ if (st->strings_used >= st->strings_size)
+ {
+ void **newstrings;
+ int newsize = st->strings_size * 2;
+
+ newstrings = bfd_realloc2 (st->strings, newsize, sizeof (*st->strings));
+ if (newstrings == NULL)
+ {
+ (*_bfd_error_handler) ("strings_used %d >= strings_size %d",
+ st->strings_used, st->strings_size);
+ abort();
+ }
+
+ st->strings = newstrings;
+ st->strings_size = newsize;
+ }
+
+ st->strings[st->strings_used++] = s;
+
+ return (st->strings_used - 1);
+}
+
+void *
+strtab_lookup(struct strtab *st, int i)
+{
+ if (i >= st->strings_used)
+ return NULL;
+
+ return (st->strings[i]);
+}
diff --git a/bfd/strtab.h b/bfd/strtab.h
new file mode 100644
index 0000000..7ea6d4b
--- /dev/null
+++ b/bfd/strtab.h
@@ -0,0 +1,9 @@
+#include "bfd.h"
+
+struct strtab;
+
+struct strtab *strtab_new(bfd *abfd);
+void strtab_free (struct strtab *st);
+int strtab_size(struct strtab const *st);
+int strtab_add(struct strtab *st, void *s);
+void *strtab_lookup(struct strtab *st, int i);
diff --git a/bfd/targets.c b/bfd/targets.c
index e491c93..fccd0b8 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -163,6 +163,7 @@ DESCRIPTION
. bfd_target_os9k_flavour,
. bfd_target_versados_flavour,
. bfd_target_msdos_flavour,
+. bfd_target_omf_flavour,
. bfd_target_ovax_flavour,
. bfd_target_evax_flavour,
. bfd_target_mmo_flavour,
@@ -758,6 +759,7 @@ extern const bfd_target i386lynx_coff_vec;
extern const bfd_target i386mach3_vec;
extern const bfd_target i386msdos_vec;
extern const bfd_target i386netbsd_vec;
+extern const bfd_target i386omf_vec;
extern const bfd_target i386os9k_vec;
extern const bfd_target i386pe_vec;
extern const bfd_target i386pei_vec;
@@ -1136,6 +1138,7 @@ static const bfd_target * const _bfd_target_vector[] =
#endif
&i386msdos_vec,
&i386netbsd_vec,
+ &i386omf_vec,
&i386os9k_vec,
&i386pe_vec,
&i386pei_vec,