This is the mail archive of the binutils@sourceware.org mailing list for the binutils project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

New backend: LDA / SIMH Tape files


Hi!

I'm working on a new BFD backend right now. It is ment to build LDA
files. They were used (punched in paper tapes) to boot eg. the RT-11
operating system on PDP11 machines. Apart from real PDP11 punch tape
readers, the format is eg. used by SIMH[1] to boot the virtual
computers it supports.

Since Binutils and GCC support these machines eg. with their PDP11 and
VAX targets, I've built this backend to be able to use objcopy to
generate bootable (virtual) paper tapes from simple compiled a.out
binaries.

The code is not yet finished and fully tested, but I would like to get
feedback in this early stage. Right now, I see these open issues:

  * How to build some (useful) testcases? Most of the existing
    testcases test other specific features, not basic output formats.

  * The target bfd will be rarely used, but it's not too invasive.
    Should I actually submit it for inclusion?

  * It is derived from ihex.c and srec.c.  Shall I keep their
    copyright years listed?

  * Can I omit simhtape_sizeof_headers() and simhtape_set_arch_mach()?

  * NEWS entry and some documentation should be written

In the following patch, I've omitted generated files to keep noise
low. It would be nice if you'd give me some feedback on it.

Thanks, JBG

[1] http://simh.trailing-edge.com/
    https://github.com/simh/simh/


diff --git a/bfd/Makefile.am b/bfd/Makefile.am
index b7271cc..963a89c 100644
--- a/bfd/Makefile.am
+++ b/bfd/Makefile.am
@@ -54,7 +54,8 @@ BFD32_LIBS = \
 	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 stab-syms.lo \
-	merge.lo dwarf2.lo simple.lo compress.lo verilog.lo
+	merge.lo dwarf2.lo simple.lo compress.lo verilog.lo \
+	simhtape.lo
 
 BFD64_LIBS = archive64.lo
 
@@ -64,7 +65,8 @@ BFD32_LIBS_CFILES = \
 	format.c init.c libbfd.c opncls.c reloc.c \
 	section.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
+	merge.c dwarf2.c simple.c compress.c verilog.c \
+	simhtape.c
 
 BFD64_LIBS_CFILES = archive64.c
 
diff --git a/bfd/configure.com b/bfd/configure.com
index a19dadd..9edca5d 100644
--- a/bfd/configure.com
+++ b/bfd/configure.com
@@ -382,7 +382,7 @@ $ CFLAGS="/name=(as_is,shortened)" + -
   "/define=(" + DEFS + ")" + OPT
 $ FILES=FILES + "archive,archive64,archures,bfd,bfdio,binary,cache,coffgen,"+-
   "compress,corefile,dwarf2,elf,format,hash,ihex,init,libbfd,linker,"+-
-  "opncls,reloc,section,simple,srec,stab-syms,syms,targets,tekhex,verilog"
+  "opncls,reloc,section,simple,srec,simhtape,stab-syms,syms,targets,tekhex,verilog"
 $ write sys$output "CFLAGS=",CFLAGS
 $ cflags_libbfd="/warning=(disable=missingreturn)"
 $ cflags_nil=""
diff --git a/bfd/configure.in b/bfd/configure.in
index 97fff61..6a1658a 100644
--- a/bfd/configure.in
+++ b/bfd/configure.in
@@ -996,6 +996,7 @@ do
     tekhex_vec)			tb="$tb tekhex.lo" ;;
     cisco_core_big_vec)		tb="$tb cisco-core.lo" ;;
     cisco_core_little_vec)	tb="$tb cisco-core.lo" ;;
+    simhtape_vec)		tb="$tb simhtape.lo" ;;
 
     "")			;;
     *) AC_MSG_ERROR(*** unknown target vector $vec) ;;
diff --git a/bfd/makefile.vms b/bfd/makefile.vms
index 3c7f721..daa7186 100644
--- a/bfd/makefile.vms
+++ b/bfd/makefile.vms
@@ -25,7 +25,7 @@ OBJS:=$(OBJS),archive.obj,archive64.obj,archures.obj,bfd.obj,bfdio.obj,\
   binary.obj,cache.obj,coffgen.obj,compress.obj,corefile.obj,dwarf2.obj,\
   elf.obj,format.obj,hash.obj,ihex.obj,init.obj,libbfd.obj,linker.obj,\
   opncls.obj,reloc.obj,section.obj,simple.obj,srec.obj,stab-syms.obj,\
-  syms.obj,targets.obj,tekhex.obj,verilog.obj
+  syms.obj,targets.obj,tekhex.obj,verilog.obj,simhtape.obj
 
 ifeq ($(CC),gcc)
 CFLAGS=/include=([],[-.include])$(DEFS)
diff --git a/bfd/simhtape.c b/bfd/simhtape.c
new file mode 100644
index 0000000..1998c15
--- /dev/null
+++ b/bfd/simhtape.c
@@ -0,0 +1,324 @@
+/* BFD back-end for LDA / SIMH Tape files
+   Derived from srec.c and ihex.h
+
+   Copyright 2012
+   Free Software Foundation, Inc.
+   Written by Steve Chamberlain of Cygnus Support <sac@cygnus.com>.
+
+   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 3 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.  */
+
+
+/* SUBSECTION
+	LDA / SIMH tape handling
+
+   DESCRIPTION
+	The LDA format was used to boot early computers (PDP11) with
+	paper tapes. To fit that era, the format is quite simple. It
+	consists of variable-sized blocks, each of which resembles
+	one section. Each section's header looks like this:
+
+	Offs.	0	0x01	Fixed byte
+		1	0x00	Fixed byte
+		2	var.	LSB of this section's size, including
+				the 6-byte header. 16bit value
+		3	var.	MSB of this section's size
+		4	var.	LSB of this section's load address,
+				16bit value
+		5	var.	MSB of section's load address.
+	
+	This header is usually followed by data, as indicated by header's
+	third and fourth byte.
+
+	A special cast is where the indicated size is only 6 bytes,
+	thus only the header without actual data bytes. In this case,
+	this section's load address is interpreted as a start address
+	of the binary.
+*/
+
+#include "sysdep.h"
+#include "bfd.h"
+#include "libbfd.h"
+#include "libiberty.h"
+#include "safe-ctype.h"
+
+/* When we write out an SIMH Tape value, the values can not be output as
+   they are seen.  Instead, we hold them in memory in this structure.  */
+
+struct simhtape_data_list
+{
+  struct simhtape_data_list *next;
+  bfd_byte *data;
+  bfd_vma where;
+  bfd_size_type size;
+};
+
+/* The SIMH Tape tdata information.  */
+
+struct simhtape_data_struct
+{
+  struct simhtape_data_list *head;
+  struct simhtape_data_list *tail;
+};
+
+/* Set the architecture for the output file.  The architecture is
+   irrelevant, so we ignore errors about unknown architectures.  */
+
+static bfd_boolean
+simhtape_set_arch_mach (bfd *abfd,
+			enum bfd_architecture arch,
+			unsigned long mach)
+{
+  if (! bfd_default_set_arch_mach (abfd, arch, mach))
+    {
+      if (arch != bfd_arch_unknown)
+	return FALSE;
+    }
+  return TRUE;
+}
+
+/* Get the size of the headers, for the linker.  */
+
+static int
+simhtape_sizeof_headers (bfd *abfd ATTRIBUTE_UNUSED,
+			 struct bfd_link_info *info ATTRIBUTE_UNUSED)
+{
+  return 0;
+}
+
+/* Create an SIMH Tape object.  */
+
+static bfd_boolean
+simhtape_mkobject (bfd *abfd)
+{
+  struct simhtape_data_struct *tdata;
+
+  tdata = (struct simhtape_data_struct *) bfd_alloc (abfd, sizeof (* tdata));
+  if (tdata == NULL)
+    return FALSE;
+
+  abfd->tdata.simhtape_data = tdata;
+  tdata->head = NULL;
+  tdata->tail = NULL;
+  return TRUE;
+}
+
+/* Output one SIMH Tape section with its checksum.  */
+
+static bfd_boolean
+simhtape_write_record (bfd *abfd, 
+		       unsigned int addr,
+		       size_t count,
+		       bfd_byte *data)
+{
+  int check = 0;
+  unsigned char checksum_byte;
+  unsigned int i;
+  unsigned char header[6] = {	0x01,						/* Fixed header.  */
+				0x00,						/* Fixed header.  */
+				((count + sizeof (header)) >> 0) & 0xff,	/* LSB size.  */
+				((count + sizeof (header)) >> 8) & 0xff,	/* MSB size.  */
+				(addr >> 0) & 0xff,				/* LSB addr.  */
+				(addr >> 8) & 0xff,				/* MSB addr.  */
+  };
+
+  /* Write header to file.  */
+  if (bfd_bwrite (header, sizeof (header), abfd) != sizeof (header))
+    return FALSE;
+
+  /* Include header into checksum.  */
+  for (i = 0; i < sizeof (header); i++)
+    check += header[i];
+
+  /* Output actual section contents.  */
+  for (i = 0; i < count; i++)
+    {
+      if (bfd_bwrite (&data[i], 1, abfd) != 1)
+	return FALSE;
+      check += data[i];
+    }
+
+  /* Prepare and output final checksum byte.  */
+  checksum_byte = (unsigned char) check & 0xff;
+  checksum_byte = 0 - checksum_byte;
+  if (bfd_bwrite (&checksum_byte, sizeof (checksum_byte), abfd) != sizeof (checksum_byte))
+    return FALSE;
+
+  return TRUE;
+}
+
+/* Write out an SIMH Tape file.  */
+static bfd_boolean
+simhtape_write_object_contents (bfd *abfd)
+{
+  struct simhtape_data_list *l;
+
+  /* Loop over all sections.  */
+  for (l = abfd->tdata.simhtape_data->head; l != NULL; l = l->next)
+    simhtape_write_record (abfd, l->where, l->size, l->data);
+
+  /* Write start address.  */
+  simhtape_write_record (abfd, abfd->start_address, 0, NULL);
+
+  return TRUE;
+}
+
+/* Set the contents of a section in an SIMH Tape file.  */
+
+static bfd_boolean
+simhtape_set_section_contents (bfd *abfd,
+			       asection *section,
+			       const void * location,
+			       file_ptr offset,
+			       bfd_size_type count)
+{
+  struct simhtape_data_list *n;
+  bfd_byte *data;
+  struct simhtape_data_struct *tdata;
+
+  if (count == 0
+      || (section->flags & SEC_ALLOC) == 0
+      || (section->flags & SEC_LOAD) == 0)
+    return TRUE;
+
+  n = (struct simhtape_data_list *) bfd_alloc (abfd, sizeof (* n));
+  if (n == NULL)
+    return FALSE;
+
+  data = (bfd_byte *) bfd_alloc (abfd, count);
+  if (data == NULL)
+    return FALSE;
+  memcpy (data, location, (size_t) count);
+
+  n->data = data;
+  n->where = section->lma + offset;
+  n->size = count;
+
+  /* Sort the records by address.  Optimize for the common case of
+     adding a record to the end of the list.  */
+  tdata = abfd->tdata.simhtape_data;
+  if (tdata->tail != NULL
+      && n->where >= tdata->tail->where)
+    {
+      tdata->tail->next = n;
+      n->next = NULL;
+      tdata->tail = n;
+    }
+  else
+    {
+      struct simhtape_data_list **pp;
+
+      for (pp = &tdata->head;
+	   *pp != NULL && (*pp)->where < n->where;
+	   pp = &(*pp)->next)
+	;
+      n->next = *pp;
+      *pp = n;
+      if (n->next == NULL)
+	tdata->tail = n;
+    }
+
+  return TRUE;
+}
+
+#define simhtape_close_and_cleanup			_bfd_generic_close_and_cleanup
+#define simhtape_bfd_free_cached_info			_bfd_generic_bfd_free_cached_info
+#define simhtape_new_section_hook			_bfd_generic_new_section_hook
+#define simhtape_bfd_is_target_special_symbol		((bfd_boolean (*) (bfd *, asymbol *)) bfd_false)
+#define simhtape_bfd_is_local_label_name		bfd_generic_is_local_label_name
+#define simhtape_canonicalize_symtab			((long (*) (bfd *, asymbol **)) bfd_0l)
+#define simhtape_get_lineno				_bfd_nosymbols_get_lineno
+#define simhtape_find_nearest_line			_bfd_nosymbols_find_nearest_line
+#define simhtape_find_inliner_info			_bfd_nosymbols_find_inliner_info
+#define simhtape_make_empty_symbol			_bfd_generic_make_empty_symbol
+#define simhtape_bfd_make_debug_symbol			_bfd_nosymbols_bfd_make_debug_symbol
+#define simhtape_read_minisymbols			_bfd_generic_read_minisymbols
+#define simhtape_minisymbol_to_symbol			_bfd_generic_minisymbol_to_symbol
+#define simhtape_get_section_contents_in_window		_bfd_generic_get_section_contents_in_window
+#define simhtape_bfd_get_relocated_section_contents	bfd_generic_get_relocated_section_contents
+#define simhtape_bfd_relax_section			bfd_generic_relax_section
+#define simhtape_bfd_gc_sections			bfd_generic_gc_sections
+#define simhtape_bfd_lookup_section_flags		bfd_generic_lookup_section_flags
+#define simhtape_bfd_merge_sections			bfd_generic_merge_sections
+#define simhtape_bfd_is_group_section			bfd_generic_is_group_section
+#define simhtape_bfd_discard_group			bfd_generic_discard_group
+#define simhtape_section_already_linked			_bfd_generic_section_already_linked
+#define simhtape_bfd_define_common_symbol		bfd_generic_define_common_symbol
+#define simhtape_bfd_link_hash_table_create		_bfd_generic_link_hash_table_create
+#define simhtape_bfd_link_hash_table_free		_bfd_generic_link_hash_table_free
+#define simhtape_bfd_link_add_symbols			_bfd_generic_link_add_symbols
+#define simhtape_bfd_link_just_syms			_bfd_generic_link_just_syms
+#define simhtape_bfd_copy_link_hash_symbol_type		_bfd_generic_copy_link_hash_symbol_type
+#define simhtape_bfd_final_link				_bfd_generic_final_link
+#define simhtape_bfd_link_split_section			_bfd_generic_link_split_section
+#define simhtape_print_symbol				_bfd_nosymbols_print_symbol
+#define simhtape_get_symtab_upper_bound			bfd_0l
+#define simhtape_get_symbol_info			_bfd_nosymbols_get_symbol_info
+#define simhtape_get_section_contents			_bfd_generic_get_section_contents
+
+const bfd_target simhtape_vec =
+{
+  "simhtape",			/* Name.  */
+  bfd_target_simhtape_flavour,
+  BFD_ENDIAN_UNKNOWN,				/* Target byte order.  */
+  BFD_ENDIAN_UNKNOWN,				/* Target headers byte order.  */
+  0,						/* Object flags.  */
+  (SEC_HAS_CONTENTS | SEC_ALLOC | SEC_LOAD),	/* Section flags.  */
+  0,						/* Leading underscore.  */
+  ' ',						/* AR_pad_char.  */
+  16,						/* AR_max_namelen.  */
+  0,						/* match priority.  */
+  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Data.  */
+  bfd_getb64, bfd_getb_signed_64, bfd_putb64,
+  bfd_getb32, bfd_getb_signed_32, bfd_putb32,
+  bfd_getb16, bfd_getb_signed_16, bfd_putb16,	/* Hdrs.  */
+
+  {
+    _bfd_dummy_target,
+    _bfd_dummy_target,				/* bfd_check_format.  */
+    _bfd_dummy_target,
+    _bfd_dummy_target,
+  },
+  {
+    bfd_false,
+    simhtape_mkobject,
+    _bfd_generic_mkarchive,
+    bfd_false,
+  },
+  {						/* bfd_write_contents.  */
+    bfd_false,
+    simhtape_write_object_contents,
+    _bfd_write_archive_contents,
+    bfd_false,
+  },
+
+  BFD_JUMP_TABLE_GENERIC (simhtape),
+  BFD_JUMP_TABLE_COPY (_bfd_generic),
+  BFD_JUMP_TABLE_CORE (_bfd_nocore),
+  BFD_JUMP_TABLE_ARCHIVE (_bfd_noarchive),
+  BFD_JUMP_TABLE_SYMBOLS (simhtape),
+  BFD_JUMP_TABLE_RELOCS (_bfd_norelocs),
+  BFD_JUMP_TABLE_WRITE (simhtape),
+  BFD_JUMP_TABLE_LINK (simhtape),
+  BFD_JUMP_TABLE_DYNAMIC (_bfd_nodynamic),
+
+  NULL,
+
+  NULL
+};
diff --git a/bfd/targets.c b/bfd/targets.c
index ce1cf35..fa582a8 100644
--- a/bfd/targets.c
+++ b/bfd/targets.c
@@ -157,6 +157,7 @@ DESCRIPTION
 .  bfd_target_oasys_flavour,
 .  bfd_target_tekhex_flavour,
 .  bfd_target_srec_flavour,
+.  bfd_target_simhtape_flavour,
 .  bfd_target_verilog_flavour,
 .  bfd_target_ihex_flavour,
 .  bfd_target_som_flavour,
@@ -894,6 +895,7 @@ extern const bfd_target symbolsrec_vec;
 extern const bfd_target tekhex_vec;
 extern const bfd_target binary_vec;
 extern const bfd_target ihex_vec;
+extern const bfd_target simhtape_vec;
 
 /* All of the xvecs for core files.  */
 extern const bfd_target aix386_core_vec;
@@ -1321,6 +1323,8 @@ static const bfd_target * const _bfd_target_vector[] =
 	&binary_vec,
 /* Likewise for ihex.  */
 	&ihex_vec,
+/* And simhtape.  */
+	&simhtape_vec,
 
 /* Add any required traditional-core-file-handler.  */
 

-- 
      Jan-Benedict Glaw      jbglaw@lug-owl.de              +49-172-7608481
Signature of:                http://catb.org/~esr/faqs/smart-questions.html
the second  :

Attachment: signature.asc
Description: Digital signature


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]