--- /dev/null
+CFLAGS = -g -O2 -Wall -Wno-parentheses -DINDEXLIB -DUNIX -I.
+LDFLAGS =
+
+SRC = lk_readnl.c lkaomf51.c lkar.c lkarea.c lkdata.c lkelf.c lkeval.c \
+ lkhead.c lklex.c lklib.c lklibr.c lklist.c lkmain.c lkmem.c \
+ lknoice.c lkout.c lkrel.c lkrloc.c lkrloc3.c lks19.c lksdcclib.c \
+ lksym.c sdld.c lksdcdb.c lkbank.c
+
+OBJS = $(SRC:%.c=%.o)
+LKOBJECTS = $(OBJS)
+
+sdldz80: $(LKOBJECTS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(LKOBJECTS)
+
+$(LKOBJECTS) : aslink.h
+
+%.o: %.c
+ $(CC) -c $(CFLAGS) -o $@ $<
+
+clean:
+ rm -f $(LKOBJECTS) *~ sdldz80
\ No newline at end of file
--- /dev/null
+
+This is a lightly hacked sdldz80 that knows about banked Fuzix binary
+formats. It's not currently a particularly clean approach but can be tidied
+up a bit once it is working.
+
+
+
+
+------------------------------------------------
+sdcc/link
+---------
+
+In gbdk the linker and assembler were split into seperate packages.
+
+For now I'm keeping that split, and leaving the mcs51 version as is.
+
+-- Michael
--- /dev/null
+/* aslink.h */
+
+/*
+ * Copyright (C) 1989-2012 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With enhancements from
+ * John L. Hartman (JLH)
+ * jhartman@compuserve.com
+ */
+
+/*
+ * System Include Files
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include "sdld.h"
+
+/*
+ * Local Definitions
+ */
+
+#define VERSION "V03.00 + NoICE + sdld"
+#define COPYRIGHT "2012"
+
+/*
+ * To include NoICE Debugging set non-zero
+ */
+#define NOICE 1
+
+/*
+ * To include SDCC Debugging set non-zero
+ */
+#define SDCDB 1
+
+/*
+ * The assembler requires certain variables to have
+ * at least 32 bits to allow correct address processing.
+ *
+ * The type INT32 is defined so that compiler dependent
+ * variable sizes may be specified in one place.
+ *
+ * LONGINT is defined when INT32 is 'long' to
+ * select the 'l' forms for format strings.
+ */
+
+/* Turbo C++ 3.0 for DOS */
+/* 'int' is 16-bits, 'long' is 32-bits */
+
+#ifdef __TURBOC__
+#define INT32 long
+#define LONGINT
+#endif
+
+/* Symantec C++ V6.x/V7.x for DOS (not DOSX) */
+/* 'int' is 16-bits, 'long' is 32-bits */
+
+#ifdef __SC__
+#define INT32 long
+#define LONGINT
+#endif
+
+/* The DEFAULT is 'int' is 32 bits */
+#ifndef INT32
+#define INT32 int
+#endif
+
+
+/*)Module aslink.h
+ *
+ * The module aslink.h contains the definitions for constants,
+ * structures, global variables, and LKxxxx functions
+ * contained in the LKxxxx.c files.
+ */
+
+/*)BUILD
+ $(PROGRAM) = ASLINK
+ $(INCLUDE) = ASLINK.H
+ $(FILES) = {
+ LKMAIN.C
+ LKLEX.C
+ LKAREA.C
+ LKBANK.C
+ LKHEAD.C
+ LKSYM.C
+ LKEVAL.C
+ LKDATA.C
+ LKLIST.C
+ LKNOICE.C
+ LKSDCDB.C
+ LKRLOC.C
+ LKRLOC3.C
+ LKLIBR.C
+ LKOUT.C
+ LKS19.C
+ }
+ $(STACK) = 2000
+*/
+
+#if defined DECUS
+/* DECUS C void definition */
+/* File/extension seperator */
+
+#define VOID char
+#define FSEPX '.'
+
+#elif defined PDOS
+/* PDOS C void definition */
+/* File/extension seperator */
+
+#define VOID char
+#define FSEPX ':'
+
+#elif defined UNIX
+/* UNIX void definition */
+/* File/extension seperator */
+
+#define VOID void
+#define FSEPX '.'
+#define LKDIRSEP '/'
+#define LKDIRSEPSTR "/"
+#define OTHERSYSTEM
+
+#else
+/* DOS/WINDOWS void definition */
+/* File/extension seperator */
+
+#define VOID void
+#define FSEPX '.'
+#define LKDIRSEP '\\'
+#define LKDIRSEPSTR "\\"
+#define OTHERSYSTEM
+
+#endif
+
+/*
+ * PATH_MAX
+ */
+#include <limits.h>
+#ifndef PATH_MAX /* POSIX, but not required */
+ #if defined(__BORLANDC__) || defined(_MSC_VER)
+ #include <stdlib.h>
+ #define PATH_MAX _MAX_PATH
+ #elif defined(__x86_64__)
+ #define PATH_MAX 4096
+ #else
+ #define PATH_MAX 255 /* define a reasonable value */
+ #endif
+#endif
+
+#define LKOBJEXT "rel"
+
+/*
+ * Global symbol types.
+ */
+#define S_REF 1 /* referenced */
+#define S_DEF 2 /* defined */
+
+/*
+ * File types
+ */
+#define F_OUT 0 /* File.ixx / File.sxx */
+#define F_STD 1 /* stdin */
+#define F_LNK 2 /* File.lnk */
+#define F_REL 3 /* File.rel */
+
+/*
+ * Error definitions
+ */
+#define ER_NONE 0 /* No error */
+#define ER_WARNING 1 /* Warning */
+#define ER_ERROR 2 /* Assembly error */
+#define ER_FATAL 3 /* Fatal error */
+
+/*
+ * This file defines the format of the
+ * relocatable binary file.
+ */
+
+#define NCPS PATH_MAX /* characters per symbol */
+#define NINPUT PATH_MAX /* Input buffer size */
+#define NHASH (1 << 6) /* Buckets in hash table */
+#define HMASK (NHASH - 1) /* Hash mask */
+#define NLPP 60 /* Lines per page */
+#define NMAX 78 /* IXX/SXX/DBX Buffer Length */
+#define IXXMAXBYTES 32 /* NMAX > (2 * IXXMAXBYTES) */
+#define SXXMAXBYTES 32 /* NMAX > (2 * SXXMAXBYTES) */
+#define DBXMAXBYTES 64 /* NMAX > ( DBXMAXBYTES ) */
+#define FILSPC PATH_MAX /* File spec length */
+
+#define NDATA 16 /* actual data */
+/*
+ * NTXT must be defined to have the same value in
+ * the ASxxxx assemblers and ASLink.
+ *
+ * The R Line coding allows only 4-bits for coding
+ * the T Line index. The MAXIMUM value for NTXT
+ * is 16. It should not be changed.
+ */
+#define NTXT 16 /* T values */
+
+/*
+ * Opcode Cycle definitions (Must Be The Same In ASxxxx / ASLink)
+ */
+#define CYCNT_BGN '[' /* Cycle count begin delimiter */
+#define CYCNT_END ']' /* Cycle count end delimiter */
+
+/*
+ * Internal ASxxxx Version Variable
+ */
+extern int ASxxxx_VERSION;
+
+
+/*
+ * ASLINK - Version 3 Definitions
+ */
+
+/*
+ * The "A3_" area constants define values used in
+ * generating the assembler area output data.
+ *
+ * Area flags
+ *
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | | | | PAG | ABS | OVR | | |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define A3_CON 000 /* concatenate */
+#define A3_OVR 004 /* overlay */
+#define A3_REL 000 /* relocatable */
+#define A3_ABS 010 /* absolute */
+#define A3_NOPAG 000 /* non-paged */
+#define A3_PAG 020 /* paged */
+
+/* sdld specific */
+/* Additional flags for 8051 address spaces */
+#define A_DATA 0000 /* data space (default)*/
+#define A_CODE 0040 /* code space */
+#define A_XDATA 0100 /* external data space */
+#define A_BIT 0200 /* bit addressable space */
+
+/* Additional flags for hc08 */
+#define A_NOLOAD 0400 /* nonloadable */
+#define A_LOAD 0000 /* loadable (default) */
+/* end sdld specific */
+
+/*
+ * The "R3_" relocation constants define values used in
+ * generating the assembler relocation output data for
+ * areas, symbols, and code.
+ *
+ *
+ * Relocation types.
+ *
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | MSB | PAGn| PAG0| USGN| BYT2| PCR | SYM | BYT |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define R3_WORD 0x00 /* 16 bit */
+#define R3_BYTE 0x01 /* 8 bit */
+
+#define R3_AREA 0x00 /* Base type */
+#define R3_SYM 0x02
+
+#define R3_NORM 0x00 /* PC adjust */
+#define R3_PCR 0x04
+
+#define R3_BYT1 0x00 /* Byte count for R_BYTE = 1 */
+#define R3_BYTX 0x08 /* Byte count for R_BYTE = X */
+
+#define R3_SGND 0x00 /* Signed value */
+#define R3_USGN 0x10 /* Unsigned value */
+
+#define R3_NOPAG 0x00 /* Page Mode */
+#define R3_PAG0 0x20 /* Page '0' */
+#define R3_PAG 0x40 /* Page 'nnn' */
+
+#define R3_LSB 0x00 /* output low byte */
+#define R3_MSB 0x80 /* output high byte */
+
+/*
+ * Additional "R3_" functionality is required to support
+ * some microprocesssor architectures. The 'illegal'
+ * "R3_" mode of R3_WORD | R3_BYTX is used as a designator
+ * of the extended R3_ modes. The extended modes replace
+ * the PAGING modes and are being added in an adhoc manner
+ * as follows:
+ *
+ * Extended Mode relocation flags
+ *
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | MSB | x | x | USGN| 1 | PCR | SYM | 0 |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define R3_ECHEK 0011 /* Extended Mode Check Bits */
+#define R3_EXTND 0010 /* Extended Mode Code */
+#define R3_EMASK 0151 /* Extended Mode Mask */
+
+/* #define R3_AREA 0000 */ /* Base type */
+/* #define R3_SYM 0002 */
+
+/* #define R3_NORM 0000 */ /* PC adjust */
+/* #define R3_PCR 0004 */
+
+/* #define R3_SGND 0000 */ /* Signed value */
+/* #define R3_USGN 0020 */ /* Unsigned value */
+
+/* #define R3_LSB 0000 */ /* output low byte */
+/* #define R3_MSB 0200 */ /* output high byte */
+
+#define R3_J11 (R3_WORD|R3_BYTX) /* JLH: 11 bit JMP and CALL (8051) */
+#define R3_J19 (R3_WORD|R3_BYTX|R3_MSB) /* BM: 19 bit JMP and CALL (DS80C390) */
+#define R_C24 (R3_WORD|R3_BYT1|R3_MSB) /* 24 bit address (DS80C390) */
+#define R_J19_MASK (R3_BYTE|R3_BYTX|R3_MSB)
+
+#define IS_R_J19(x) (((x) & R_J19_MASK) == R3_J19)
+#define IS_R_J11(x) (((x) & R_J19_MASK) == R3_J11)
+#define IS_C24(x) (((x) & R_J19_MASK) == R_C24)
+
+/* sdld specific */
+#define R_BYT3 0x100 /* if R3_BYTE is set, this is a
+ * 3 byte address, of which
+ * the linker must select one byte.
+ */
+#define R_HIB 0x200 /* If R3_BYTE & R_BYT3 are set, linker
+ * will select byte 3 of the relocated
+ * 24 bit address.
+ */
+
+#define R_BIT 0x400 /* Linker will convert from byte-addressable
+ * space to bit-addressable space.
+ */
+
+#define R_ESCAPE_MASK 0xf0 /* Used to escape relocation modes
+ * greater than 0xff in the .rel
+ * file.
+ */
+/* end sdld specific */
+
+
+/*
+ * ASLINK - Version 4 Definitions
+ */
+
+/*
+ * The "A4_" area constants define values used in
+ * generating the assembler area output data.
+ *
+ * Area flags
+ *
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | BNK | SEG | | PAG | ABS | OVR | WL1 | WL0 |
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define A4_BYTE 0x0000 /* 8 bit */
+#define A4_WORD 0x0001 /* 16 bit */
+
+#define A4_1BYTE 0x0000 /* 1 Byte Word Length */
+#define A4_2BYTE 0x0001 /* 2 Byte Word Length */
+#define A4_3BYTE 0x0002 /* 3 Byte Word Length */
+#define A4_4BYTE 0x0003 /* 4 Byte Word Length */
+#define A4_WLMSK 0x0003 /* Word Length Mask */
+
+#define A4_CON 0x0400 /* Concatenating */
+#define A4_OVR 0x0404 /* Overlaying */
+#define A4_REL 0x0800 /* Relocatable */
+#define A4_ABS 0x0808 /* absolute */
+#define A4_NOPAG 0x1000 /* Non-Paged */
+#define A4_PAG 0x1010 /* Paged */
+
+#define A4_CSEG 0x4000 /* CSEG */
+#define A4_DSEG 0x4040 /* DSEG */
+#define A4_NOBNK 0x8000 /* Non-Banked */
+#define A4_BNK 0x8080 /* Banked */
+
+#define A4_OUT 0x0100 /* Output Code Flag */
+
+/*
+ * The "R4_" relocation constants define values used in
+ * generating the assembler relocation output data for
+ * areas, symbols, and code.
+ *
+ * Note: The PAGE modes, PCR modes, Signed, Unsigned,
+ * and MSB codes are mutually exclusive !!!
+ *
+ *
+ * Relocation flags
+ *
+ * 7 6 5 4 3 2 1 0
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ * | SYM | PCR | PAGn| PAG0| USGN| SGND| BYT1| BYT0|
+ * +-----+-----+-----+-----+-----+-----+-----+-----+
+ */
+
+#define R4_BYTE 0x0000 /* 8 bit */
+#define R4_WORD 0x0001 /* 16 bit */
+
+#define R4_1BYTE 0x0000 /* 1 Byte */
+#define R4_2BYTE 0x0001 /* 2 Byte */
+#define R4_3BYTE 0x0002 /* 3 Byte */
+#define R4_4BYTE 0x0003 /* 4 Byte */
+#define R4_BYTES 0x0003 /* Data Size */
+
+#define R4_SGND 0x0004 /* Signed */
+#define R4_USGN 0x0008 /* Unsigned */
+#define R4_OVRF 0x0008 /* Overflow */
+
+#define R4_MBRS 0x0004 /* Merge Bit Range Signed */
+ /* An alias for Signed */
+#define R4_MBRU 0x0008 /* Merge Bit Range Unsigned */
+ /* An alias for Unsigned */
+#define R4_MBRO 0x0008 /* Merge Bit Range Overflow */
+ /* An alias for Unsigned */
+
+#define R4_MSB 0x000C /* MSB */
+ /* Mutually exclusive with Signed / Unsigned */
+
+#define R4_AREA 0x0000 /* Base type */
+#define R4_SYM 0x0080
+
+/*
+ * Paging Modes:
+ */
+
+#define R4_NOPAG 0x0000 /* Page Mode */
+#define R4_PBITS 0x003C /* Paging Bits */
+#define R4_PAGE 0x0030 /* Paged Addressing */
+#define R4_PAG0 0x0010 /* Page '0' .setdp */
+#define R4_PAGN 0x0020 /* Page 'nnn' .setdp */
+#define R4_PAGX 0x0030 /* Page 'x', Extended Relocation Mode */
+#define R4_PAGX0 0x0030 /* Page 'x', pc + 0 */
+#define R4_PAGX1 0x0034 /* Page 'x', pc + 1 */
+#define R4_PAGX2 0x0038 /* Page 'x', pc + 2 */
+#define R4_PAGX3 0x003C /* Page 'x', pc + 3 */
+
+/*
+ * PCR Modes:
+ */
+
+#define R4_PCR 0x0040 /* PC adjust (default) */
+#define R4_PCRN 0x0050 /* PC adjust (default) no range check */
+
+#define R4_PCR0 0x0054 /* PC adjust (offset = 0) */
+#define R4_PCR1 0x0060 /* PC adjust (offset = 1) */
+#define R4_PCR2 0x0064 /* PC adjust (offset = 2) */
+#define R4_PCR3 0x0068 /* PC adjust (offset = 3) */
+#define R4_PCR4 0x006C /* PC adjust (offset = 4) */
+
+#define R4_PCR0N 0x0058 /* PC adjust (offset = 0) no range check */
+#define R4_PCR1N 0x0070 /* PC adjust (offset = 1) no range check */
+#define R4_PCR2N 0x0074 /* PC adjust (offset = 2) no range check */
+#define R4_PCR3N 0x0078 /* PC adjust (offset = 3) no range check */
+#define R4_PCR4N 0x007C /* PC adjust (offset = 4) no range check */
+
+/*
+ * Basic Relocation Modes
+ */
+
+#define R4_NORM 0x0000 /* No Bit Positioning */
+
+
+/*
+ * The defined type 'a_uint' is used for all address and
+ * unsigned variable value calculations. Its size is
+ * required to be at least 32-bits to allow upto
+ * 32-bit addressing or 32-bit value manipulation.
+ */
+typedef unsigned INT32 a_uint;
+
+/*
+ * The defined type 'v_sint' is used for address and
+ * variable value calculations requiring a sign.
+ * Its size is required to be at least 32-bits to allow
+ * upto 32-bit addressing or 32-bit value manipulation.
+ */
+typedef signed INT32 v_sint;
+
+/*
+ * The structures of head, mode, bank, area, areax, and sym
+ * are created as the REL files are read during the first
+ * pass of the linker. The struct head is created upon
+ * encountering a H directive in the REL file. The
+ * structure contains a link to a link file structure
+ * (struct lfile) which describes the file containing the H
+ * directive, a pointer to an array of merge mode
+ * definition pointers, the number of data/code areas
+ * contained in this header segment, the number of
+ * symbols referenced/defined in this header segment, a pointer
+ * to an array of pointers to areax structures (struct areax)
+ * created as each A directive is read, a pointer to an
+ * array of pointers to symbol structures (struct sym) for
+ * all referenced/defined symbols and a pointer to an array
+ * of pointers to bank structures (struct bank) referenced
+ * by this module. As H directives are read
+ * from the REL files a linked list of head structures is
+ * created by placing a link to the new head structure
+ * in the previous head structure.
+ */
+struct head
+{
+ struct head *h_hp; /* Header link */
+ struct lfile *h_lfile; /* Associated file */
+ int h_narea; /* # of areas */
+ struct areax **a_list; /* Area list */
+ int h_nsym; /* # of symbols */
+ struct sym **s_list; /* Symbol list */
+ int h_nbank; /* # of banks */
+ struct bank **b_list; /* Bank list */
+ int h_nmode; /* # of modes */
+ struct mode **m_list; /* Mode list */
+ char * m_id; /* Module name */
+};
+
+/*
+ * The MODE structure contains the specification of one of the
+ * assemblers' relocation modes. Each assembler must specify
+ * at least one relocation mode. The relocation specification
+ * allows arbitrarily defined active bits and bit positions.
+ * The 32 element arrays are indexed from 0 to 31.
+ * Index 0 corresponds to bit 0, ..., and 31 corresponds to bit 31
+ * of a normal integer value.
+ *
+ * The value an array element defines if the normal integer bit is
+ * active (bit <7> is set, 0x80) and what destination bit
+ * (bits <4:0>, 0 - 31) should be loaded with this normal
+ * integer bit.
+ *
+ * The specification for a 32-bit integer:
+ *
+ * char mode_[32] = {
+ * 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ * 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
+ * 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ * 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F
+ * };
+ *
+ *
+ * The specification for the 11-bit 8051 addressing mode:
+ *
+ * char mode_[32] = {
+ * 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ * 0x8D, 0x8E, 0x8F, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
+ * 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ * 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F
+ * };
+ *
+ *
+ * m_def is the bit relocation definition array.
+ * m_flag indicates that bit position swapping is required.
+ * m_dbits contains the active bit positions for the output.
+ * m_sbits contains the active bit positions for the input.
+ */
+struct mode
+{
+ char m_def[32]; /* Bit Relocation Definition */
+ int m_flag; /* Bit Swapping Flag */
+ a_uint m_dbits; /* Destination Bit Mask */
+ a_uint m_sbits; /* Source Bit Mask */
+};
+
+/*
+ * The bank structure contains the parameter values for a
+ * specific program or data bank. The bank structure
+ * is a linked list of banks. The initial default bank
+ * is unnamed and is defined in lkdata.c, the next bank structure
+ * will be linked to this structure through the structure
+ * element 'struct bank *b_bp'. The structure contains the
+ * bank name, the bank base address (default = 0), the bank size
+ * (default = 0, whole addressing space), the bank mapping,
+ * and the file name suffix. (default is none) These optional
+ * parameters are from the .bank assembler directive.
+ * The bank structure also contains the bank data output
+ * file specification, file handle pointer and the
+ * bank first output flag.
+ */
+struct bank
+{
+ struct bank *b_bp; /* Bank link */
+ char * b_id; /* Bank Name */
+ char * b_fsfx; /* Bank File Suffix / File Specification */
+ a_uint b_base; /* Bank base address */
+ a_uint b_size; /* Bank size */
+ a_uint b_map; /* Bank mapping */
+ int b_flag; /* Bank flags */
+ char * b_fspec; /* Bank File Specification */
+ FILE * b_ofp; /* Bank File Handle */
+ char * b_ofspec; /* Bank Output File Specification */
+ int b_oflag; /* Bank has output flag */
+ int b_rtaflg; /* Bank First Output flag */
+};
+
+#define B_BASE 0001 /* 'base' address specified */
+#define B_SIZE 0002 /* 'size' of bank specified */
+#define B_FSFX 0004 /* File suffix specified */
+#define B_MAP 0010 /* Mapped Bank Flag */
+
+/*
+ * A structure area is created for each 'unique' data/code
+ * area definition found as the REL files are read. The
+ * struct area contains the name of the area, a flag byte
+ * which contains the area attributes (REL/CON/OVR/ABS),
+ * the area base address set flag byte (-b option), and the
+ * area base address and total size which will be filled
+ * in at the end of the first pass through the REL files.
+ * The area structure also contains a link to the bank
+ * this area is a part of and a data output file handle
+ * pointer which is loaded from from the bank structure.
+ * As A directives are read from the REL files a linked
+ * list of unique area structures is created by placing a
+ * link to the new area structure in the previous area structure.
+ */
+struct area
+{
+ struct area *a_ap; /* Area link */
+ struct areax *a_axp; /* Area extension link */
+ struct bank *a_bp; /* Bank link */
+ FILE * a_ofp; /* Area File Handle */
+ a_uint a_addr; /* Beginning address of area */
+ a_uint a_size; /* Total size of the area */
+ int a_bset; /* Area base address set */
+/* sdld specific */
+ a_uint a_unaloc; /* Total number of unallocated bytes, for error reporting */
+/* end sdld specific */
+ int a_flag; /* Flags */
+ char * a_id; /* Name */
+/* sdld specific */
+ char *a_image; /* Something for hc08/lkelf */
+ char *a_used; /* Something for hc08/lkelf */
+ a_uint a_imagesize; /* Something for hc08/lkelf */
+/* end sdld specific */
+};
+
+/*
+ * An areax structure is created for every A directive found
+ * while reading the REL files. The struct areax contains a
+ * link to the 'unique' area structure referenced by the A
+ * directive and to the head structure this area segment is
+ * a part of. The size of this area segment as read from the
+ * A directive is placed in the areax structure. The beginning
+ * address of this segment will be filled in at the end of the
+ * first pass through the REL files. As A directives are read
+ * from the REL files a linked list of areax structures is
+ * created for each unique area. The final areax linked
+ * list has at its head the 'unique' area structure linked
+ * to the linked areax structures (one areax structure for
+ * each A directive for this area).
+ */
+struct areax
+{
+ struct areax *a_axp; /* Area extension link */
+ struct area *a_bap; /* Base area link */
+ struct head *a_bhp; /* Base header link */
+ a_uint a_addr; /* Beginning address of section */
+ a_uint a_size; /* Size of the area in section */
+};
+
+/*
+ * A sym structure is created for every unique symbol
+ * referenced/defined while reading the REL files. The
+ * struct sym contains the symbol's name, a flag value
+ * (not used in this linker), a symbol type denoting
+ * referenced/defined, and an address which is loaded
+ * with the relative address within the area in which
+ * the symbol was defined. The sym structure also
+ * contains a link to the area where the symbol was defined.
+ * The sym structures are linked into linked lists using
+ * the symbol link element.
+ */
+struct sym
+{
+ struct sym *s_sp; /* Symbol link */
+ struct areax *s_axp; /* Symbol area link */
+ char s_type; /* Symbol subtype */
+ char s_flag; /* Flag byte */
+ a_uint s_addr; /* Address */
+ char *s_id; /* Name (JLH) */
+ char *m_id; /* Module symbol define in */
+};
+
+/*
+ * The structure lfile contains a pointer to a
+ * file specification string, an index which points
+ * to the file name (past the 'path'), the file type,
+ * an object output flag, and a link to the next
+ * lfile structure.
+ */
+struct lfile
+{
+ struct lfile *f_flp; /* lfile link */
+ int f_type; /* File type */
+ char *f_idp; /* Pointer to file spec */
+ int f_idx; /* Index to file name */
+ int f_obj; /* Object output flag */
+};
+
+/*
+ * The struct base contains a pointer to a
+ * base definition string and a link to the next
+ * base structure.
+ */
+struct base
+{
+ struct base *b_base; /* Base link */
+ char *b_strp; /* String pointer */
+};
+
+/*
+ * The struct globl contains a pointer to a
+ * global definition string and a link to the next
+ * global structure.
+ */
+struct globl
+{
+ struct globl *g_globl; /* Global link */
+ char *g_strp; /* String pointer */
+};
+
+/*
+ * A structure sdp is created for each 'unique' paged
+ * area definition found as the REL files are read.
+ * As P directives are read from the REL files a linked
+ * list of unique sdp structures is created by placing a
+ * link to the new sdp structure in the previous area structure.
+ */
+struct sdp
+{
+ struct area *s_area; /* Paged Area link */
+ struct areax *s_areax; /* Paged Area Extension Link */
+ a_uint s_addr; /* Page address offset */
+};
+
+/*
+ * The structure rerr is loaded with the information
+ * required to report an error during the linking
+ * process. The structure contains an index value
+ * which selects the areax structure from the header
+ * areax structure list, a mode value which selects
+ * symbol or area relocation, the base address in the
+ * area section, an area/symbol list index value, and
+ * an area/symbol offset value.
+ */
+struct rerr
+{
+ int aindex; /* Linking area */
+ int mode; /* Relocation mode */
+ a_uint rtbase; /* Base address in section */
+ int rindex; /* Area/Symbol reloaction index */
+ a_uint rval; /* Area/Symbol offset value */
+};
+
+/*
+ * The structure lbpath is created for each library
+ * path specification input by the -k option. The
+ * lbpath structures are linked into a list using
+ * the next link element.
+ */
+struct lbpath {
+ struct lbpath *next;
+ char *path;
+};
+
+/*
+ * The structure lbname is created for all combinations of the
+ * library path specifications (input by the -k option) and the
+ * library file specifications (input by the -l option) that
+ * lead to an existing file. The element path points to
+ * the path string, element libfil points to the library
+ * file string, and the element libspc is the concatenation
+ * of the valid path and libfil strings.
+ *
+ * The lbpath structures are linked into a list
+ * using the next link element.
+ *
+ * Each library file contains a list of object files
+ * that are contained in the particular library. e.g.:
+ *
+ * \iolib\termio
+ * \inilib\termio
+ *
+ * Only one specification per line is allowed.
+ */
+struct lbname {
+ struct lbname *next;
+ char *path;
+ char *libfil;
+ char *libspc;
+ int f_obj;
+};
+
+/*
+ * The function fndsym() searches through all combinations of the
+ * library path specifications (input by the -k option) and the
+ * library file specifications (input by the -l option) that
+ * lead to an existing file for a symbol definition.
+ *
+ * The structure lbfile is created for the first library
+ * object file which contains the definition for the
+ * specified undefined symbol.
+ *
+ * The element libspc points to the library file path specification
+ * and element relfil points to the object file specification string.
+ * The element filspc is the complete path/file specification for
+ * the library file to be imported into the linker. The f_obj
+ * flag specifies if the object code from this file is
+ * to be output by the linker. The file specification
+ * may be formed in one of two ways:
+ *
+ * (1) If the library file contained an absolute
+ * path/file specification then this becomes filspc.
+ * (i.e. C:\...)
+ *
+ * (2) If the library file contains a relative path/file
+ * specification then the concatenation of the path
+ * and this file specification becomes filspc.
+ * (i.e. \...)
+ *
+ * The lbpath structures are linked into a list
+ * using the next link element.
+ */
+struct lbfile {
+ struct lbfile *next;
+ char *libspc;
+ char *relfil;
+ char *filspc;
+ int f_obj;
+/* sdld specific */
+ long offset;
+ unsigned int type;
+/* end sdld specific */
+};
+
+/*
+ * External Definitions for all Global Variables
+ */
+
+extern char *_abs_; /* = { ". .ABS." };
+ */
+extern int lkerr; /* ASLink error flag
+ */
+extern char *ip; /* pointer into the REL file
+ * text line in ib[]
+ */
+extern char ib[NINPUT]; /* REL file text line
+ */
+extern char *rp; /* pointer into the LST file
+ * text line in rb[]
+ */
+extern char rb[NINPUT]; /* LST file text line being
+ * address relocated
+ */
+extern char ctype[]; /* array of character types, one per
+ * ASCII character
+ */
+
+/*
+ * Character Type Definitions
+ */
+#define SPACE '\000'
+#define ETC '\000'
+#define LETTER '\001'
+#define DIGIT '\002'
+#define BINOP '\004'
+#define RAD2 '\010'
+#define RAD8 '\020'
+#define RAD10 '\040'
+#define RAD16 '\100'
+#define ILL '\200'
+
+#define DGT2 DIGIT|RAD16|RAD10|RAD8|RAD2
+#define DGT8 DIGIT|RAD16|RAD10|RAD8
+#define DGT10 DIGIT|RAD16|RAD10
+#define LTR16 LETTER|RAD16
+
+extern char afspec[]; /* The filespec created by afile()
+ */
+extern char ccase[]; /* an array of characters which
+ * perform the case translation function
+ */
+
+extern struct lfile *filep; /* The pointers (lfile *) filep,
+ * (lfile *) cfp, and (FILE *) sfp
+ * are used in conjunction with
+ * the routine nxtline() to read
+ * aslink commands from
+ * (1) the standard input or
+ * (2) or a command file
+ * and to read the REL files
+ * sequentially as defined by the
+ * aslink input commands.
+ *
+ * The pointer *filep points to the
+ * beginning of a linked list of
+ * lfile structures.
+ */
+extern struct lfile *cfp; /* The pointer *cfp points to the
+ * current lfile structure
+ */
+extern struct lfile *startp;/* aslink startup file structure
+ */
+extern struct lfile *linkp; /* pointer to first lfile structure
+ * containing an input REL file
+ * specification
+ */
+extern struct lfile *lfp; /* pointer to current lfile structure
+ * being processed by parse()
+ */
+extern struct head *headp; /* The pointer to the first
+ * head structure of a linked list
+ */
+extern struct head *hp; /* Pointer to the current
+ * head structure
+ */
+extern struct bank *bankp; /* The pointer to the first
+ * bank structure of a linked list
+ */
+extern struct bank *bp; /* Pointer to the current
+ * bank structure
+ */
+extern struct area *areap; /* The pointer to the first
+ * area structure of a linked list
+ */
+extern struct area *ap; /* Pointer to the current
+ * area structure
+ */
+extern struct areax *axp; /* Pointer to the current
+ * areax structure
+ */
+extern struct sym *symhash[NHASH]; /* array of pointers to NHASH
+ * linked symbol lists
+ */
+extern struct base *basep; /* The pointer to the first
+ * base structure
+ */
+extern struct base *bsp; /* Pointer to the current
+ * base structure
+ */
+extern struct globl *globlp;/* The pointer to the first
+ * globl structure
+ */
+extern struct globl *gsp; /* Pointer to the current
+ * globl structure
+ */
+extern struct sdp sdp; /* Base Paged structure
+ */
+extern struct rerr rerr; /* Structure containing the
+ * linker error information
+ */
+extern FILE *nbofp; /* Non Banked Linker Output
+ * File Handle
+ */
+extern FILE *ofp; /* Linker Output file handle
+ */
+
+#if NOICE
+extern FILE *jfp; /* NoICE output file handle
+ */
+#endif
+
+extern FILE *mfp; /* Map output file handle
+ */
+extern FILE *rfp; /* File handle for output
+ * address relocated ASxxxx
+ * listing file
+ */
+extern FILE *sfp; /* The file handle sfp points to the
+ * currently open file
+ */
+extern FILE *tfp; /* File handle for input
+ * ASxxxx listing file
+ */
+
+#if SDCDB
+extern FILE *yfp; /* SDCDB output file handle
+ */
+#endif
+
+extern int oflag; /* Output file type flag
+ */
+extern int objflg; /* Linked file/library object output flag
+ */
+
+#if NOICE
+extern int jflag; /* -j, enable NoICE Debug output
+ */
+#endif
+
+extern int mflag; /* Map output flag
+ */
+extern int xflag; /* Map file radix type flag
+ */
+
+#if SDCDB
+extern int yflag; /* -y, enable SDCC Debug output
+ */
+#endif
+
+extern int pflag; /* print linker command file flag
+ */
+extern int uflag; /* Listing relocation flag
+ */
+extern int wflag; /* Enable wide format listing
+ */
+extern int zflag; /* Disable symbol case sensitivity
+ */
+extern int radix; /* current number conversion radix:
+ * 2 (binary), 8 (octal), 10 (decimal),
+ * 16 (hexadecimal)
+ */
+extern int line; /* current line number
+ */
+extern int page; /* current page number
+ */
+extern int lop; /* current line number on page
+ */
+extern int pass; /* linker pass number
+ */
+extern a_uint pc; /* current relocation address
+ */
+extern int pcb; /* current bytes per pc word
+ */
+extern int rtcnt; /* count of elements in the
+ * rtval[] and rtflg[] arrays
+ */
+extern a_uint rtval[]; /* data associated with relocation
+ */
+extern int rtflg[]; /* indicates if rtval[] value is
+ * to be sent to the output file.
+ */
+extern int rterr[]; /* indicates if rtval[] value should
+ * be flagged as a relocation error.
+ */
+extern char rtbuf[]; /* S19/IHX output buffer
+ */
+extern struct bank *rtabnk; /* rtbuf[] processing
+ */
+extern int rtaflg; /* rtbuf[] processing
+ */
+extern a_uint rtadr0; /*
+ */
+extern a_uint rtadr1; /*
+ */
+extern a_uint rtadr2; /*
+ */
+extern int obj_flag; /* Linked file/library object output flag
+ */
+extern int a_bytes; /* REL file T Line address length
+ */
+extern int hilo; /* REL file byte ordering
+ */
+extern a_uint a_mask; /* Address Mask
+ */
+extern a_uint s_mask; /* Sign Mask
+ */
+extern a_uint v_mask; /* Value Mask
+ */
+extern int gline; /* LST file relocation active
+ * for current line
+ */
+extern int gcntr; /* LST file relocation active
+ * counter
+ */
+extern struct lbpath *lbphead; /* pointer to the first
+ * library path structure
+ */
+extern struct lbname *lbnhead; /* pointer to the first
+ * library name structure
+ */
+extern struct lbfile *lbfhead; /* pointer to the first
+ * library file structure
+ */
+/* sdld specific */
+extern int sflag; /* JCF: Memory usage output flag
+ */
+extern int packflag; /* Pack data memory flag
+ */
+extern int stacksize; /* Stack size
+ */
+extern int rflag; /* Extended linear address record flag.
+ */
+extern a_uint iram_size; /* internal ram size
+ */
+extern long xram_size; /* external ram size
+ */
+extern long code_size; /* code size
+ */
+extern char *sdld_output; /* output file name, --output argument
+ */
+extern char *optsdcc;
+extern char *optsdcc_module;
+/* sdld 8015 specific */
+extern char idatamap[256]; /* space is unused
+ */
+/* end sdld 8051 specific */
+/* end sdld specific */
+
+
+
+/* C Library function definitions */
+/* for reference only
+extern VOID exit();
+extern int fclose();
+extern char * fgets();
+extern FILE * fopen();
+extern int fprintf();
+extern VOID free();
+extern VOID * malloc();
+extern char putc();
+extern char * sprintf();
+extern char * strcpy();
+extern int strlen();
+extern char * strncpy();
+extern char * strrchr();
+*/
+
+/* Program function definitions */
+
+#ifdef OTHERSYSTEM
+
+/* lkmain.c */
+extern FILE * afile(char *fn, char *ft, int wf);
+extern VOID bassav(void);
+extern int fndidx(char *str);
+extern int fndext(char *str);
+extern VOID gblsav(void);
+extern int intsiz(void);
+extern VOID iramsav(void);
+extern VOID xramsav(void);
+extern VOID codesav(void);
+extern VOID iramcheck(void);
+extern VOID link_main(void);
+extern VOID lkexit(int i);
+extern int main(int argc, char *argv[]);
+extern VOID map(void);
+extern VOID sym(void);
+extern int parse(void);
+extern VOID doparse(void);
+extern VOID setarea(void);
+extern VOID setgbl(void);
+extern VOID usage(int n);
+extern VOID copyfile (FILE *dest, FILE *src);
+
+/* lklex.c */
+extern VOID chopcrlf(char *str);
+extern char endline(void);
+extern int get(void);
+extern VOID getfid(char *str, int c);
+extern VOID getid(char *id, int c);
+extern VOID getSid(char *id);
+extern int getmap(int d);
+extern int getnb(void);
+extern int more(void);
+extern int nxtline(void);
+extern VOID skip(int c);
+extern VOID unget(int c);
+
+/* lkarea.c */
+extern VOID lkparea(char *id);
+extern VOID lnkarea(void);
+extern VOID lnkarea2(void);
+extern VOID newarea(void);
+
+/* lkbank.c */
+extern VOID chkbank(FILE *fp);
+extern VOID lkfclose(void);
+extern VOID lkfopen(void);
+extern VOID lkpbank(char * id);
+extern VOID newbank(void);
+extern VOID setbank(void);
+
+/* lkhead.c */
+extern VOID module(void);
+extern VOID newhead(void);
+extern VOID newmode(void);
+
+/* lksym.c */
+extern int hash(char *p, int cflag);
+extern struct sym * lkpsym(char *id, int f);
+extern char * new(unsigned int n);
+extern struct sym * newsym(void);
+extern char * strsto(char *str);
+extern VOID symdef(FILE *fp);
+extern int symeq(char *p1, char *p2, int cflag);
+extern VOID syminit(void);
+extern VOID symmod(FILE *fp, struct sym *tsp);
+extern a_uint symval(struct sym *tsp);
+
+/* lkeval.c */
+extern int digit(int c, int r);
+extern a_uint eval(void);
+extern a_uint expr(int n);
+extern int oprio(int c);
+extern a_uint term(void);
+
+/* lklist.c */
+extern int dgt(int rdx, char *str, int n);
+extern VOID newpag(FILE *fp);
+extern VOID slew(struct area *xp, struct bank *yp);
+extern VOID lstarea(struct area *xp, struct bank *yp);
+extern VOID lkulist(int i);
+extern VOID lkalist(a_uint cpc);
+extern VOID lkglist(a_uint cpc, int v, int err);
+
+/* lknoice.c */
+extern VOID NoICEfopen(void);
+extern VOID NoICEmagic(void);
+extern VOID DefineNoICE(char *name, a_uint value, struct bank *yp);
+extern VOID DefineGlobal(char *name, a_uint value, struct bank *yp);
+extern VOID DefineScoped(char *name, a_uint value, struct bank *yp);
+extern VOID DefineFile(char *name, a_uint value, struct bank *yp);
+extern VOID DefineFunction(char *name, a_uint value, struct bank *yp);
+extern VOID DefineStaticFunction(char *name, a_uint value, struct bank *yp);
+extern VOID DefineEndFunction(a_uint value, struct bank *yp);
+extern VOID DefineLine(char *lineString, a_uint value, struct bank *yp);
+extern VOID PagedAddress(a_uint value, struct bank *yp);
+
+/* lksdcdb.c */
+extern VOID SDCDBfopen(void);
+extern VOID SDCDBcopy(char * str);
+extern VOID DefineSDCDB(char *name, a_uint value);
+
+/* lkrloc.c */
+extern a_uint adb_1b(a_uint v, int i);
+extern a_uint adb_2b(a_uint v, int i);
+extern a_uint adb_3b(a_uint v, int i);
+extern a_uint adb_4b(a_uint v, int i);
+extern a_uint adb_xb(a_uint v, int i);
+extern a_uint evword(void);
+extern VOID prntval(FILE *fptr, a_uint v);
+extern VOID reloc(int c);
+
+/* lkrloc3.c */
+extern a_uint adb_bit(a_uint v, int i);
+extern a_uint adb_24_bit(a_uint v, int i);
+extern a_uint adb_24_hi(a_uint v, int i);
+extern a_uint adb_24_mid(a_uint v, int i);
+extern a_uint adb_24_lo(a_uint v, int i);
+extern a_uint adb_hi(a_uint v, int i);
+extern a_uint adb_lo(a_uint v, int i);
+extern char * errmsg3[];
+extern VOID errdmp3(FILE *fptr, char *str);
+extern VOID erpdmp3(FILE *fptr, char *str);
+extern VOID rele3(void);
+extern VOID reloc3(int c);
+extern VOID relt3(void);
+extern VOID relr3(void);
+extern VOID relp3(void);
+extern VOID relerr3(char *str);
+extern VOID relerp3(char *str);
+
+/* lklibr.c */
+extern int addfile(char *path, char *libfil);
+extern VOID addlib(void);
+extern VOID addpath(void);
+extern int fndsym(char *name);
+extern VOID library(void);
+extern VOID loadfile(char *filspc);
+extern VOID search(void);
+
+/* lkout.c */
+extern VOID lkout(int i, int b);
+extern VOID lkflush(void);
+extern VOID ixx(int i, int b);
+extern VOID iflush(void);
+extern VOID dbx(int i);
+extern VOID dflush(void);
+
+/* lks19.c */
+extern VOID s19(int i);
+extern VOID sflush(void);
+
+/* EEP: lkelf.c */
+extern VOID elf();
+
+/* JCF: lkmem.c */
+extern int summary(struct area * xp);
+extern int summary2(struct area * xp);
+
+/* JCF: lkaomf51.c */
+extern void SaveLinkedFilePath(char * filepath);
+extern void CreateAOMF51(void);
+
+/* lkgb.h */
+VOID gb(int in);
+VOID gg(int in);
+
+/* strcmpi.h */
+extern int as_strcmpi(const char *s1, const char *s2);
+extern int as_strncmpi(const char *s1, const char *s2, size_t n);
+
+#else
+
+#endif
--- /dev/null
+#ifndef __ASXXXX_CONFIG_H
+#define __ASXXXX_CONFIG_H
+
+#define TYPE_BYTE char
+#define TYPE_WORD short
+#define TYPE_DWORD int
+#define TYPE_UBYTE unsigned char
+#define TYPE_UWORD unsigned short
+#define TYPE_UDWORD unsigned int
+
+#endif /* __ASXXXX_CONFIG_H */
--- /dev/null
+/*
+ lk_readnl.c - read a line from file into a buffer
+ version 1.0.0, April 25th, 2008
+
+ Copyright (c) 2008 Borut Razem
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Borut Razem
+ borut.razem@siol.net
+*/
+
+#include "lk_readnl.h"
+
+/*******************************************************************************
+
+ lk_readnl
+
+lk_readnl() reads in at most one less than size characters from stream and stores
+them into the buffer pointed to by s. Reading stops after an EOF or a newline.
+The newline character is not stored into the buffer. A '\0' is stored after the
+last character in the buffer. All the characters between size and the newline or
+EOF are skipped.
+
+lk_readnl() return s on success, and NULL on error or when end of file occurs
+while no characters have been read.
+
+*******************************************************************************/
+
+char *
+lk_readnl (char *s, int size, FILE * stream)
+{
+ static char eof_f = 0;
+ int c = '\0';
+ char *s_o;
+ char prev_c;
+
+ if (eof_f)
+ {
+ eof_f = 0;
+ return NULL;
+ }
+
+ s_o = s;
+ --size; /* for null terminator */
+ while (size > 0)
+ {
+ prev_c = c;
+ if ((c = getc (stream)) == '\n' || c == EOF)
+ break;
+
+ if (prev_c == '\r')
+ {
+ *s++ = prev_c;
+ if (--size <= 0)
+ break;
+ }
+
+ if (c != '\r')
+ {
+ *s++ = c;
+ --size;
+ }
+ }
+ *s = '\0';
+
+ while (c != '\n' && c != EOF)
+ c = getc (stream);
+
+ if (c == EOF)
+ {
+ if (s == s_o)
+ return NULL;
+
+ eof_f = 1;
+ }
+
+ return s_o;
+}
--- /dev/null
+/*
+ lk_readnl.h - read a line from file into a buffer
+ version 1.0.0, Aprile 25th, 2008
+
+ Copyright (c) 2008 Borut Razem
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Borut Razem
+ borut.razem@siol.net
+*/
+
+
+#ifndef __LK_READNL_H
+#define __LK_READNL_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ char *lk_readnl (char *s, int size, FILE * stream);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LK_READNL_H */
--- /dev/null
+/* lkaomf51.c - Create an absolute object memory format 51 file
+
+ Copyright (C) 2002 Jesus Calvino-Fraga, jesusc at ieee dot org
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include "aslink.h"
+
+#define EQ(A,B) !strcmp((A),(B))
+#define MEMSIZE 0x1000000
+#ifndef DODUMP
+#define DODUMP 0
+#endif
+
+typedef struct
+{
+ char PathName[PATH_MAX];
+ char ModuleName[PATH_MAX];
+} _infn;
+
+int numin=0;
+_infn * infn=NULL;
+
+typedef struct
+{
+ char name[0x100];
+ int FileNameNumber;
+ int Procedure;//If the symbol belongs to a function
+ int Static; //If the symbol is only public on its file
+ int Address;
+ int UsageType;
+} _symbol;
+
+int numsym=0;
+_symbol * symbol=NULL;
+
+typedef struct
+{
+ char name[0x100];
+ int FileNameNumber;
+ int BeginAdd;
+ int EndAdd;
+ int RegBank;
+} _procedure;
+
+int numproc=0;
+_procedure * procedure=NULL;
+
+typedef struct
+{
+ int Number;
+ int Address;
+ int Procedure;
+ int FileNameNumber;
+} _linenum;
+
+int numlinenum=0;
+_linenum * linenum=NULL;
+#if 0
+typedef struct
+{
+ char * name;
+ int usage;
+}
+_UsageType;
+
+_UsageType UsageType[]=
+{
+ {"CSEG", 0},
+ {"GSINIT", 0},
+ {"GSINIT0", 0},
+ {"GSINIT1", 0},
+ {"GSINIT2", 0},
+ {"GSINIT3", 0},
+ {"GSINIT4", 0},
+ {"GSINIT5", 0},
+ {"GSFINAL", 0},
+ {"HOME", 0},
+ {"XINIT", 0},
+ {"XSEG", 1},
+ {"XISEG", 1},
+ {"REG_BANK_0", 2},
+ {"REG_BANK_1", 2},
+ {"REG_BANK_2", 2},
+ {"REG_BANK_3", 2},
+ {"DSEG", 2},
+ {"OSEG", 2},
+ {"SSEG", 2},
+ {"ISEG", 3},
+ {"BSEG", 4},
+ {"", 5} /*A typeless number?*/
+};
+#endif
+char * UsageTypeName[]={"CODE", "XDATA", "DATA", "IDATA", "BIT", "NUMBER"};
+int AddNumber;
+short * ihxBuff=NULL;
+FILE * aomf51out;
+int GlobalChkSum=0;
+int HexSize, HexBegin=0x1000000;
+
+
+int GetName(char * filepath, char * name)
+{
+ int j, k;
+ for(j=strlen(filepath); j>0; j--)
+ if( (filepath[j-1]=='/')||(filepath[j-1]=='\\') ) break;
+ for(k=0; (filepath[j]!=0)&&(filepath[j]!='.'); j++, k++)
+ name[k]=filepath[j];
+ name[k]=0;
+ return j;
+}
+
+void SaveLinkedFilePath(char * filepath)
+{
+ int j;
+
+ if((yflag) && (!rflag))
+ {
+ int ext;
+
+ infn = realloc(infn, sizeof(_infn)*(numin+1));
+
+ /*Get the module name=filename, no drive, no dir, no ext*/
+ ext = GetName(filepath, infn[numin].ModuleName);
+ //printf("%s, %s\n", infn[numin].PathName, infn[numin].ModuleName);
+
+ strcpy(infn[numin].PathName, filepath);
+
+ /*If there is an extension remove it*/
+ if (infn[numin].PathName[ext] == '.')
+ infn[numin].PathName[ext] = '\0';
+
+ /*Check if this filename is already in*/
+ for (j=0; j<numin; j++)
+ {
+ if (EQ(infn[numin].PathName, infn[j].PathName))
+ break;
+ }
+ if (j==numin)
+ numin++;
+ }
+}
+
+void FreeAll(void)
+{
+ if(infn!=NULL)
+ {
+ free(infn);
+ numin=0;
+ infn=NULL;
+ }
+
+ if(symbol!=NULL)
+ {
+ free(symbol);
+ numsym=0;
+ symbol=NULL;
+ }
+
+ if(procedure!=NULL)
+ {
+ free(procedure);
+ numproc=0;
+ procedure=NULL;
+ }
+
+ if(linenum!=NULL)
+ {
+ free(linenum);
+ numlinenum=0;
+ linenum=NULL;
+ }
+
+ if(ihxBuff!=NULL)
+ {
+ free(ihxBuff);
+ ihxBuff=NULL;
+ }
+}
+
+void OutputByte(unsigned char value)
+{
+ GlobalChkSum+=value;
+ fwrite( &value, 1, 1, aomf51out );
+}
+
+void OutputWord(int value)
+{
+ OutputByte((unsigned char)(value%0x100));
+ OutputByte((unsigned char)(value/0x100));
+}
+
+void OutputName(char * name)
+{
+ int k;
+ OutputByte((unsigned char)strlen(name));
+ for(k=0; name[k]!=0; k++)
+ OutputByte((unsigned char)toupper(name[k]));
+}
+
+void OutputChkSum(void)
+{
+ OutputByte((unsigned char)(0x100-(GlobalChkSum%0x100)));
+ GlobalChkSum=0;
+}
+
+void DumpForDebug (void)
+{
+ char DumpFileName[PATH_MAX];
+ FILE * DumpFile;
+ int j, k;
+
+ strcpy(DumpFileName, infn[0].PathName);
+ strcat(DumpFileName, ".d51");
+
+ DumpFile=fopen(DumpFileName, "wb");
+ if(DumpFile==NULL)
+ {
+ printf("Couldn't create file %s\n", DumpFileName);
+ return;
+ }
+
+ fprintf(DumpFile,"SYMBOLS:\n");
+
+ for(j=0; j<numsym; j++)
+ {
+ k=symbol[j].UsageType&0xf;
+ fprintf(DumpFile, "%s, %s, %s, 0x%04x, %s\n",
+ symbol[j].name,
+ infn[symbol[j].FileNameNumber].PathName,
+ (symbol[j].Procedure>=0)?procedure[symbol[j].Procedure].name:"GLOBAL",
+ symbol[j].Address,
+ k<6?UsageTypeName[k]:"???");
+ }
+
+ fprintf(DumpFile,"\nPROCEDURES:\n");
+ for(j=0; j<numproc; j++)
+ {
+ fprintf(DumpFile, "%s, %s, 0x%04x-0x%04x, %c\n",
+ procedure[j].name,
+ infn[procedure[j].FileNameNumber].PathName,
+ procedure[j].BeginAdd,
+ procedure[j].EndAdd,
+ procedure[j].RegBank + '0');
+ }
+
+ fprintf(DumpFile,"\nLINE NUMBERS:\n");
+ for(j=0; j<numlinenum; j++)
+ {
+ fprintf(DumpFile, "%d:0x%04x, %s -> %s\n",
+ linenum[j].Number,
+ linenum[j].Address,
+ infn[linenum[j].FileNameNumber].PathName,
+ (linenum[j].Procedure>=0)?procedure[linenum[j].Procedure].name:"I don't know");
+ }
+
+ fclose(DumpFile);
+}
+
+void ParseRegisters(_symbol * symbol, const char * Registers)
+{
+ char c;
+ int i;
+ char regs[0x100][4];
+ int address[4];
+ int nRegs = sscanf(Registers, "[ %[^,] %c %[^,] %c %[^,] %c %[^,] ]",
+ regs[0], &c, regs[1], &c, regs[2], &c, regs[3]);
+ nRegs = (nRegs + 1) / 2;
+ for (i=0; i<nRegs; i++)
+ {
+ if ((regs[i][0] == 'r') && isdigit(regs[i][1]))
+ {
+ address[i] = regs[i][1] - '0';
+ }
+ }
+ for (i=1; i<nRegs; i++)
+ {
+ if (address[i] != address[i-1] + 1)
+ {// we need strict ascending registers
+ return;
+ }
+ }
+ if (0 <= symbol->Procedure && symbol->Procedure < numproc)
+ symbol->Address = address[0] + procedure[symbol->Procedure].RegBank * 8;
+}
+
+void OutputAOEMF51(void)
+{
+ int i, j, k, recsize;
+ char MHRname[0x100], Mname[0x100];
+ char aomf51FileName[PATH_MAX];
+
+ strcpy(aomf51FileName, infn[0].PathName);
+ strcat(aomf51FileName, ".omf");
+
+ aomf51out=fopen(aomf51FileName, "wb");
+ if(aomf51out==NULL)
+ {
+ printf("Couldn't create file %s\n", aomf51FileName);
+ return;
+ }
+
+ GetName(infn[0].PathName, MHRname);
+ GlobalChkSum=0;
+
+ /*Module header record*/
+ OutputByte(0x02);/*REC TYPE*/
+ OutputWord((strlen(MHRname)+1)+3);/*Record Length*/
+ OutputName(MHRname);/*Module Name*/
+ OutputByte(0xff);/*TRN ID: RL51?*/
+ OutputByte(0x00);
+ OutputChkSum();
+
+ for(j=0; j<numin; j++)
+ {
+ GetName(infn[j].PathName, Mname);
+
+ /*Scope Definition record: begin module block*/
+ OutputByte(0x10);/*REC TYPE*/
+ OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+ OutputByte(0x00);/*BLK TYP: module block*/
+ OutputName(Mname);/*Module Name*/
+ OutputChkSum();
+
+ /*Public symbols defined in this module*/
+ recsize=2;
+ for(k=0; k<numsym; k++)/*Compute the record length*/
+ {
+ if ( (symbol[k].FileNameNumber==j) &&
+ (symbol[k].Address!=-1) &&
+ (symbol[k].Procedure==-1) &&
+ (symbol[k].Static==-1) )
+ {
+ recsize+=((strlen(symbol[k].name)+1)+5);
+ }
+ }
+
+ if(recsize>2) /*If there are any symbols*/
+ {
+ OutputByte(0x12); /*REC TYPE*/
+ OutputWord(recsize); /*Record Length*/
+ OutputByte(0x01); /*DEF TYPE: Public symbols*/
+ for(k=0; k<numsym; k++)
+ {
+ if ( (symbol[k].FileNameNumber==j) &&
+ (symbol[k].Address!=-1) &&
+ (symbol[k].Procedure==-1) &&
+ (symbol[k].Static==-1) )
+ {
+ OutputByte(0x00);/*SEG ID*/
+ OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
+ OutputWord(symbol[k].Address);/*Offset*/
+ OutputByte(0x00);
+ OutputName(symbol[k].name);/*Symbol name*/
+ }
+ }
+ OutputChkSum();
+ }
+
+ /*Local symbols defined in this module*/
+ recsize=2;
+ for(k=0; k<numsym; k++)/*Compute the record length*/
+ {
+ if ( (symbol[k].FileNameNumber==j) &&
+ (symbol[k].Address!=-1) &&
+ (symbol[k].Procedure==-1) &&
+ (symbol[k].Static==j) )
+ {
+ recsize+=((strlen(symbol[k].name)+1)+5);
+ }
+ }
+
+ if(recsize>2) /*If there are any symbols*/
+ {
+ OutputByte(0x12); /*REC TYPE*/
+ OutputWord(recsize); /*Record Length*/
+ OutputByte(0x00); /*DEF TYPE: Local symbols*/
+ for(k=0; k<numsym; k++)
+ {
+ if ( (symbol[k].FileNameNumber==j) &&
+ (symbol[k].Address!=-1) &&
+ (symbol[k].Procedure==-1) &&
+ (symbol[k].Static==j) )
+ {
+ OutputByte(0x00);/*SEG ID*/
+ OutputByte((unsigned char)symbol[k].UsageType);/*SYM INFO*/
+ OutputWord(symbol[k].Address);/*Offset*/
+ OutputByte(0x00);
+ OutputName(symbol[k].name);/*Symbol name*/
+ }
+ }
+ OutputChkSum();
+ }
+
+ /*Output the procedures of this module*/
+
+ for(k=0; k<numproc; k++)
+ {
+ if(procedure[k].FileNameNumber==j)
+ {
+ /*Scope Definition record: begin PROCEDURE block*/
+ OutputByte(0x10);/*REC TYPE*/
+ OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
+ OutputByte(0x02);/*BLK TYP: PROCEDURE block*/
+ OutputName(procedure[k].name);/*Module Name*/
+ OutputChkSum();
+
+ /*Content Record*/
+ OutputByte(0x06);/*REC TYPE*/
+ if (procedure[k].EndAdd==-1)
+ procedure[k].EndAdd=HexSize;
+ recsize=procedure[k].EndAdd-procedure[k].BeginAdd+1+4;
+ OutputWord(recsize);/*Record Length*/
+ OutputByte(0x00);/*SEG ID*/
+ OutputWord(procedure[k].BeginAdd); /*Offset*/
+ for (i=procedure[k].BeginAdd; i<=procedure[k].EndAdd; i++)
+ {
+ OutputByte((unsigned char)ihxBuff[i]);
+ ihxBuff[i] -= 0x200;
+ }
+ OutputChkSum();
+
+ /*Local Symbols*/
+
+ recsize=2;
+ for(i=0; i<numsym; i++)/*Get the record length*/
+ {
+ if( (symbol[i].Procedure==k) &&
+ (symbol[i].Address!=-1) )
+ {
+ recsize+=((strlen(symbol[i].name)+1)+5);
+ }
+ }
+
+ if(recsize>2) /*If there are any symbols*/
+ {
+ OutputByte(0x12); /*REC TYPE*/
+ OutputWord(recsize); /*Record Length*/
+ OutputByte(0x00); /*DEF TYPE: Local symbols*/
+ for(i=0; i<numsym; i++)
+ {
+ if ( (symbol[i].Procedure==k) &&
+ (symbol[i].Address!=-1) )
+ {
+ OutputByte(0x00);/*SEG ID*/
+ OutputByte((unsigned char)symbol[i].UsageType);/*SYM INFO*/
+ OutputWord(symbol[i].Address);/*Offset*/
+ OutputByte(0x00);
+ OutputName(symbol[i].name);/*Symbol name*/
+ }
+ }
+ OutputChkSum();
+ }
+
+ /*Line Numbers*/
+ recsize=2;
+ for(i=0; i<numlinenum; i++)/*Get the record length*/
+ if(linenum[i].Procedure==k)
+ recsize+=5;
+
+ if(recsize>2) /*If there are any line numbers*/
+ {
+ OutputByte(0x12); /*REC TYPE*/
+ OutputWord(recsize); /*Record Length*/
+ OutputByte(0x03); /*DEF TYPE: Line numbers*/
+ for(i=0; i<numlinenum; i++)
+ {
+ if ( (linenum[i].Procedure==k) )
+ {
+ OutputByte(0x00);/*SEG ID*/
+ OutputWord(linenum[i].Address);/*Offset*/
+ OutputWord(linenum[i].Number);/*Line Number*/
+ }
+ }
+ OutputChkSum();
+ }
+
+ /*Scope Definition record: end PROCEDURE block*/
+ OutputByte(0x10);/*REC TYPE*/
+ OutputWord((strlen(procedure[k].name)+1)+2);/*Record Length*/
+ OutputByte(0x05);/*BLK TYP: PROCEDURE end block*/
+ OutputName(procedure[k].name);/*Module Name*/
+ OutputChkSum();
+ }
+ }
+
+ /*Scope Definition record: end module block*/
+ OutputByte(0x10);/*REC TYPE*/
+ OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+ OutputByte(0x03);/*BLK TYP: module end*/
+ OutputName(Mname);/*Module Name*/
+ OutputChkSum();
+ }
+
+ /*Content records for everything that is not in the above procedures*/
+ strcpy(Mname, "OTHER_SDCC_STUFF");
+
+ /*Scope Definition record: begin module block*/
+ OutputByte(0x10);/*REC TYPE*/
+ OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+ OutputByte(0x00);/*BLK TYP: module block*/
+ OutputName(Mname);/*Module Name*/
+ OutputChkSum();
+
+ for (i=HexBegin; i<HexSize; )
+ {
+ for (k=i; k<HexSize; k++)
+ {
+ if (ihxBuff[k] < 0)
+ break;
+ }
+ if (k > i)
+ {
+ /*Content Record*/
+ OutputByte(0x06);/*REC TYPE*/
+ OutputWord(k-i+4);/*Record Length*/
+ OutputByte(0x00);/*SEG ID*/
+ OutputWord(i); /*Offset*/
+ for ( ; i<k; i++)
+ {
+ OutputByte((unsigned char)ihxBuff[i]);
+ ihxBuff[i] -= 0x200;
+ }
+ OutputChkSum();
+ }
+ for ( ; i<HexSize; i++)
+ {
+ if (ihxBuff[i] >= 0)
+ break;
+ }
+ }
+
+ /*Scope Definition record: end module block*/
+ OutputByte(0x10);/*REC TYPE*/
+ OutputWord((strlen(Mname)+1)+2);/*Record Length*/
+ OutputByte(0x03);/*BLK TYP: module end*/
+ OutputName(Mname);/*Module Name*/
+ OutputChkSum();
+
+ /*Module end record*/
+ OutputByte(0x04);/*REC TYPE*/
+ OutputWord((strlen(MHRname)+1)+5);/*Record Length*/
+ OutputName(MHRname);/*Module Name*/
+ OutputWord(0x00);
+ OutputByte(0x0f);/*REG MSK: All the register banks?*/
+ OutputByte(0x00);
+ OutputChkSum();
+
+ fclose(aomf51out);
+}
+
+void CollectInfoFromCDB(void)
+{
+ int i, j, k, CurrentModule;
+ FILE * CDBin;
+ char buff[0x1000];
+ char SourceName[PATH_MAX];
+
+ //"S:{G|F<filename>|L<filename>.<functionName>}$<name>$<level>$<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>"
+ char Sfmt[]="%[^$] %c %[^$] %c %[^$] %c %s";
+ char c;
+ char module[0x100];
+ char scope[0x100];
+ char name[0x100];
+ char level[0x100];
+ char block[0x100];
+ char TypeInfo[0x100];
+ char AddressSpace;
+ int OnStack;
+ int StackOffset;
+ int IsISR;
+ int IntNr;
+ int RegBank;
+ char Registers[0x100];
+ int Address, CLine;
+
+ if(numin==0) return;
+
+ if (yfp != NULL)
+ {
+ fclose(yfp);
+ yfp=NULL;
+ }
+
+ /*Build the source filename*/
+ strcpy(SourceName, infn[0].PathName);
+ strcat(SourceName, ".cdb");
+ CDBin=fopen(SourceName, "r");
+ if(CDBin==NULL)
+ {
+ printf("Couldn't open file '%s'\n", SourceName);
+ lkexit(1);
+ }
+
+ CurrentModule=0; /*Set the active module as the first one*/
+ while(!feof(CDBin))
+ {
+ if(NULL==fgets(buff, sizeof(buff)-1, CDBin))
+ {
+ if(ferror(CDBin))
+ {
+ perror("Can't read file");
+ lkexit(1);
+ }
+ else if(!feof(CDBin))
+ {
+ fprintf(stderr, "Unknown error while reading file '%s'\n", SourceName);
+ lkexit(1);
+ }
+ }
+
+ if(!feof(CDBin)) switch(buff[0])
+ {
+ /*Example: "M:adq"*/
+ case 'M':
+ sscanf(&buff[2], "%s", name);
+ for(j=0; j<numin; j++)
+ if(EQ(infn[j].ModuleName, name)) break;
+ if(j<numin) CurrentModule=j;
+ break;
+
+ /* Example:
+ "S:G$actual$0$0({7}ST__00010000:S),E,0,0"
+ "S:Lfile.main$j$1$1({2}SI:S),E,0,0"
+ "S:Lfile.main$k$1$1({2}DG,SI:S),R,0,0,[r2,r3]"
+ "S:G$DS1306_Reset_SPI$0$0({2}DF,SV:S),C,0,0"
+ "S:G$main$0$0({2}DF,SV:S),C,0,0"
+ */
+
+ case 'S':
+ sscanf(buff, Sfmt,
+ scope, &c,
+ name, &c,
+ level, &c,
+ block);
+
+ /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>*/
+ sscanf(block, "%[^)] %c %c %c %c %d %c %d %c %s",
+ TypeInfo, &c, &c,
+ &AddressSpace, &c,
+ &OnStack, &c,
+ &StackOffset, &c,
+ Registers);
+
+ i=-1; k=-1;
+ switch(scope[2])
+ {
+ case 'G': /*Global symbol*/
+ break;
+ case 'F': /*Local symbol to a module*/
+ for(j=0; j<numin; j++)
+ {
+ if (EQ(&scope[3], infn[j].ModuleName))
+ {
+ i = j;
+ break;
+ }
+ }
+ break;
+ case 'L': /*Local symbol of a procedure*/
+ for(j=0; j<numproc; j++)
+ {
+ size_t mlen = strlen(infn[procedure[j].FileNameNumber].ModuleName);
+ if ((!strncmp (&scope[3], infn[procedure[j].FileNameNumber].ModuleName, mlen)) &&
+ (scope[mlen+3] == '.') &&
+ (EQ(&scope[mlen+4], procedure[j].name)))
+ {
+ k = j; /*Local symbol*/
+ break;
+ }
+ }
+ break;
+ }
+
+ /*This symbol may have been already defined*/
+ for (j=0; j<numsym; j++)
+ {
+ if (EQ(name, symbol[j].name) &&
+ (symbol[j].Procedure == k) &&
+ (symbol[j].Static == i) ) break;
+ }
+ if(j==numsym) /*New symbol*/
+ {
+ symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
+ symbol[numsym].FileNameNumber=CurrentModule;
+ strcpy(symbol[numsym].name, name);
+ symbol[numsym].Procedure=k;
+ symbol[numsym].Static=i;
+ symbol[numsym].Address=-1;/*Collected later*/
+
+ switch(AddressSpace)
+ {
+ case 'C': /*Code*/
+ case 'D': /*Code/static segment*/
+ case 'Z': /*Functions and undefined code space*/
+ symbol[numsym].UsageType=0x40;
+ break;
+
+ case 'F': /*External ram*/
+ case 'A': /*External stack*/
+ case 'P': /*External Pdata*/
+ symbol[numsym].UsageType=0x41;
+ break;
+
+ case 'E': /*Internal ram (lower 128) bytes*/
+ case 'I': /*SFR space*/
+ symbol[numsym].UsageType=0x42;
+ break;
+
+ case 'R': /*Register Space*/
+ ParseRegisters(&symbol[numsym], Registers);
+ symbol[numsym].UsageType=0x42;
+ break;
+
+ case 'B': /*Internal stack*/
+ case 'G': /*Internal ram*/
+ symbol[numsym].UsageType=0x43;
+ break;
+
+ case 'H': /*Bit addressable*/
+ case 'J': /*SBIT space*/
+ symbol[numsym].UsageType=0x44;
+ break;
+
+ default:
+ printf("Unknown scope information for: %s, AddressSpace:%c\n", symbol[numsym].name, AddressSpace);
+ break;
+ }
+ numsym++;
+ }
+ break;
+
+ /*Examples:
+ F:G$AsciiToHex$0$0({2}DF,SC:U),C,0,0,0,0,0
+ F:G$main$0$0({2}DF,SV:S),C,0,0,0,0,0
+ F:Fbug1627975$f2$0$0({2}DF,DG,SI:U),C,0,0,0,0,0 */
+
+ case 'F':
+ sscanf(buff, "%[^$] %c %[^$] %c %[^$] %c %s",
+ scope, &c,
+ name, &c,
+ level, &c,
+ block);
+
+ /*<block>(<type info>),<Address Space>,<on Stack?>,<stack offset>,<isr?>,<int nr>,<regbank> */
+ sscanf(block, "%[^)] %c %c %c %c %d %c %d %c %d %c %d %c %d",
+ TypeInfo, &c, &c,
+ &AddressSpace, &c,
+ &OnStack, &c,
+ &StackOffset, &c,
+ &IsISR, &c,
+ &IntNr, &c,
+ &RegBank);
+ /*The same may have been already defined */
+ for(j=0; j<numproc; j++)
+ {
+ if (EQ(name, procedure[j].name) &&
+ (procedure[j].FileNameNumber == CurrentModule))
+ {
+ break;
+ }
+ }
+ if (j==numproc)
+ {
+ procedure=realloc(procedure, sizeof(_procedure)*(numproc+1));
+ strcpy(procedure[numproc].name, name);
+ procedure[numproc].FileNameNumber=CurrentModule;
+ procedure[numproc].BeginAdd=-1;/*To be collected latter*/
+ procedure[numproc].EndAdd=-1;/*To be collected latter*/
+ procedure[numproc].RegBank=RegBank;
+ numproc++;
+ }
+
+ /*This function name is also a global symbol*/
+ for(j=0; j<numsym; j++)/*A global symbol may have been already defined*/
+ {
+ if (EQ(name, symbol[j].name) &&
+ (symbol[j].Procedure==-1) &&
+ (symbol[j].FileNameNumber == CurrentModule))
+ {
+ break;
+ }
+ }
+ if (j==numsym)
+ {
+ symbol=realloc(symbol, sizeof(_symbol)*(numsym+1));
+ symbol[numsym].FileNameNumber=CurrentModule;
+ strcpy(symbol[numsym].name, name);
+ symbol[numsym].UsageType=0x00;/*A procedure name symbol*/
+ symbol[numsym].Procedure=-1; /*Global symbol*/
+ symbol[numsym].Address=-1;/*Collected later*/
+ symbol[numsym].Static= buff[2]=='F' ? CurrentModule : -1; // o_gloom
+ numsym++;
+ }
+ break;
+
+ case 'L':
+ switch(buff[2])
+ {
+ case 'G': /*Example L:G$P0$0$0:80*/
+ sscanf(buff, "%[^$] %c %[^$] %c %[^:] %c %x",
+ scope, &c, name, &c, level, &c, &Address);
+
+ for(j=0; j<numsym; j++)
+ {
+ if(EQ(symbol[j].name, name))
+ {
+ if( (symbol[j].Address==-1) && (symbol[j].Procedure==-1) )
+ {
+ symbol[j].Address=Address;
+ }
+
+ /*If the symbol is the name of a procedure, the address is also
+ the begining of such procedure*/
+ if ((symbol[j].UsageType & 0x0f) == 0x00)
+ {
+ for (k=0; k<numproc; k++)
+ {
+ if (EQ(symbol[j].name, procedure[k].name))
+ {
+ if (procedure[k].BeginAdd == -1)
+ procedure[k].BeginAdd = Address;
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+ break;
+
+ case 'F': /*Example L:Fadq$_str_2$0$0:57A*/
+ sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
+ scope, &c, name, &c, level, &c, &Address);
+
+ for (j=0; j<numsym; j++)
+ {
+ if (EQ(symbol[j].name, name) &&
+ EQ(infn[symbol[j].FileNameNumber].ModuleName, scope))
+ {
+ if( (symbol[j].Address == -1) )
+ {
+ symbol[j].Address = Address;
+ }
+ break;
+ }
+ }
+
+ /*It could be also a static function*/
+ for (j=0; j<numproc; j++)
+ {
+ if (EQ(procedure[j].name, name) &&
+ EQ(infn[procedure[j].FileNameNumber].ModuleName, scope))
+ {
+ if( (procedure[j].BeginAdd == -1) )
+ {
+ procedure[j].BeginAdd = Address;
+ }
+ break;
+ }
+ }
+
+ break;
+
+ case 'L': /*Example L:Lmain$j$1$1:29*/
+
+ /*
+ L:Lds1306.DS1306_Write$Value$1$1:34
+ L:Lds1306.DS1306_Burst_Read$count$1$1:35
+ L:Lds1306.DS1306_Burst_Read$address$1$1:36
+ L:Lds1306.DS1306_Burst_Write$count$1$1:37
+ L:Lds1306.DS1306_Burst_Write$address$1$1:38
+ */
+ sscanf(&buff[3], "%[^.] %c %[^$] %c %[^$] %c %[^:] %c %x",
+ module, &c, scope, &c, name, &c, level, &c, &Address);
+
+ for (k=0; k<numproc; k++)
+ {
+ if (EQ(procedure[k].name, scope) &&
+ EQ(infn[procedure[k].FileNameNumber].ModuleName, module))
+ {
+ for (j=0; j<numsym; j++)
+ {
+ if ((symbol[j].FileNameNumber == procedure[k].FileNameNumber) &&
+ (symbol[j].Procedure == k) &&
+ (EQ(symbol[j].name, name)))
+ {
+ if (symbol[j].Address == -1)
+ symbol[j].Address = Address;
+ break;
+ }
+ }
+ if (j<numsym)
+ break;
+ }
+ }
+ break;
+
+ /*Line Numbers*/
+ case 'C': /*Example L:C$adq.c$38$1$1:3E*/ /*L:C$hwinit.c$29$1$1:7AD*/
+ sscanf(&buff[4], "%[^.] %[^$] %c %d %[^:] %c %x",
+ name, level, &c, &CLine, level, &c, &Address);
+
+ for(j=0; j<numin; j++)
+ if(EQ(infn[j].ModuleName, name)) break;
+ if(j<numin)
+ {
+ /*Check if this line is already defined*/
+ for(k=0; k<numlinenum; k++)
+ {
+ if( (linenum[k].Number==CLine) &&
+ (linenum[k].FileNameNumber==j) )break;
+ }
+ if(k==numlinenum) /*New line number*/
+ {
+ linenum=realloc(linenum, sizeof(_linenum)*(numlinenum+1));
+ linenum[numlinenum].Number=CLine;
+ linenum[numlinenum].FileNameNumber=j;
+ linenum[numlinenum].Procedure=-1;/*To be asigned later*/
+ linenum[numlinenum].Address=Address;
+ numlinenum++;
+ }
+ }
+ break;
+
+ case 'A': /*Example L:A$adq$424:40*/
+ /*No use for this one*/
+ break;
+
+ /*The end of a procedure*/
+ case 'X': /*Example L:XG$AsciiToHex$0$0:88*/
+ sscanf(&buff[3], "%[^$] %c %[^$] %c %[^:] %c %x",
+ scope, &c, name, &c, level, &c, &Address);
+
+ for(k=0; k<numproc; k++)
+ {
+ if (EQ(procedure[k].name, name) &&
+ (scope[0] == 'G' ||
+ EQ(infn[procedure[k].FileNameNumber].ModuleName, &scope[1])))
+ {
+ if( (procedure[k].EndAdd == -1) )
+ {
+ procedure[k].EndAdd = Address;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ /*Make sure each procedure has an end*/
+ for(k=0; k<(numproc-1); k++)
+ {
+ if (procedure[k].EndAdd==-1) procedure[k].EndAdd=procedure[k+1].BeginAdd-1;
+ }
+ /*Assign each line number to a procedure*/
+ for(j=0; j<numlinenum; j++)
+ {
+ for(k=0; k<numproc; k++)
+ {
+ if ( (linenum[j].Address>=procedure[k].BeginAdd) &&
+ (linenum[j].Address<=procedure[k].EndAdd) &&
+ (linenum[j].FileNameNumber==procedure[k].FileNameNumber) )
+ {
+ linenum[j].Procedure=k;
+ }
+ }
+ }
+
+ fclose(CDBin);
+}
+
+int hex2dec (unsigned char hex_digit)
+{
+ if (isdigit (hex_digit))
+ return hex_digit-'0';
+ else
+ return toupper (hex_digit)-'A'+10;
+}
+
+unsigned char GetByte(char * buffer)
+{
+ return hex2dec(buffer[0])*0x10+hex2dec(buffer[1]);
+}
+
+unsigned short GetWord(char * buffer)
+{
+ return hex2dec(buffer[0])*0x1000+
+ hex2dec(buffer[1])*0x100+
+ hex2dec(buffer[2])*0x10+
+ hex2dec(buffer[3]);
+}
+
+int ReadHexFile(int * Begin)
+{
+ char ihxFileName[PATH_MAX];
+ char buffer[1024];
+ FILE * filein;
+ int j;
+ unsigned char linesize, recordtype, rchksum, value;
+ int address, hi_addr = 0;
+ int MaxAddress = 0;
+ int chksum;
+
+ /*If the hexfile is already open, close it*/
+ if(ofp!=NULL)
+ {
+ fclose(ofp);
+ ofp=NULL;
+ }
+
+ strcpy(ihxFileName, infn[0].PathName);
+ strcat(ihxFileName, ".ihx");
+
+ if ( (filein=fopen(ihxFileName, "r")) == NULL )
+ {
+ printf("Error: Can't open file `%s`.\r\n", ihxFileName);
+ return 0;
+ }
+
+ ihxBuff = calloc(MEMSIZE, sizeof(short));
+ if (ihxBuff==NULL)
+ {
+ printf("Insufficient memory\n");
+ fclose(filein);
+ return -1;
+ }
+
+ for (j=0; j<MEMSIZE; j++) ihxBuff[j]=-1;
+
+ while(1)
+ {
+ if(fgets(buffer, sizeof(buffer), filein)==NULL)
+ {
+ printf("Error reading file '%s'\n", ihxFileName);
+ break;
+ }
+ if(buffer[0]==':')
+ {
+ linesize = GetByte(&buffer[1]);
+ address = hi_addr | GetWord(&buffer[3]);
+ recordtype = GetByte(&buffer[7]);
+ rchksum = GetByte(&buffer[9]+(linesize*2));
+ chksum=linesize+(address/0x100)+(address%0x100)+recordtype+rchksum;
+
+ switch (recordtype)
+ {
+ case 0:
+ for (j=0; j<linesize; j++)
+ {
+ value = GetByte(&buffer[9]+(j*2));
+ chksum += value;
+ ihxBuff[address+j] = value;
+ }
+ if (MaxAddress < (address+linesize-1))
+ MaxAddress = (address+linesize-1);
+ if (address < *Begin)
+ *Begin = address;
+ break;
+
+ case 4:
+ hi_addr = (GetWord(&buffer[9]) << 16) & 0x00FFFFFF; //upto 24 bit address space
+ break;
+
+ default:
+ break;
+ }
+
+ if ((chksum % 0x100) != 0)
+ {
+ printf("ERROR: Bad checksum in file %s\n", ihxFileName);
+ fclose(filein);
+ return -1;
+ }
+
+ if (recordtype==1) /*End of record*/
+ break;
+ }
+ }
+ fclose(filein);
+
+ return MaxAddress;
+}
+
+void CreateAOMF51(void)
+{
+ if((yflag) && (!rflag))
+ {
+ CollectInfoFromCDB();
+#if DODUMP
+ DumpForDebug();
+#endif
+ HexSize=ReadHexFile(&HexBegin)+1;
+ OutputAOEMF51();
+ FreeAll();
+ }
+}
--- /dev/null
+/* lkar.c - ar library format handling
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+ Copyright (C) 2008-2009 Borut Razem, borut dot razem at gmail dot com
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <assert.h>
+
+#include "aslink.h"
+#include "lklibr.h"
+#include "lkrel.h"
+#include "lkar.h"
+
+
+#ifndef max
+# define max(a,b) ((a) > (b) ? (a) : (b))
+#endif
+
+#ifndef min
+# define min(a,b) ((a) < (b) ? (a) : (b))
+#endif
+
+static int
+is_ar (FILE * libfp)
+{
+ char buf[SARMAG];
+ int ret;
+
+ if (!(ret = fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, ARMAG, SARMAG) == 0))
+ rewind (libfp);
+
+ return ret;
+}
+
+static char *str_tab; /* string table */
+static int str_tab_size; /* string table size */
+
+static char *
+get_long_name (const char *name)
+{
+ assert ('/' == name[0]);
+
+ if (NULL != str_tab)
+ {
+ char *p;
+
+ int name_offset = strtol (++name, &p, 0);
+ if (p != name && name_offset < str_tab_size)
+ {
+ int len = p - name + 1;
+ while (len < AR_NAME_LEN && name[len++] == ' ')
+ ;
+ if (len == AR_NAME_LEN)
+ {
+ const char *n;
+
+ /* long name: get it from the symbol table */
+ name = &str_tab[name_offset];
+ for (n = name; *n != '/' && *n != '\n'; ++n)
+ assert (n < &str_tab[str_tab_size]);
+
+ if (n[0] != '/' || n[1] != '\n')
+ while (*++n != '\n')
+ assert (n < &str_tab[str_tab_size]);
+
+ return strndup (name, n - name);
+ }
+ }
+ }
+ return NULL;
+}
+
+static char *
+get_member_name (char *name, size_t *p_size, int allocate, FILE * libfp)
+{
+ if (p_size != NULL)
+ *p_size = 0;
+
+ if (0 == memcmp (name, "#1/", 3))
+ {
+ char *p;
+ size_t len = strtoul (&name [3], &p, 10);
+ if (p > &name [3])
+ {
+ /* BSD appends real file name to the file header */
+ if (p_size != NULL)
+ *p_size = len;
+
+ if (allocate)
+ {
+ char *n = (char *) malloc (len);
+ if (fread (n, 1, len, libfp) != len)
+ {
+ /* not an ar archive or broken ar archive */
+ free (n);
+ return NULL;
+ }
+ else
+ return n;
+ }
+ else
+ {
+ /* just advance the file pointer */
+ fseek (libfp, len, SEEK_CUR);
+ return NULL;
+ }
+ }
+ else
+ {
+ /* not an ar archive or broken ar archive */
+ return NULL;
+ }
+ }
+ else if (allocate)
+ {
+ if (name[0] == '/')
+ {
+ char *n = get_long_name (name);
+ if (NULL != n)
+ return n;
+ }
+ else
+ {
+ const char *p = strrchr (name + 1, '/');
+
+ if (NULL != p)
+ {
+ int len = p - name;
+ while (name[++len] == ' ')
+ ;
+ if (len == AR_NAME_LEN)
+ return strndup (name, p - name);
+ }
+ else
+ {
+ /* BSD formed member name:
+ trim trailing spaces */
+ p = name + AR_NAME_LEN;
+ while (*--p == ' ' && p >= name)
+ ;
+ return strndup (name, p - name + 1);
+ }
+ }
+
+ /* bad formed member name or long name not found:
+ just return it */
+
+ return strdup (name);
+ }
+ else
+ return NULL;
+}
+
+static size_t
+ar_get_header (struct ar_hdr *hdr, FILE * libfp, char **p_obj_name)
+{
+ char header[ARHDR_LEN];
+ char buf[AR_DATE_LEN + 1];
+ char *obj_name;
+ size_t size;
+
+ if (fread (header, 1, sizeof (header), libfp) != sizeof (header)
+ || memcmp (header + AR_FMAG_OFFSET, ARFMAG, AR_FMAG_LEN) != 0)
+ {
+ /* not an ar archive */
+ return 0;
+ }
+
+ memcpy (hdr->ar_name, &header[AR_NAME_OFFSET], AR_NAME_LEN);
+ hdr->ar_name[AR_NAME_LEN] = '\0';
+
+ memcpy (buf, &header[AR_DATE_OFFSET], AR_DATE_LEN);
+ buf[AR_DATE_LEN] = '\0';
+ hdr->ar_date = strtol (buf, NULL, 0);
+
+ memcpy (buf, &header[AR_UID_OFFSET], AR_GID_LEN);
+ buf[AR_GID_LEN] = '\0';
+ hdr->ar_uid = (uid_t) strtol (buf, NULL, 0);
+
+ memcpy (buf, &header[AR_GID_OFFSET], AR_DATE_LEN);
+ buf[AR_DATE_LEN] = '\0';
+ hdr->ar_gid = (gid_t) strtol (buf, NULL, 0);
+
+ memcpy (buf, &header[AR_MODE_OFFSET], AR_MODE_LEN);
+ buf[AR_MODE_LEN] = '\0';
+ hdr->ar_mode = (mode_t) strtoul (buf, NULL, 0);
+
+ memcpy (buf, &header[AR_SIZE_OFFSET], AR_SIZE_LEN);
+ buf[AR_SIZE_LEN] = '\0';
+ hdr->ar_size = strtol (buf, NULL, 0);
+
+ obj_name = get_member_name (hdr->ar_name, &size, p_obj_name != NULL, libfp);
+
+ if (p_obj_name != NULL)
+ *p_obj_name = obj_name;
+
+ /* treat BSD appended real file name as a part of the header */
+ hdr->ar_size -= size;
+
+ return size + ARHDR_LEN;
+}
+
+#ifdef INDEXLIB
+static char *
+get_member_name_by_offset (FILE * fp, long offset)
+{
+ struct ar_hdr hdr;
+ char *name;
+
+ fseek (fp, offset, SEEK_SET);
+ return (ar_get_header (&hdr, fp, &name) != 0) ? name : NULL;
+}
+
+static pmlibraryfile
+find_member_by_offset (const char *libspc, long offset)
+{
+ pmlibraryfile p;
+
+ /* walk trough all archive members */
+ for (p = libr; p; p = p->next)
+ {
+ if (0 == strcmp (libspc, p->libspc) && p->offset == offset)
+ return p;
+ }
+
+ return NULL;
+}
+
+static pmlibraryfile
+buildlibraryindex_ar (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
+{
+ struct ar_hdr hdr;
+ char *obj_name;
+ size_t hdr_size;
+ int sym_found = 0;
+
+ /* walk trough all archive members */
+ while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+ {
+ long pos = ftell (libfp);
+
+ if (AR_IS_SYMBOL_TABLE (obj_name))
+ {
+ char *buf, *po, *ps;
+ int i;
+ long nsym;
+
+ /* duplicated symbol table */
+ assert (!sym_found);
+
+ free (obj_name);
+
+ buf = (char *) new (hdr.ar_size);
+
+ if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (buf);
+ return This;
+ }
+
+ nsym = sgetl (buf);
+
+ po = buf + 4;
+ ps = po + nsym * 4;
+
+ for (i = 0; i < nsym; ++i)
+ {
+ pmlibrarysymbol ThisSym;
+ char *sym;
+ long offset;
+ pmlibraryfile entry;
+
+ offset = sgetl (po);
+ po += 4;
+
+ sym = strdup (ps);
+ ps += strlen (ps) + 1;
+
+ if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
+ {
+ for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
+ ;
+ }
+ else
+ {
+ /* Opened OK - create a new libraryfile object for it */
+ if (This == NULL)
+ {
+ assert (libr == NULL);
+ libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+ }
+ else
+ {
+ This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+ This = This->next;
+ }
+ This->next = NULL;
+ This->loaded = 0;
+ This->libspc = lbnh->libspc;
+ This->offset = offset;
+ This->relfil = get_member_name_by_offset (libfp, offset); /* member name */
+ This->filspc = strdup (This->relfil); /* member file name */
+ This->type = type;
+
+ /* start a new linked list of symbols for this module. */
+ This->symbols = ThisSym = NULL;
+ }
+
+ if (ThisSym == NULL)
+ ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+ else
+ {
+ ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+ ThisSym = ThisSym->next;
+ }
+ ThisSym->next = NULL;
+ ThisSym->name = sym;
+ }
+ free (buf);
+
+ sym_found = 1;
+
+ /* string table already found: finish */
+ if (str_tab)
+ break;
+ }
+ else if (AR_IS_BSD_SYMBOL_TABLE (obj_name))
+ {
+ char *buf, *po, *ps;
+ int i;
+ long nsym, tablesize;
+
+ /* duplicated symbol table */
+ assert (!sym_found);
+
+ free (obj_name);
+
+ buf = (char *) new (hdr.ar_size);
+
+ if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (buf);
+ return This;
+ }
+
+ tablesize = sgetl (buf);
+ nsym = tablesize / 8;
+
+ po = buf + 4;
+
+ ps = po + tablesize + 4;
+
+ for (i = 0; i < nsym; ++i)
+ {
+ pmlibrarysymbol ThisSym;
+ char *sym;
+ long offset;
+ pmlibraryfile entry;
+
+ sym = ps + sgetl (po);
+ po += 4;
+ offset = sgetl (po);
+ po += 4;
+
+ sym = strdup (ps);
+
+ if ((entry = find_member_by_offset (lbnh->libspc, offset)) != NULL)
+ {
+ for (ThisSym = entry->symbols; ThisSym->next != NULL; ThisSym = ThisSym->next)
+ ;
+ }
+ else
+ {
+ /* Opened OK - create a new libraryfile object for it */
+ if (This == NULL)
+ {
+ assert (libr == NULL);
+ libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+ }
+ else
+ {
+ This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+ This = This->next;
+ }
+ This->next = NULL;
+ This->loaded = 0;
+ This->libspc = lbnh->libspc;
+ This->offset = offset;
+ This->relfil = get_member_name_by_offset (libfp, offset); /* member name */
+ This->filspc = strdup (This->relfil); /* member file name */
+ This->type = type;
+
+ /* start a new linked list of symbols for this module. */
+ This->symbols = ThisSym = NULL;
+ }
+
+ if (ThisSym == NULL)
+ ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+ else
+ {
+ ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+ ThisSym = ThisSym->next;
+ }
+ ThisSym->next = NULL;
+ ThisSym->name = sym;
+ }
+ free (buf);
+
+ sym_found = 1;
+
+ /* string table already found: finish */
+ if (str_tab)
+ break;
+ }
+ else if (AR_IS_STRING_TABLE (obj_name))
+ {
+ free (obj_name);
+
+ /* duplicated string table */
+ assert (NULL == str_tab);
+
+ str_tab = (char *) new (hdr.ar_size);
+
+ if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (str_tab);
+ str_tab_size = 0;
+ return This;
+ }
+ str_tab_size = hdr.ar_size;
+
+ /* sybol table already found: finish */
+ if (sym_found)
+ break;
+ }
+ else
+ {
+ if (NULL == libr)
+ {
+ /* Opened OK - create a new libraryfile object for it */
+ if (This == NULL)
+ {
+ assert (libr == NULL);
+ libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+ }
+ else
+ {
+ This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+ This = This->next;
+ }
+ This->next = NULL;
+ This->loaded = -1;
+ This->libspc = lbnh->libspc;
+ This->offset = pos - hdr_size;
+
+ This->relfil = obj_name; /* member name */
+ This->filspc = strdup (This->relfil); /* member file name */
+
+ D (" Indexing module: %s\n", This->relfil);
+
+ This->type = type;
+
+ /* start a new linked list of symbols for this module. */
+ This->symbols = NULL;
+
+ add_rel_index (libfp, hdr.ar_size, This);
+ }
+ }
+ fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
+ }
+
+ if (NULL != str_tab)
+ {
+ /* has a symbol table: walk through modules and replace offsets with names */
+ pmlibraryfile lfp;
+
+ for (lfp = libr; lfp; lfp = lfp->next)
+ {
+ char *name = lfp->relfil;
+ if (name[0] == '/')
+ {
+ char *p = get_long_name (name);
+ if (NULL != p)
+ {
+ free (lfp->relfil);
+ lfp->relfil = p;
+ free (lfp->filspc);
+ lfp->filspc = strdup (p);
+ }
+ }
+ }
+
+
+ free (str_tab);
+ str_tab = NULL;
+ str_tab_size = 0;
+ }
+
+ return This;
+}
+
+#else
+
+#if 0
+static int
+load_adb (FILE * libfp, struct lbfile *lbfh)
+{
+ struct ar_hdr hdr;
+ char *adb_name;
+ char *obj_name;
+ size_t hdr_size;
+
+ /* check if it is a .rel file */
+ if (0 != stricmp (&lbfh->relfil[strlen (lbfh->relfil) - 4], ".rel"))
+ return 0;
+
+
+ adb_name = (char *) new (strlen (lbfh->relfil) + 1);
+ memcpy (adb_name, lbfh->relfil, strlen (lbfh->relfil) - 4);
+ memcpy (&adb_name[strlen (lbfh->relfil) - 4], ".adb", 5);
+
+ if (!is_ar (libfp))
+ {
+ fprintf (stderr, "?ASlink-Error-%s is not an archive\n", lbfh->libspc);
+ fclose (libfp);
+ lkexit (1);
+ }
+
+ /* walk trough all archive members */
+ while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+ {
+ if (AR_IS_STRING_TABLE (obj_name))
+ {
+ free (obj_name);
+
+ if (str_tab)
+ free (str_tab);
+
+ str_tab = (char *) new (hdr.ar_size);
+
+ if ((off_t) fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (str_tab);
+ str_tab_size = 0;
+ return 0;
+ }
+ str_tab_size = hdr.ar_size;
+ }
+ if (AR_IS_SYMBOL_TABLE (obj_name) || 0 != stricmp (obj_name, adb_name))
+ {
+ free (obj_name);
+
+ /* skip the mamber */
+ fseek (libfp, hdr.ar_size + (hdr.ar_size & 1), SEEK_CUR);
+ }
+ else
+ {
+ long left = hdr.ar_size;
+ char buf[4096];
+
+ free (obj_name);
+
+ while (left)
+ {
+ size_t n = min (left, sizeof buf);
+
+ if (fread (buf, 1, n, libfp) != n)
+ {
+ assert (0);
+ }
+
+ fwrite (buf, 1, n, yfp);
+
+ left -= n;
+ }
+
+ if (hdr.ar_size & 1)
+ getc (libfp);
+
+ free (adb_name);
+ return 1;
+ }
+ }
+
+ free (adb_name);
+ return 0;
+}
+#endif
+
+static void
+load_str_tab (FILE * libfp)
+{
+ struct ar_hdr hdr;
+ char *obj_name;
+ size_t hdr_size;
+
+ /* walk trough all archive members */
+ while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+ {
+ long pos = ftell (libfp);
+
+ if (AR_IS_STRING_TABLE (obj_name))
+ {
+ free (obj_name);
+
+ /* duplicated string table */
+ assert (NULL == str_tab);
+
+ str_tab = (char *) new (hdr.ar_size);
+
+ if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (str_tab);
+ str_tab_size = 0;
+ return;
+ }
+ str_tab_size = hdr.ar_size;
+ return;
+
+ }
+ fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
+ }
+}
+
+static int
+fndsym_ar (const char *name, struct lbname *lbnh, FILE * libfp, int type)
+{
+ struct ar_hdr hdr;
+ int ret = 0;
+ size_t hdr_size;
+ char *obj_name;
+ long pos;
+
+ pos = ftell (libfp);
+ load_str_tab (libfp);
+ fseek (libfp, pos, SEEK_SET);
+
+ /* walk trough all archive members */
+ while ((hdr_size = ar_get_header (&hdr, libfp, &obj_name)) != 0)
+ {
+ char filspc[PATH_MAX] = { 0 };
+
+ if (lbnh->path != NULL)
+ {
+ strcpy (filspc, lbnh->path);
+ if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
+ {
+ strcat (filspc, LKDIRSEPSTR);
+ }
+ }
+
+ if (AR_IS_SYMBOL_TABLE (obj_name))
+ {
+ char *buf, *po, *ps;
+ int i;
+ long nsym;
+
+ free (obj_name);
+
+ buf = (char *) new (hdr.ar_size);
+
+ if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (buf);
+ return 0;
+ }
+
+ nsym = sgetl (buf);
+
+ po = buf + 4;
+ ps = po + nsym * 4;
+
+ for (i = 0; i < nsym; ++i)
+ {
+ char *sym;
+ long offset;
+
+ offset = sgetl (po);
+ po += 4;
+
+ sym = ps;
+ while (*ps++ != '\0')
+ ;
+
+ if (0 == strcmp (name, sym))
+ {
+ fseek (libfp, offset, SEEK_SET);
+ if (ar_get_header (&hdr, libfp, &obj_name))
+ {
+ sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
+
+ /* If this module has been loaded already don't load it again. */
+ if (!is_module_loaded (filspc))
+ {
+ struct lbfile *lbfh, *lbf;
+
+ lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+ lbfh->libspc = strdup (lbnh->libspc);
+ lbfh->relfil = obj_name;
+ lbfh->filspc = strdup (filspc);
+ lbfh->offset = offset;
+ lbfh->type = type;
+
+ if (lbfhead == NULL)
+ {
+ lbfhead = lbfh;
+ }
+ else
+ {
+ for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+ ;
+
+ lbf->next = lbfh;
+ }
+
+ D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
+ load_rel (libfp, hdr.ar_size);
+ ///* if cdb information required & .adb file present */
+ //if (yflag && yfp)
+ // {
+ // if (load_adb(FILE *libfp, struct lbfile *lbfh))
+ // SaveLinkedFilePath (filspc);
+ // }
+ ret = 1;
+ break;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
+ fclose (libfp);
+ lkexit (1);
+ }
+ }
+ }
+ free (buf);
+
+ break;
+ }
+ else if (AR_IS_BSD_SYMBOL_TABLE (obj_name))
+ {
+ char *buf, *po, *ps;
+ int i;
+ long nsym, tablesize;
+
+ free (obj_name);
+
+ buf = (char *) new (hdr.ar_size);
+
+ if (fread (buf, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (buf);
+ return 0;
+ }
+
+ tablesize = sgetl (buf);
+ nsym = tablesize / 8;
+
+ po = buf + 4;
+
+ ps = po + tablesize + 4;
+
+ for (i = 0; i < nsym; ++i)
+ {
+ char *sym;
+ long offset;
+
+ sym = ps + sgetl (po);
+ po += 4;
+ offset = sgetl (po);
+ po += 4;
+
+ if (0 == strcmp (name, sym))
+ {
+ fseek (libfp, offset, SEEK_SET);
+ if (ar_get_header (&hdr, libfp, &obj_name))
+ {
+ sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
+
+ /* If this module has been loaded already don't load it again. */
+ if (!is_module_loaded (filspc))
+ {
+ struct lbfile *lbfh, *lbf;
+
+ lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+ lbfh->libspc = strdup (lbnh->libspc);
+ lbfh->relfil = obj_name;
+ lbfh->filspc = strdup (filspc);
+ lbfh->offset = offset;
+ lbfh->type = type;
+
+ if (lbfhead == NULL)
+ {
+ lbfhead = lbfh;
+ }
+ else
+ {
+ for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+ ;
+
+ lbf->next = lbfh;
+ }
+
+ D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
+ load_rel (libfp, hdr.ar_size);
+ ///* if cdb information required & .adb file present */
+ //if (yflag && yfp)
+ // {
+ // if (load_adb(FILE *libfp, struct lbfile *lbfh))
+ // SaveLinkedFilePath (filspc);
+ // }
+ ret = 1;
+ break;
+ }
+ }
+ else
+ {
+ fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbnh->libspc, name);
+ fclose (libfp);
+ lkexit (1);
+ }
+ }
+ }
+ free (buf);
+
+ break;
+ }
+ else if (AR_IS_STRING_TABLE (obj_name))
+ {
+ free (obj_name);
+
+ if (str_tab)
+ free (str_tab);
+
+ str_tab = (char *) new (hdr.ar_size);
+
+ if (fread (str_tab, 1, hdr.ar_size, libfp) != hdr.ar_size)
+ {
+ free (str_tab);
+ str_tab = NULL;
+ str_tab_size = 0;
+ return 0;
+ }
+ str_tab_size = hdr.ar_size;
+ }
+ else
+ {
+ long pos = ftell (libfp);
+
+ free (obj_name);
+
+ D (" Module: %s\n", hdr.ar_name);
+
+ sprintf (&filspc[strlen (filspc)], "%s", hdr.ar_name);
+
+ /* Opened OK - create a new libraryfile object for it */
+ ret = add_rel_file (name, lbnh, hdr.ar_name, filspc, pos - hdr_size, libfp, hdr.ar_size, type);
+ ///* if cdb information required & .adb file present */
+ //if (yflag && yfp)
+ // {
+ // if (load_adb(FILE *libfp, struct lbfile *lbfh))
+ // SaveLinkedFilePath (filspc);
+ // }
+ if (ret)
+ break;
+
+ fseek (libfp, pos + hdr.ar_size + (hdr.ar_size & 1), SEEK_SET);
+ }
+ }
+
+ if (NULL != str_tab)
+ {
+ free (str_tab);
+ str_tab = NULL;
+ str_tab_size = 0;
+ }
+
+ return ret;
+}
+#endif
+
+static void
+loadfile_ar (struct lbfile *lbfh)
+{
+ FILE *fp;
+
+#ifdef __CYGWIN__
+ char posix_path[PATH_MAX];
+ void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
+ cygwin_conv_to_full_posix_path (lbfh->libspc, posix_path);
+ fp = fopen (posix_path, "rb");
+#else
+ fp = fopen (lbfh->libspc, "rb");
+#endif
+
+ if (fp != NULL)
+ {
+ struct ar_hdr hdr;
+
+ fseek (fp, lbfh->offset, SEEK_SET);
+ if (ar_get_header (&hdr, fp, NULL) != 0)
+ {
+ D ("Loading module %s from file %s.\n", hdr.ar_name, lbfh->libspc);
+ load_rel (fp, hdr.ar_size);
+ fclose (fp);
+ }
+ else
+ {
+ fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
+ fclose (fp);
+ lkexit (1);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
+ lkexit (1);
+ }
+}
+
+struct aslib_target aslib_target_ar = {
+ &is_ar,
+#ifdef INDEXLIB
+ &buildlibraryindex_ar,
+#else
+ &fndsym_ar,
+#endif
+ &loadfile_ar,
+};
--- /dev/null
+/* lkar.h - ar library format handling
+
+ Copyright (C) 2008-2012 Borut Razem, borut dot razem at siol dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __LKAR_H
+#define __LKAR_H
+
+#include <sys/types.h>
+#include <string.h>
+
+
+#ifdef _WIN32
+typedef unsigned short mode_t;
+typedef short uid_t;
+typedef short gid_t;
+typedef _off_t off_t;
+#endif
+
+#define sgetl(buf) (((((((unsigned char)(buf)[0] << 8) + (unsigned char)(buf)[1]) << 8) + (unsigned char)(buf)[2]) << 8) + (unsigned char)(buf)[3])
+#define sputl(value, buf) ((buf)[0] = (value) >> 24, (buf)[1] = (value) >> 16, (buf)[2] = (value) >> 8, (buf)[3] = (value))
+
+/* Note that the usual '\n' in magic strings may translate to different
+ characters, as allowed by ANSI. '\012' has a fixed value, and remains
+ compatible with existing BSDish archives. */
+
+#define ARMAG "!<arch>\012" /* magic string */
+#define SARMAG (sizeof (ARMAG) - 1) /* length of magic string */
+
+#define ARFMAG "`\012" /* header trailer string */
+
+#define AR_NAME_OFFSET 0
+#define AR_NAME_LEN 16
+
+#define AR_DATE_OFFSET 16
+#define AR_DATE_LEN 12
+
+#define AR_UID_OFFSET 28
+#define AR_UID_LEN 6
+
+#define AR_GID_OFFSET 34
+#define AR_GID_LEN 6
+
+#define AR_MODE_OFFSET 40
+#define AR_MODE_LEN 8
+
+#define AR_SIZE_OFFSET 48
+#define AR_SIZE_LEN 10
+
+#define AR_FMAG_OFFSET 58
+#define AR_FMAG_LEN (sizeof (ARFMAG) - 1)
+
+#define ARHDR_LEN (AR_NAME_LEN + AR_DATE_LEN + AR_UID_LEN + AR_GID_LEN + AR_MODE_LEN + AR_SIZE_LEN + AR_FMAG_LEN)
+
+#define AR_SYMBOL_TABLE_NAME "/ "
+#define AR_STRING_TABLE_NAME "// "
+
+#define AR_BSD_SYMBOL_TABLE_NAME "__.SYMDEF "
+#define AR_BSD_SORTED_SYMBOL_TABLE_NAME "__.SYMDEF SORTED"
+
+#define AR_IS_SYMBOL_TABLE(name) (0 == strcmp((name), AR_SYMBOL_TABLE_NAME))
+#define AR_IS_STRING_TABLE(name) (0 == strcmp((name), AR_STRING_TABLE_NAME))
+
+#define AR_IS_BSD_SYMBOL_TABLE(name) (0 == strcmp((name), AR_BSD_SYMBOL_TABLE_NAME) || 0 == strcmp((name), AR_BSD_SORTED_SYMBOL_TABLE_NAME))
+
+
+struct ar_hdr /* archive member header */
+{
+ char ar_name[AR_NAME_LEN + 1]; /* archive member name */
+ time_t ar_date; /* archive member date */
+ uid_t ar_uid; /* archive member user identification */
+ gid_t ar_gid; /* archive member group identification */
+ mode_t ar_mode; /* archive member mode (octal) */
+ size_t ar_size; /* archive member size */
+};
+
+#endif /* __LKAR_H */
--- /dev/null
+/* lkarea.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+/*
+ * 02-Apr-98 JLH: add code to link 8051 data spaces
+ */
+
+#include "aslink.h"
+
+/*)Module lkarea.c
+ *
+ * The module lkarea.c contains the functions which
+ * create and link together all area definitions read
+ * from the .rel file(s).
+ *
+ * lkarea.c contains the following functions:
+ * VOID lnkarea()
+ * VOID lnksect()
+ * VOID lkparea()
+ * VOID newarea()
+ * VOID setarea()
+ *
+ * lkarea.c contains no global variables.
+ */
+
+/*)Function VOID newarea()
+ *
+ * The function newarea() creates and/or modifies area
+ * and areax structures for each A directive read from
+ * the .rel file(s). The function lkparea() is called
+ * to find the area structure associated with this name.
+ * If the area does not yet exist then a new area
+ * structure is created and linked to any existing
+ * linked area structures. The area flags are copied
+ * into the area flag variable. For each occurence of
+ * an A directive an areax structure is created and
+ * linked to the areax structures associated with this
+ * area. The size of this area section is placed into
+ * the areax structure. The flag value for all subsequent
+ * area definitions for the same area are compared and
+ * flagged as an error if they are not identical.
+ * The areax structure created for every occurence of
+ * an A directive is loaded with a pointer to the base
+ * area structure and a pointer to the associated
+ * head structure. And finally, a pointer to this
+ * areax structure is loaded into the list of areax
+ * structures in the head structure. Refer to lkdata.c
+ * for details of the structures and their linkage.
+ *
+ * local variables:
+ * areax **halp pointer to an array of pointers
+ * a_uint i value
+ * char id[] id string
+ * int k counter, loop variable
+ * int narea number of areas in this head structure
+ * areax * taxp pointer to an areax structure
+ * to areax structures
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * areax *axp Pointer to the current
+ * areax structure
+ * head *hp Pointer to the current
+ * head structure
+ * int lkerr error flag
+ *
+ * functions called:
+ * a_uint eval() lkeval.c
+ * VOID exit() c_library
+ * int fprintf() c_library
+ * VOID getid() lklex.c
+ * VOID lkparea() lkarea.c
+ * VOID skip() lklex.c
+ *
+ * side effects:
+ * The area and areax structures are created and
+ * linked with the appropriate head structures.
+ * Failure to allocate area or areax structure
+ * space will terminate the linker. Other internal
+ * errors most likely caused by corrupted .rel
+ * files will also terminate the linker.
+ */
+
+/*
+ * Create an area entry.
+ *
+ * A xxxxxx size nnnn flags mm bank n
+ * | | | |
+ * | | | `-- ap->a_bank
+ * | | `---------- ap->a_flag
+ * | `--------------------- axp->a_size
+ * `--------------------------------- ap->a_id
+ *
+ */
+VOID
+newarea(void)
+{
+ a_uint i;
+ int k, narea;
+ struct areax *taxp;
+ struct areax **halp;
+ char id[NCPS];
+
+ if (headp == NULL) {
+ fprintf(stderr, "No header defined\n");
+ lkexit(ER_FATAL);
+ }
+ /*
+ * Create Area entry
+ */
+ getid(id, -1);
+ lkparea(id);
+ /*
+ * Evaluate area size
+ */
+ skip(-1);
+ axp->a_size = eval();
+ /*
+ * Evaluate flags
+ */
+ skip(-1);
+ i = 0;
+ taxp = ap->a_axp;
+ while (taxp->a_axp) {
+ ++i;
+ taxp = taxp->a_axp;
+ }
+ if (i == 0) {
+ ap->a_flag = eval();
+ } else {
+ i = eval();
+ if ((!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) &&
+ i && (ap->a_flag != i)) {
+ fprintf(stderr, "Conflicting flags in area %8s\n", id);
+ lkerr++;
+ }
+ }
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) {
+ /*
+ * Evaluate area address
+ */
+ skip(-1);
+ axp->a_addr = eval();
+ }
+ /*
+ * Place pointer in header area list
+ */
+ narea = hp->h_narea;
+ halp = hp->a_list;
+ for (k=0; k < narea ;++k) {
+ if (halp[k] == NULL) {
+ halp[k] = taxp;
+ return;
+ }
+ }
+ fprintf(stderr, "Header area list overflow\n");
+ lkexit(ER_FATAL);
+}
+
+/*)Function VOID lkparea(id)
+ *
+ * char * id pointer to the area name string
+ *
+ * The function lkparea() searches the linked area structures
+ * for a name match. If the name is not found then an area
+ * structure is created. An areax structure is created and
+ * appended to the areax structures linked to the area structure.
+ * The associated base area and head structure pointers are
+ * loaded into the areax structure.
+ *
+ * local variables:
+ * area * tap pointer to an area structure
+ * areax * taxp pointer to an areax structure
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * areax *axp Pointer to the current
+ * areax structure
+ *
+ * functions called:
+ * VOID * new() lksym()
+ * char * strsto() lksym.c
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * Area and/or areax structures are created.
+ * Failure to allocate space for created structures
+ * will terminate the linker.
+ */
+
+VOID
+lkparea(char *id)
+{
+ struct area *tap;
+ struct areax *taxp;
+
+ ap = areap;
+ axp = (struct areax *) new (sizeof(struct areax));
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB))
+ axp->a_addr = -1; /* default: no address yet */
+ while (ap) {
+ if (symeq(id, ap->a_id, 1)) {
+ taxp = ap->a_axp;
+ while (taxp->a_axp)
+ taxp = taxp->a_axp;
+ taxp->a_axp = axp;
+ axp->a_bap = ap;
+ axp->a_bhp = hp;
+ return;
+ }
+ ap = ap->a_ap;
+ }
+ ap = (struct area *) new (sizeof(struct area));
+ if (areap == NULL) {
+ areap = ap;
+ } else {
+ tap = areap;
+ while (tap->a_ap)
+ tap = tap->a_ap;
+ tap->a_ap = ap;
+ }
+ ap->a_axp = axp;
+ axp->a_bap = ap;
+ axp->a_bhp = hp;
+ ap->a_id = strsto(id);
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB))
+ ap->a_addr = 0;
+}
+
+/*)Function VOID lnkarea()
+ *
+ * The function lnkarea() resolves all area addresses.
+ * The function evaluates each area structure (and all
+ * the associated areax structures) in sequence. The
+ * linking process supports four (4) possible area types:
+ *
+ * ABS/OVR - All sections (each individual areax
+ * section) starts at the identical base
+ * area address overlaying all other
+ * areax sections for this area. The
+ * size of the area is largest of the area
+ * sections.
+ *
+ * ABS/CON - All sections (each individual areax
+ * section) are concatenated with the
+ * first section starting at the base
+ * area address. The size of the area
+ * is the sum of the section sizes.
+ *
+ * NOTE: Multiple absolute (ABS) areas are
+ * never concatenated with each other,
+ * thus absolute area A and absolute area
+ * B will overlay each other if they begin
+ * at the same location (the default is
+ * always address 0 for absolute areas).
+ *
+ * REL/OVR - All sections (each individual areax
+ * section) starts at the identical base
+ * area address overlaying all other
+ * areax sections for this area. The
+ * size of the area is largest of the area
+ * sections.
+ *
+ * REL/CON - All sections (each individual areax
+ * section) are concatenated with the
+ * first section starting at the base
+ * area address. The size of the area
+ * is the sum of the section sizes.
+ *
+ * NOTE: Relocatable (REL) areas are always concatenated
+ * with each other, thus relocatable area B
+ * (defined after area A) will follow
+ * relocatable area A independent of the
+ * starting address of area A. Within a
+ * specific area each areax section may be
+ * overlayed or concatenated with other
+ * areax sections.
+ *
+ *
+ * If a base address for an area is specified then the
+ * area will start at that address. Any relocatable
+ * areas defined subsequently will be concatenated to the
+ * previous relocatable area if it does not have a base
+ * address specified.
+ *
+ * The names s_<areaname> and l_<areaname> are created to
+ * define the starting address and length of each area.
+ *
+ * local variables:
+ * a_uint rloc ;current relocation address
+ * char temp[] ;temporary string
+ * struct symbol *sp ;symbol structure
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID lnksect() lkarea.c
+ * symbol *lkpsym() lksysm.c
+ * char * strncpy() c_library
+ * int symeq() lksysm.c
+ *
+ * side effects:
+ * All area and areax addresses and sizes are
+ * determined and saved in their respective
+ * structures.
+ */
+
+/* sdld6808 specific */
+unsigned long codemap6808[2048];
+/* end sdld6808 specific */
+/* sdld specific */
+VOID lnksect(struct area *tap);
+/* end sdld specific */
+/*
+ * Resolve all bank/area addresses.
+ */
+VOID
+lnkarea(void)
+{
+ /* sdld specific */
+ a_uint rloc[4] = { 0, 0, 0, 0 };
+ int locIndex;
+ /* end sdld specific */
+ /* sdld8051 & sdld6808 specific */
+ /*JCF: used to save the REG_BANK_[0-3] and SBIT_BYTES area pointers*/
+ struct area *ta[5];
+ int j;
+ /* end sdld8051 & sdld6808 specific */
+ /* sdld6800 specific */
+ a_uint gs_size = 0;
+ struct area *abs_ap = NULL;
+ struct area *gs0_ap = NULL;
+ /* end sdld6800 specific */
+ char temp[NCPS+2];
+ struct sym *sp;
+
+ if (TARGET_IS_6808) {
+ memset(codemap6808, 0, sizeof(codemap6808));
+
+ /* first sort all absolute areas to the front */
+ ap = areap;
+ /* no need to check first area, it's in front anyway */
+ while (ap && ap->a_ap) {
+ if (ap->a_ap->a_flag & A3_ABS)
+ {/* next area is absolute, move it to front,
+ reversed sequence is no problem for absolutes */
+ abs_ap = ap->a_ap;
+ ap->a_ap = abs_ap->a_ap;
+ abs_ap->a_ap = areap;
+ areap = abs_ap;
+ }
+ else {
+ ap = ap->a_ap;
+ }
+ }
+
+ /* next accumulate all GSINITx/GSFINAL area sizes
+ into GSINIT so they stay together */
+ ap = areap;
+ while (ap) {
+ if (!strncmp(ap->a_id, "GS", 2))
+ {/* GSxxxxx area */
+ if (ap->a_size == 0)
+ {
+ axp = ap->a_axp;
+ while (axp)
+ {
+ ap->a_size += axp->a_size;
+ axp = axp->a_axp;
+ }
+ }
+ gs_size += ap->a_size;
+ if (!strcmp(ap->a_id, "GSINIT0"))
+ {/* GSINIT0 area */
+ gs0_ap = ap;
+ }
+ }
+ ap = ap->a_ap;
+ }
+ if (gs0_ap)
+ gs0_ap->a_size = gs_size;
+ }
+
+ ap = areap;
+ while (ap) {
+ if (ap->a_flag & A3_ABS) {
+ /*
+ * Absolute sections
+ */
+ lnksect(ap);
+ } else {
+ /* sdld specific */
+ /* Determine memory space */
+ locIndex = 0;
+ if ((TARGET_IS_8051)) {
+ if (ap->a_flag & A_CODE) {
+ locIndex = 1;
+ }
+ if (ap->a_flag & A_XDATA) {
+ locIndex = 2;
+ }
+ if (ap->a_flag & A_BIT) {
+ locIndex = 3;
+ }
+ }
+ /*
+ * Relocatable sections
+ */
+ if (!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB) {
+ if (ap->a_addr == 0)
+ ap->a_addr = rloc[locIndex];
+ }
+ else if (ap->a_bset == 0) {
+ if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD) {
+ locIndex = 2;
+ ap->a_addr = 0;
+ }
+ else {
+ ap->a_addr = rloc[locIndex];
+ }
+ ap->a_bset = 1;
+ }
+ lnksect(ap);
+ rloc[ locIndex ] = ap->a_addr + ap->a_size;
+ /* end sdld specific */
+ }
+
+ /*
+ * Create symbols called:
+ * s_<areaname> the start address of the area
+ * l_<areaname> the length of the area
+ */
+
+ if (! symeq(ap->a_id, _abs_, 1)) {
+ strcpy(temp+2, ap->a_id);
+ *(temp+1) = '_';
+
+ *temp = 's';
+ sp = lkpsym(temp, 1);
+ sp->s_addr = ap->a_addr;
+ if (!is_sdld() || TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)
+ sp->s_axp = NULL;
+ sp->s_type |= S_DEF;
+
+ *temp = 'l';
+ sp = lkpsym(temp, 1);
+ sp->s_addr = ap->a_size;
+ sp->s_axp = NULL;
+ sp->s_type |= S_DEF;
+ }
+
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_Z180 || TARGET_IS_GB)) {
+ /*JCF: Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG
+ to compute the byte size of BSEG_BYTES: */
+ if (!strcmp(ap->a_id, "BSEG")) {
+ if (TARGET_IS_8051)
+ ap->a_ap->a_axp->a_size += ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
+ else
+ ap->a_ap->a_axp->a_size=(ap->a_addr/8)+((ap->a_size+7)/8); /*Bits to bytes*/
+ }
+ else if (!strcmp(ap->a_id, "REG_BANK_0")) ta[0]=ap;
+ else if (!strcmp(ap->a_id, "REG_BANK_1")) ta[1]=ap;
+ else if (!strcmp(ap->a_id, "REG_BANK_2")) ta[2]=ap;
+ else if (!strcmp(ap->a_id, "REG_BANK_3")) ta[3]=ap;
+ else if (!strcmp(ap->a_id, "BSEG_BYTES"))
+ {
+ ta[4]=ap;
+ for(j=4; j>1; j--)
+ {
+ /*If upper register banks are not used roll back the relocation counter*/
+ if ( (ta[j]->a_size==0) && (ta[j-1]->a_size==0) )
+ {
+ rloc[0]-=8;
+ }
+ else break;
+ }
+ }
+ }
+ ap = ap->a_ap;
+ }
+}
+
+/* sdld specific */
+static
+a_uint find_empty_space(a_uint start, a_uint size, char *id, unsigned long *map, unsigned int map_size)
+{
+ a_uint i, j, k;
+ unsigned long mask, b;
+ map_size /= sizeof(*map); /* Convert from bytes to number of elements */
+
+ while (1) {
+ a_uint a = start;
+ i = start >> 5;
+ j = (start + size) >> 5;
+ mask = -(1 << (start & 0x1F));
+
+ if (j > map_size) {
+ fprintf(stderr, "internal memory limit is exceeded for %s; memory size = 0x%06X, address = 0x%06X\n", id, map_size << 5, start + size - 1);
+ break;
+ }
+ else {
+ while (i < j) {
+ if (map[i] & mask) {
+ k = 32;
+ for (b=0x80000000; b!=0; b>>=1, k--) {
+ if (map[i] & b)
+ break;
+ }
+ start = a + k;
+ break;
+ }
+ i++;
+ mask = 0xFFFFFFFF;
+ a += 32;
+ }
+ if (start > a)
+ continue;
+
+ mask &= (1 << ((start + size) & 0x1F)) - 1;
+ if (i < map_size && map[i] & mask) {
+ k = 32;
+ for (b=0x80000000; b!=0; b>>=1, k--) {
+ if (map[i] & b)
+ break;
+ }
+ start = (a & ~0x1F) + k;
+ }
+ if (start <= a)
+ break;
+ }
+ }
+ return start;
+}
+
+static
+a_uint allocate_space(a_uint start, a_uint size, char *id, unsigned long *map, unsigned int map_size)
+{
+ a_uint i, j;
+ unsigned long mask;
+ a_uint a = start;
+ i = start >> 5;
+ j = (start + size) >> 5;
+ mask = -(1 << (start & 0x1F));
+ map_size /= sizeof(*map); /* Convert from bytes to number of elements */
+
+ if (j > map_size) {
+ fprintf(stderr, "internal memory limit is exceeded for %s; memory size = 0x%06X, address = 0x%06X\n", id, map_size << 5, start + size - 1);
+ }
+ else {
+ while (i < j) {
+ if (map[i] & mask) {
+ fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
+ }
+ map[i++] |= mask;
+ mask = 0xFFFFFFFF;
+ a += 32;
+ }
+ mask &= (1 << ((start + size) & 0x1F)) - 1;
+ if (i < map_size && map[i] & mask) {
+ fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
+ }
+ map[i] |= mask;
+ }
+ return start;
+}
+/* end sdld specific */
+
+/*)Function VOID lnksect(tap)
+ *
+ * area * tap pointer to an area structure
+ *
+ * The function lnksect() is the function called by
+ * lnkarea() to resolve the areax addresses. Refer
+ * to the function lnkarea() for more detail. Pageing
+ * boundary and length errors will be reported by this
+ * function.
+ *
+ * local variables:
+ * a_uint size size of area
+ * a_uint addr address of area
+ * areax * taxp pointer to an areax structure
+ *
+ * global variables:
+ * int lkerr error flag
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * All area and areax addresses and sizes are determined
+ * and linked into the structures.
+ */
+
+VOID
+lnksect(struct area *tap)
+{
+ a_uint size, addr;
+ struct areax *taxp;
+
+ size = 0;
+ addr = tap->a_addr;
+ taxp = tap->a_axp;
+ if (tap->a_flag & A3_OVR) {
+ /*
+ * Overlayed sections
+ */
+ while (taxp) {
+ taxp->a_addr = addr;
+ if (taxp->a_size > size)
+ size = taxp->a_size;
+ taxp = taxp->a_axp;
+ }
+ } else if (TARGET_IS_6808 && tap->a_flag & A3_ABS) {
+ /*
+ * Absolute sections
+ */
+ while (taxp) {
+ allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+ taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
+ size += taxp->a_size;
+ taxp = taxp->a_axp;
+ }
+ } else {
+ /*
+ * Concatenated sections
+ */
+ if (TARGET_IS_6808 && tap->a_size && !(ap->a_flag & A_NOLOAD)) {
+ addr = find_empty_space(addr, tap->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+ }
+ while (taxp) {
+ /* find next unused address now */
+ if (TARGET_IS_6808 && taxp->a_size && !(ap->a_flag & A_NOLOAD)) {
+ addr = find_empty_space(addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+ allocate_space(addr, taxp->a_size, tap->a_id, codemap6808, sizeof (codemap6808));
+ }
+ taxp->a_addr = addr;
+ addr += taxp->a_size;
+ size += taxp->a_size;
+ taxp = taxp->a_axp;
+ }
+ }
+ tap->a_size = size;
+ tap->a_addr = tap->a_axp->a_addr;
+ for (taxp = tap->a_axp; taxp && !taxp->a_size; taxp = taxp->a_axp)
+ {
+ }
+ if (taxp)
+ {
+ tap->a_addr = taxp->a_addr;
+ }
+
+ if ((tap->a_flag & A3_PAG) && (size > 256)) {
+ fprintf(stderr,
+ "\n?ASlink-Warning-Paged Area %s Length Error\n",
+ tap->a_id);
+ lkerr++;
+ }
+ if (TARGET_IS_8051 &&
+ (tap->a_flag & A3_PAG) && (tap->a_size) &&
+ ((tap->a_addr & 0xFFFFFF00) != ((addr-1) & 0xFFFFFF00)))
+ {
+ fprintf(stderr,
+ "\n?ASlink-Warning-Paged Area %s Boundary Error\n",
+ tap->a_id);
+ lkerr++;
+ }
+}
+
+
+/*)Function VOID setarea()
+ *
+ * The function setarea() scans the base address lines in the
+ * basep structure, evaluates the arguments, and sets the beginning
+ * address of the specified areas.
+ *
+ * local variables:
+ * a_uint v expression value
+ * char id[] base id string
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * base *basep The pointer to the first
+ * base structure
+ * base *bsp Pointer to the current
+ * base structure
+ * char *ip pointer into the REL file
+ * text line in ib[]
+ * int lkerr error flag
+ *
+ * functions called:
+ * a_uint expr() lkeval.c
+ * int fprintf() c_library
+ * VOID getid() lklex.c
+ * int getnb() lklex.c
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * The base address of an area is set.
+ */
+
+VOID
+setarea(void)
+{
+ a_uint v;
+ char id[NCPS];
+
+ bsp = basep;
+ while (bsp) {
+ ip = bsp->b_strp;
+ getid(id, -1);
+ if (getnb() == '=') {
+ v = expr(0);
+ for (ap = areap; ap != NULL; ap = ap->a_ap) {
+ if (symeq(id, ap->a_id, 1))
+ break;
+ }
+ if (ap == NULL) {
+ fprintf(stderr,
+ "ASlink-Warning-No definition of area %s\n", id);
+ lkerr++;
+ } else {
+ ap->a_addr = v;
+ ap->a_bset = 1;
+ }
+ } else {
+ fprintf(stderr, "ASlink-Warning-No '=' in base expression");
+ lkerr++;
+ }
+ bsp = bsp->b_base;
+ }
+}
+
+
+
+/* sdld specific */
+a_uint lnksect2 (struct area *tap, int locIndex);
+unsigned long codemap8051[524288];
+unsigned long xdatamap[131216];
+struct area *dseg_ap = NULL;
+a_uint dram_start = 0;
+a_uint iram_start = 0;
+
+/*Modified version of the functions for packing variables in internal data memory*/
+VOID lnkarea2 (void)
+{
+ a_uint rloc[4]={0, 0, 0, 0};
+ a_uint gs_size = 0;
+ int locIndex;
+ char temp[NCPS+2];
+ struct sym *sp;
+ int j;
+ struct area *bseg_ap = NULL;
+ struct area *abs_ap = NULL;
+ struct area *gs0_ap = NULL;
+ struct sym *sp_dseg_s=NULL, *sp_dseg_l=NULL;
+
+ memset(idatamap, ' ', 256);
+ memset(codemap8051, 0, sizeof(codemap8051));
+ memset(xdatamap, 0, sizeof(xdatamap));
+
+ /* first sort all absolute areas to the front */
+ ap = areap;
+ /* no need to check first area, it's in front anyway */
+ while (ap && ap->a_ap)
+ {
+ if (ap->a_ap->a_flag & A3_ABS)
+ {/* next area is absolute, move it to front,
+ reversed sequence is no problem for absolutes */
+ abs_ap = ap->a_ap;
+ ap->a_ap = abs_ap->a_ap;
+ abs_ap->a_ap = areap;
+ areap = abs_ap;
+ }
+ else
+ {
+ ap = ap->a_ap;
+ }
+ }
+
+ /* next accumulate all GSINITx/GSFINAL area sizes
+ into GSINIT so they stay together */
+ ap = areap;
+ abs_ap = areap;
+ while (ap)
+ {
+ if (ap->a_flag & A3_ABS)
+ {
+ abs_ap = ap; /* Remember the last abs area */
+ }
+ if (!strncmp(ap->a_id, "GS", 2))
+ {/* GSxxxxx area */
+ if (ap->a_size == 0)
+ {
+ axp = ap->a_axp;
+ while (axp)
+ {
+ ap->a_size += axp->a_size;
+ axp = axp->a_axp;
+ }
+ }
+ gs_size += ap->a_size;
+ if (!strcmp(ap->a_id, "GSINIT0"))
+ {/* GSINIT0 area */
+ gs0_ap = ap;
+ }
+ }
+ /*Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG
+ to compute the byte size of BSEG_BYTES: */
+ else if (!strcmp(ap->a_id, "BSEG"))
+ {
+ bseg_ap = ap->a_ap; //BSEG_BYTES
+ for (axp=ap->a_axp; axp; axp=axp->a_axp)
+ ap->a_size += axp->a_size;
+ bseg_ap->a_axp->a_size = ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
+ ap->a_ap = bseg_ap->a_ap; //removed BSEG_BYTES from list
+ bseg_ap->a_ap = abs_ap->a_ap;
+ abs_ap->a_ap = bseg_ap; //inserted BSEG_BYTES after abs
+ bseg_ap = ap; //BSEG
+ }
+ else if (!strcmp(ap->a_id, "DSEG"))
+ {
+ dseg_ap = ap; /*Need it later*/
+ dram_start = ap->a_addr;
+ }
+ else if (!strcmp(ap->a_id, "ISEG"))
+ {
+ iram_start = ap->a_addr;
+ }
+ ap = ap->a_ap;
+ }
+ if (gs0_ap)
+ gs0_ap->a_size = gs_size;
+
+ ap = areap;
+ while (ap)
+ {
+ /* Determine memory space */
+ if (ap->a_flag & A_CODE) locIndex = 1;
+ else if (ap->a_flag & A_XDATA) locIndex = 2;
+ else if (ap->a_flag & A_BIT) locIndex = 3;
+ else locIndex = 0;
+
+ if (ap->a_flag & A3_ABS) /* Absolute sections */
+ {
+ lnksect2(ap, locIndex);
+ }
+ else /* Relocatable sections */
+ {
+ if (ap->a_bset == 0)
+ {
+ ap->a_addr = rloc[locIndex];
+ ap->a_bset = 1;
+ }
+
+ rloc[locIndex] = lnksect2(ap, locIndex);
+ }
+
+ if (!strcmp(ap->a_id, "BSEG_BYTES") && (ap->a_axp->a_addr >= 0x20))
+ {
+ bseg_ap->a_addr += (ap->a_axp->a_addr - 0x20) * 8; /*Bytes to bits*/
+ }
+ /*
+ * Create symbols called:
+ * s_<areaname> the start address of the area
+ * l_<areaname> the length of the area
+ */
+
+ if (! symeq(ap->a_id, _abs_, 1))
+ {
+ strcpy(temp+2,ap->a_id);
+ *(temp+1) = '_';
+
+ *temp = 's';
+ sp = lkpsym(temp, 1);
+ sp->s_addr = ap->a_addr;
+ sp->s_type |= S_DEF;
+ if (!strcmp(ap->a_id, "DSEG")) sp_dseg_s=sp;
+
+ *temp = 'l';
+ sp = lkpsym(temp, 1);
+ sp->s_addr = ap->a_size;
+ sp->s_axp = NULL;
+ sp->s_type |= S_DEF;
+ if (!strcmp(ap->a_id, "DSEG")) sp_dseg_l=sp;
+ }
+
+ ap = ap->a_ap;
+ }
+
+ /*Compute the size of DSEG*/
+ if(dseg_ap!=NULL)
+ {
+ dseg_ap->a_addr=0;
+ dseg_ap->a_size=0;
+ for(j=0; j<0x80; j++) if(idatamap[j]!=' ') dseg_ap->a_size++;
+ }
+ if(sp_dseg_s!=NULL) sp_dseg_s->s_addr=0;
+ if(sp_dseg_l!=NULL) sp_dseg_l->s_addr=dseg_ap->a_size;
+}
+
+a_uint lnksect2 (struct area *tap, int locIndex)
+{
+ a_uint size, addr;
+ struct areax *taxp;
+ int j, k, ramlimit, ramstart;
+ char fchar=' ', dchar='a';
+ char ErrMsg[]="?ASlink-Error-Could not get %d consecutive byte%s"
+ " in internal RAM for area %s.\n";
+
+ tap->a_unaloc=0;
+
+ /*Notice that only ISEG and SSEG can be in the indirectly addressable internal RAM*/
+ if( (!strcmp(tap->a_id, "ISEG")) || (!strcmp(tap->a_id, "SSEG")) )
+ {
+ ramstart = iram_start;
+
+ if ((iram_size <= 0) || (ramstart + iram_size > 0x100))
+ ramlimit = 0x100;
+ else
+ ramlimit = ramstart + iram_size;
+ }
+ else
+ {
+ ramstart = dram_start;
+
+ if ((iram_size <= 0) || (ramstart + iram_size > 0x80))
+ ramlimit = 0x80;
+ else
+ ramlimit = ramstart + iram_size;
+ }
+
+ size = 0;
+ addr = tap->a_addr;
+ taxp = tap->a_axp;
+
+ /*Use a letter to identify each area in the internal RAM layout map*/
+ if (locIndex==0)
+ {
+ /**/ if(!strcmp(tap->a_id, "DSEG"))
+ fchar='D'; /*It will be converted to letters 'a' to 'z' later for each areax*/
+ else if(!strcmp(tap->a_id, "ISEG"))
+ fchar='I';
+ else if(!strcmp(tap->a_id, "SSEG"))
+ fchar='S';
+ else if(!strcmp(tap->a_id, "OSEG"))
+ fchar='Q';
+ else if(!strcmp(tap->a_id, "REG_BANK_0"))
+ fchar='0';
+ else if(!strcmp(tap->a_id, "REG_BANK_1"))
+ fchar='1';
+ else if(!strcmp(tap->a_id, "REG_BANK_2"))
+ fchar='2';
+ else if(!strcmp(tap->a_id, "REG_BANK_3"))
+ fchar='3';
+ else if(!strcmp(tap->a_id, "BSEG_BYTES"))
+ fchar='B';
+ else if(!strcmp(tap->a_id, "BIT_BANK"))
+ fchar='T';
+ else
+ fchar=' ';/*???*/
+ }
+ else if (locIndex == 1)
+ {
+ /**/ if(!strcmp(tap->a_id, "GSINIT"))
+ fchar='G';
+ }
+ else if (locIndex == 2)
+ {
+ /**/ if(!strcmp(tap->a_id, "XSTK"))
+ fchar='K';
+ }
+
+ if (tap->a_flag & A3_OVR) /* Overlayed sections */
+ {
+ while (taxp)
+ {
+ if(taxp->a_size == 0)
+ {
+ taxp = taxp->a_axp;
+ continue;
+ }
+
+ if ( (fchar=='0')||(fchar=='1')||(fchar=='2')||(fchar=='3') ) /*Reg banks*/
+ {
+ addr=(fchar-'0')*8;
+ taxp->a_addr=addr;
+ size=taxp->a_size;
+ for(j=addr; (j<(int)(addr+size)) && (j<ramlimit); j++)
+ idatamap[j]=fchar;
+ }
+ else if( (fchar=='S') || (fchar=='Q') ) /*Overlay and stack in internal RAM*/
+ {
+ /*Find the size of the space currently used for this areax overlay*/
+ for(j=ramstart, size=0; j<ramlimit; j++)
+ if(idatamap[j]==fchar) size++;
+
+ if( (fchar=='S') && (stacksize==0) )
+ {
+ /*Search for the largest space available and use it for stack*/
+ for(j=ramstart, k=0, taxp->a_size=0; j<ramlimit; j++)
+ {
+ if(idatamap[j]==' ')
+ {
+ if((++k)>(int)taxp->a_size)
+ taxp->a_size=k;
+ }
+ else
+ {
+ k=0;
+ }
+ }
+ stacksize=taxp->a_size;
+ }
+
+ /*If more space required, release the previously allocated areax in
+ internal RAM and search for a bigger one*/
+ if((int)taxp->a_size>size)
+ {
+ size=(int)taxp->a_size;
+
+ for(j=ramstart; j<ramlimit; j++)
+ if(idatamap[j]==fchar) idatamap[j]=' ';
+
+ /*Search for a space large enough in data memory for this overlay areax*/
+ for(j=ramstart, k=0; j<ramlimit; j++)
+ {
+ if(idatamap[j]==' ')
+ k++;
+ else
+ k=0;
+ if(k==(int)taxp->a_size)
+ break;
+ }
+
+ /*Mark the memory used for overlay*/
+ if(k==(int)taxp->a_size)
+ {
+ addr = j-k+1;
+ for(j=addr; (j<(int)(addr+size)); j++)
+ idatamap[j]=fchar;
+ }
+ else /*Couldn't find a chunk big enough: report the problem.*/
+ {
+ tap->a_unaloc=taxp->a_size;
+ fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+ lkerr++;
+ }
+ }
+ }
+ else if (fchar=='T') /*Bit addressable bytes in internal RAM*/
+ {
+ /*Find the size of the space currently used for this areax overlay*/
+// for(j=0x20, size=0; j<0x30; j++)
+// if(idatamap[j]==fchar) size++;
+
+ /*If more space required, release the previously allocated areax in
+ internal RAM and search for a bigger one*/
+ if((int)taxp->a_size>size)
+ {
+ size=(int)taxp->a_size;
+
+ for(j=0x20; j<0x30; j++)
+ if(idatamap[j]==fchar) idatamap[j]=' ';
+
+ /*Search for a space large enough in data memory for this overlay areax*/
+ for(j=0x20, k=0; j<0x30; j++)
+ {
+ if(idatamap[j]==' ')
+ k++;
+ else
+ k=0;
+ if(k==(int)taxp->a_size)
+ break;
+ }
+
+ /*Mark the memory used for overlay*/
+ if(k==(int)size)
+ {
+ addr = j-k+1;
+ for(j=addr; (j<(int)(addr+size)); j++)
+ idatamap[j]=fchar;
+ }
+ else /*Couldn't find a chunk big enough: report the problem.*/
+ {
+ tap->a_unaloc=taxp->a_size;
+ fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+ lkerr++;
+ }
+ }
+ }
+ else /*Overlay areas not in internal ram*/
+ {
+ taxp->a_addr = addr;
+ if (taxp->a_size > size) size = taxp->a_size;
+ }
+ taxp = taxp->a_axp;
+ }
+ /*Now set all overlayed areax to the same start address*/
+ taxp = tap->a_axp;
+ while (taxp)
+ {
+ taxp->a_addr = addr;
+ taxp = taxp->a_axp;
+ }
+ }
+ else if (tap->a_flag & A3_ABS) /* Absolute sections */
+ {
+ while (taxp)
+ {
+ if (locIndex == 0)
+ {
+ for (j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<256); j++)
+ {
+ if (idatamap[j] == ' ')
+ idatamap[j] = 'A';
+ else
+ fprintf(stderr, "memory overlap at 0x%X for %s\n", j, tap->a_id);
+ }
+ }
+ else if (locIndex == 1)
+ {
+ allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+ }
+ else if (locIndex == 2)
+ {
+ allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+ }
+ taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
+ size += taxp->a_size;
+ taxp = taxp->a_axp;
+ }
+ }
+ else /* Concatenated sections */
+ {
+ if ((locIndex == 1) && tap->a_size)
+ {
+ addr = find_empty_space(addr, tap->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+ }
+ if ((locIndex == 2) && tap->a_size)
+ {
+ addr = find_empty_space(addr, tap->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+ }
+ while (taxp)
+ {
+ if (taxp->a_size)
+ {
+ if( (fchar=='D') || (fchar=='I') )
+ {
+ /*Search for a space large enough in internal RAM for this areax*/
+ for(j=ramstart, k=0; j<ramlimit; j++)
+ {
+ if(idatamap[j]==' ')
+ k++;
+ else
+ k=0;
+ if(k==(int)taxp->a_size)
+ break;
+ }
+
+ if(k==(int)taxp->a_size)
+ {
+ taxp->a_addr = j-k+1;
+
+ size += taxp->a_size;
+
+ for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<ramlimit); j++)
+ idatamap[j]=(fchar=='D')?dchar:fchar;
+ if((taxp->a_size>0)&&(fchar=='D'))dchar++;
+ if((dchar<'a')||(dchar>'z')) dchar='D'; /*Ran out of letters?*/
+ }
+ else /*We are in trouble, there is not enough memory for an areax chunk*/
+ {
+ taxp->a_addr = addr;
+ addr += taxp->a_size;
+ size += taxp->a_size;
+ tap->a_unaloc+=taxp->a_size;
+ fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+ lkerr++;
+ }
+ }
+ else if (fchar=='B')
+ {
+ /*Search for a space large enough in data memory for this areax*/
+ for(j=0x20, k=0; j<0x30; j++)
+ {
+ if(idatamap[j]==' ')
+ k++;
+ else
+ k=0;
+ if(k==(int)taxp->a_size) break;
+ }
+
+ /*Mark the memory used*/
+ if(k==(int)taxp->a_size)
+ {
+ taxp->a_addr = j-k+1;
+ for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<0x30); j++)
+ idatamap[j]=fchar;
+ }
+ else /*Couldn't find a chunk big enough: report the problem.*/
+ {
+ tap->a_unaloc=taxp->a_size;
+ fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+ lkerr++;
+ }
+ size += taxp->a_size;
+ }
+ else /*For concatenated BIT, CODE, and XRAM areax's*/
+ {
+ //expand external stack
+ if((fchar=='K') && (taxp->a_size == 1))
+ {
+ taxp->a_size = 256-(addr & 0xFF);
+ }
+ //find next unused address now
+ if (locIndex == 1)
+ {
+ addr = find_empty_space(addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+ allocate_space(addr, taxp->a_size, tap->a_id, codemap8051, sizeof (codemap8051));
+ }
+ if (locIndex == 2)
+ {
+ addr = find_empty_space(addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+ allocate_space(addr, taxp->a_size, tap->a_id, xdatamap, sizeof (xdatamap));
+ }
+ taxp->a_addr = addr;
+ addr += taxp->a_size;
+ size += taxp->a_size;
+ }
+ }
+ else
+ {
+ taxp->a_addr = addr;
+ }
+ taxp = taxp->a_axp;
+ }
+ }
+ tap->a_size = size;
+ tap->a_addr = tap->a_axp->a_addr;
+ for (taxp = tap->a_axp; taxp && !taxp->a_size; taxp = taxp->a_axp)
+ {
+ }
+ if (taxp)
+ {
+ tap->a_addr = taxp->a_addr;
+ }
+
+ if ((tap->a_flag & A3_PAG) && (size > 256))
+ {
+ fprintf(stderr,
+ "\n?ASlink-Warning-Paged Area %s Length Error\n",
+ tap->a_id);
+ lkerr++;
+ }
+ if ((tap->a_flag & A3_PAG) && (tap->a_size) &&
+ ((tap->a_addr & 0xFFFFFF00) != ((addr-1) & 0xFFFFFF00)))
+ {
+ fprintf(stderr,
+ "\n?ASlink-Warning-Paged Area %s Boundary Error\n",
+ tap->a_id);
+ lkerr++;
+ }
+ return addr;
+}
+/* end sdld specific */
+
--- /dev/null
+/* lkbank.c */
+
+/*
+ * Copyright (C) 2001-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+#include "aslink.h"
+
+/*Module lkbank.c
+ *
+ * The module lkbank.c contains the function newbank() which
+ * creates a bank structure and the function module() which
+ * loads the module name into the current head structure.
+ *
+ * lkbank.c contains the following functions:
+ * VOID newbank()
+ * VOID lkpbank()
+ * VOID setbank()
+ * VOID chkbank()
+ * VOID lkfopen()
+ * VOID lkfclose()
+ *
+ * lkbank.c contains no local variables.
+ */
+
+/*)Function VOID newbank()
+ *
+ * The function newbank() creates and/or modifies bank
+ * structures for each B directive read from
+ * the .rel file(s). The function lkpbank() is called
+ * to find the bank structure associated with this name.
+ * If the bank does not yet exist then a new bank
+ * structure is created and linked to any existing
+ * linked bank structures. The bank flags are copied
+ * into the bank flag variable. Refer to lkdata.c for
+ * details of the structures and their linkage.
+ *
+ * local variables:
+ * bank **hblp pointer to an array of pointers
+ * int i counter, loop variable, value
+ * char id[] id string
+ * int nbank number of banks in this head structure
+ * a_uint v temporary value
+ *
+ * global variables:
+ * bank *bp Pointer to the current
+ * bank structure
+ * head *hp Pointer to the current
+ * head structure
+ * int lkerr error flag
+ *
+ * functions called:
+ * a_uint eval() lkeval.c
+ * VOID exit() c_library
+ * int fprintf() c_library
+ * VOID getid() lklex.c
+ * VOID lkpbank() lkbank.c
+ * VOID skip() lklex.c
+ *
+ * side effects:
+ * The bank structure is created and
+ * linked with the appropriate head structures.
+ * Failure to allocate bank structure
+ * space will terminate the linker. Other internal
+ * errors most likely caused by corrupted .rel
+ * files will also terminate the linker.
+ */
+
+/*
+ * Create a bank entry.
+ *
+ * B xxxxxx base nnnn size nnnn map nnn flags n fsfx xxxxxx
+ * | | | | | |
+ * | | | | | `-- bp->b_fsfx
+ * | | | | `--------- bp->b_flag
+ * | | | `--------------------bp->b_map
+ * | | `---------------------------- bp->b_size
+ * | `-------------------------------------- bp->b_base
+ * `-------------------------------------------------- bp->b_id
+ *
+ */
+VOID
+newbank(void)
+{
+ int i;
+ a_uint v;
+ char id[NCPS];
+ int nbank;
+ struct bank **hblp;
+
+ if (headp == NULL) {
+ fprintf(stderr, "No header defined\n");
+ lkexit(ER_FATAL);
+ }
+ /*
+ * Create bank entry
+ */
+ getid(id, -1);
+ lkpbank(id);
+ /*
+ * Evaluate Parameters
+ */
+ while (more()) {
+ getid(id, -1);
+ /*
+ * Evaluate base address
+ */
+ if (symeq("base", id, 1)) {
+ v = eval();
+ if (bp->b_base == 0) {
+ bp->b_base = v;
+ } else {
+ if (v && (bp->b_base != v)) {
+ fprintf(stderr, "Conflicting address in bank %s\n", id);
+ lkerr++;
+ }
+ }
+ } else
+ /*
+ * Evaluate bank size
+ */
+ if (symeq("size", id, 1)) {
+ v = eval();
+ if (bp->b_size == 0) {
+ bp->b_size = v;
+ } else {
+ if (v && (bp->b_size != v)) {
+ fprintf(stderr, "Conflicting size in bank %s\n", id);
+ lkerr++;
+ }
+ }
+ } else
+ /*
+ * Evaluate bank mapping
+ */
+ if (symeq("map", id, 1)) {
+ v = eval();
+ if (bp->b_map == 0) {
+ bp->b_map = v;
+ } else {
+ if (v && (bp->b_map != v)) {
+ fprintf(stderr, "Conflicting mapping in bank %s\n", id);
+ lkerr++;
+ }
+ }
+ } else
+ /*
+ * Evaluate flags
+ */
+ if (symeq("flags", id, 1)) {
+ i = (int) eval();
+ if (bp->b_flag == 0) {
+ bp->b_flag = i;
+ } else {
+ if (i && (bp->b_flag != i)) {
+ fprintf(stderr, "Conflicting flags in bank %s\n", id);
+ lkerr++;
+ }
+ }
+ } else
+ /*
+ * File Suffix
+ */
+ if (symeq("fsfx", id, 1)) {
+ if (more()) {
+ getid(id, -1);
+ if (bp->b_fsfx == NULL) {
+ bp->b_fsfx = strsto(id);
+ } else {
+ if (!symeq(bp->b_fsfx, id, 1)) {
+ fprintf(stderr, "Conflicting fsfx in bank %s\n", id);
+ lkerr++;
+ }
+ }
+ }
+ }
+ }
+ /*
+ * Place pointer in header bank list
+ */
+ nbank = hp->h_nbank;
+ hblp = hp->b_list;
+ for (i=0; i < nbank; i++) {
+ if (hblp[i] == NULL) {
+ hblp[i] = bp;
+ return;
+ }
+ }
+ fprintf(stderr, "Header bank list overflow\n");
+ lkexit(ER_FATAL);
+}
+
+/*)Function VOID lkpbank(id)
+ *
+ * char * id pointer to the bank name string
+ *
+ * The function lkpbank() searches the linked bank structures
+ * for a name match. If the name is not found then a bank
+ * structure is created. The linker flag, rtaflg, for initializing
+ * i86 format output is set.
+ *
+ * local variables:
+ * area * tbp pointer to a bank structure
+ *
+ * global variables:
+ * bank *bp Pointer to the current
+ * bank structure
+ * bank *bankp The pointer to the first
+ * bank structure of a linked list
+ *
+ * functions called:
+ * VOID * new() lksym()
+ * char * strsto() lksym.c
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * Bank structure may be created.
+ * Failure to allocate space for a structure
+ * will terminate the linker.
+ */
+
+VOID
+lkpbank(char *id)
+{
+ struct bank *tbp;
+
+ bp = bankp;
+ while (bp) {
+ if (symeq(id, bp->b_id, 1)) {
+ return;
+ }
+ bp = bp->b_bp;
+ }
+ bp = (struct bank *) new (sizeof(struct bank));
+ tbp = bankp;
+ while (tbp->b_bp)
+ tbp = tbp->b_bp;
+ tbp->b_bp = bp;
+ bp->b_id = strsto(id);
+ bp->b_rtaflg = 1;
+}
+
+
+/*)Function VOID setbank()
+ *
+ * The function setbank() sets the base address of the bank by
+ * finding the first area in the bank and initializing the
+ * value to the bank base address. The bank base address is always
+ * specified in 'byte' addressing. A first area which is not 'byte'
+ * addressed (e.g. a processor addressed by a 'word' of 2 or more bytes)
+ * has the base address scaled to begin at the 'byte' address.
+ *
+ * If the area base address has been set using the -b linker
+ * option then the bank base address is NOT set.
+ *
+ * The function setbank() also scans all the areas searching
+ * for non-banked entries. All non-banked areas are linked
+ * to bank[0] which does not have a bank file suffix.
+ *
+ * local variables:
+ * a_uint base base address in 'bytes'
+ * int bytes size of PC increment in bytes
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * bank *bp Pointer to the current
+ * bank structure
+ * bank *bankp The pointer to the first
+ * bank structure of a linked list
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * Base starting address may be set and non-banked
+ * areas linked to bank[0].
+ */
+
+VOID
+setbank(void)
+{
+ a_uint base;
+ int bytes;
+
+ /*
+ * For each bank structure with a defined base address value
+ * scan the area structures for the first relocatable area
+ * in the bank and all absolute areas in the bank.
+ * Load the base address value into the area address if the
+ * bank base address has not been overridden by a -b option.
+ * The bank base address is always expressed in 'bytes'.
+ */
+ for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+ if ((bp->b_flag & B_BASE) == 0)
+ continue;
+ for (ap = areap; ap != NULL; ap = ap->a_ap) {
+ if (ap->a_bp != bp)
+ continue;
+ if ((ap->a_flag & A4_BNK) != A4_BNK)
+ continue;
+ if (ap->a_bset)
+ continue;
+ bytes = 1 + (ap->a_flag & A4_WLMSK);
+ base = bp->b_base;
+ ap->a_addr = (base/bytes) + ((base % bytes) ? 1 : 0);
+ ap->a_bset = 1;
+ if ((ap->a_flag & A4_ABS) == A4_ABS) {
+ continue;
+ } else {
+ break;
+ }
+ }
+ }
+
+ /*
+ * Scan all the area structures for non-banked
+ * areas. Set the area bank pointer to reference
+ * bank[0] which has no file suffix.
+ */
+ for (ap = areap; ap != NULL; ap = ap->a_ap) {
+ if ((ap->a_flag & A4_BNK) == 0) {
+ ap->a_bp = bankp;
+ }
+ }
+}
+
+
+/*)Function VOID chkbank(fp)
+ *
+ * FILE *fp file handle
+ *
+ * The function chkbank() scans the bank/area structures to
+ * determine the length of a bank. Banks exceeding the size
+ * specified from a bank size option are flagged. The bank
+ * size is always in 'byte' units.
+ *
+ * local variables:
+ * a_uint alow lowest address in a bank
+ * a_uint ahigh highest address in a bank
+ * a_uint blimit bank size limit
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * bank *bp Pointer to the current
+ * bank structure
+ * bank *bankp The pointer to the first
+ * bank structure of a linked list
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * Bank size may be flagged.
+ */
+
+VOID
+chkbank(FILE *fp)
+{
+ a_uint alow, ahigh, blimit, bytes;
+
+ for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+ if ((bp->b_flag & B_SIZE) == 0) {
+ continue;
+ }
+ blimit = bp->b_size;
+ if (blimit == 0) {
+ continue;
+ }
+ alow = ~0;
+ ahigh = 0;
+ for (ap = areap; ap != NULL; ap = ap->a_ap) {
+ if (ap->a_bp != bp) {
+ continue;
+ }
+ if ((ap->a_flag & A4_BNK) != A4_BNK) {
+ continue;
+ }
+ bytes = ap->a_addr * (1 + (ap->a_flag & A4_WLMSK));
+ if (bytes < alow) {
+ alow = bytes;
+ }
+ bytes = (ap->a_addr + ap->a_size) * (1 + (ap->a_flag & A4_WLMSK));
+ if (bytes > ahigh) {
+ ahigh = bytes;
+ }
+ }
+ if ((ahigh - alow) > blimit) {
+ fprintf(fp,
+ "\n?ASlink-Warning-Size limit exceeded in bank %s\n", bp->b_id);
+ lkerr++;
+ }
+ }
+}
+
+
+/*)Function VOID lkfopen()
+ *
+ * The function lkfopen() scans the bank/area structures to
+ * open output data files for banks with any data. Files
+ * are not opened for banks/areas with no output data.
+ *
+ * The bank structures are first scanned to create the
+ * file specification from the output file name combined
+ * with any given file suffixs.
+ *
+ * local variables:
+ * int idx position of FSEPX in file specification
+ * File * fp temporary file handle
+ * char * frmt temporary file type string
+ * char str[] File Specification String
+ * struct bank *tbp temporary bank pointer
+ *
+ *
+ * global variables:
+ * int a_bytes T line address bytes
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * char afspec[] Filespec from afile()
+ * bank *bp Pointer to the current
+ * bank structure
+ * bank *bankp The pointer to the first
+ * bank structure of a linked list
+ * FILE * jfp NoICE output file handle
+ * int oflag data output type flag
+ * FILE * stderr Standard Error Output handle
+ *
+ * functions called:
+ * FILE * afile() lkmain.c
+ * int fclose() c_library
+ * int fprintf() c_library
+ * VOID lkexit() lkmain.c
+ * char * strcpy() c_library
+ * char * strsto() lksym.c
+ * char * symeq() lksym.c
+ *
+ * side effects:
+ * All data output files are opened.
+ */
+
+VOID
+lkfopen(void)
+{
+ int idx;
+ char * frmt;
+ char str[NCPS+NCPS];
+ struct bank *tbp;
+ struct sym *sp;
+ FILE * fp;
+
+ if (oflag == 0) return;
+
+ /*
+ * Scan bank structures preparing
+ * the output file specifications.
+ */
+ idx = linkp->f_idx + fndext(linkp->f_idp + linkp->f_idx);
+ strncpy(str, linkp->f_idp, idx);
+ str[idx] = 0;
+
+ for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+ if (bp->b_flag & B_FSFX) {
+ strcpy(str + idx, bp->b_fsfx);
+ }
+ bp->b_fspec = strsto(str);
+ str[idx] = 0;
+ }
+
+ /*
+ * If .__.END. is defined force
+ * an output file to be opened.
+ */
+ sp = lkpsym(".__.END.", 0);
+ if (sp) {
+ sp->s_axp->a_bap->a_flag |= A4_OUT;
+ }
+
+ /*
+ * Scan the area list opening the appropriate
+ * output file if there is data in the area.
+ */
+ ap = areap;
+ while (ap) {
+ if ((ap->a_flag & A4_BNK) != A4_BNK) {
+ ap->a_bp = bankp;
+ }
+ if ((ap->a_flag & A4_OUT) || (ap->a_size != 0)) {
+ bp = ap->a_bp;
+ if (bp->b_ofp == NULL) {
+ /*
+ * Scan file specifications for
+ * identical file already opened.
+ */
+ for (tbp = bankp; tbp != NULL; tbp = tbp->b_bp) {
+ if (symeq(tbp->b_fspec, bp->b_fspec, 1)) {
+ if (tbp->b_ofp != NULL) {
+ bp->b_ofp = tbp->b_ofp;
+ bp->b_ofspec = tbp->b_ofspec;
+ }
+ }
+ }
+ }
+ if (bp->b_ofp == NULL) {
+ fp = stderr;
+ /*
+ * Open output file
+ */
+ if (oflag == 1) {
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "ihx"; break;
+ }
+ fp = afile(bp->b_fspec, frmt, 1);
+ } else
+ if (oflag == 2) {
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "s19"; break;
+ case 3: frmt = "s28"; break;
+ case 4: frmt = "s37"; break;
+ }
+ fp = afile(bp->b_fspec, frmt, 1);
+ } else
+ if (oflag == 3) {
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "bin"; break;
+ case 3: frmt = "bi3"; break;
+ case 4: frmt = "bi4"; break;
+ }
+ fp = afile(bp->b_fspec, frmt, 2);
+ } else
+ /* sdld specific */
+ if (oflag == 4) {
+ fp = afile(bp->b_fspec, "elf", 2);
+ }
+ /* end sdld specific */
+ if (fp != stderr) {
+ if (fp == NULL) {
+ lkexit(ER_FATAL);
+ }
+ bp->b_ofspec = strsto(afspec);
+#if NOICE
+ /*
+ * Include NoICE command to load file
+ */
+ if (jfp) {
+ fprintf(jfp, "LOAD %s\n", bp->b_ofspec);
+ }
+#endif
+ }
+ bp->b_ofp = fp;
+ }
+ ap->a_ofp = bp->b_ofp;
+ } else {
+ ap->a_ofp = NULL;
+ }
+ ap = ap->a_ap;
+ }
+}
+
+
+/*)Function VOID lkfclose()
+ *
+ * The function lkfclose() scans the bank structures to
+ * close all open data output files.
+ *
+ * local variables:
+ * struct bank *tbp temporary bank pointer
+ *
+ * global variables:
+ * bank *bp Pointer to the current
+ * bank structure
+ * bank *bankp The pointer to the first
+ * bank structure of a linked list
+ * FILE * ofp Output file handle
+ * FILE * stderr Standard Error Output handle
+ *
+ * functions called:
+ * VOID lkout() lkout.c
+ * int fclose() c_library
+ *
+ * side effects:
+ * All open data output files are closed.
+ */
+
+VOID
+lkfclose(void)
+{
+ struct bank *tbp;
+
+ /*
+ * Scan Bank Structure
+ * Output data terminations
+ * and close open files
+ */
+ bp = bankp;
+ while (bp != NULL) {
+ ofp = bp->b_ofp;
+ if (ofp != NULL) {
+ lkout(0, 0);
+ if (ofp != stderr) {
+ fclose(ofp);
+ }
+ /*
+ * Scan bank structure for
+ * identical file handles.
+ */
+ for (tbp = bp->b_bp; tbp != NULL; tbp = tbp->b_bp) {
+ if (tbp->b_ofp == ofp) {
+ tbp->b_ofp = NULL;
+ }
+ }
+ ofp = NULL;
+ bp->b_ofp = NULL;
+ }
+ bp = bp->b_bp;
+ }
+}
--- /dev/null
+/* lkdata.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With enhancements from
+ * John L. Hartman (JLH)
+ * jhartman@compuserve.com
+ *
+ */
+
+#include "aslink.h"
+
+/*)Module lkdata.c
+ *
+ * The module lkdata contains the global variables
+ * and structures used in the linker aslink.
+ */
+
+/*
+ * Internal ASxxxx Version Variable
+ */
+int ASxxxx_VERSION;
+
+
+/*
+ * Definitions for all Global Variables
+ */
+
+char *_abs_ = { ". .ABS." };
+
+char afspec[FILSPC]; /* The filespec created by afile()
+ */
+int lkerr; /* Linker error flag
+ */
+char *ip; /* Pointer into the REL file text line in ib[]
+ */
+char ib[NINPUT]; /* REL file text line
+ */
+char *rp; /* pointer into the LST file
+ * text line in rb[]
+ */
+char rb[NINPUT]; /* LST file text line being
+ * address relocated
+ */
+int oflag; /* Output file type flag
+ */
+int objflg; /* Linked file/library object output flag
+ */
+
+#if NOICE
+int jflag; /* NoICE output flag
+ */
+#endif
+
+#if SDCDB
+int yflag; /* SDCDB output flag
+ */
+#endif
+
+int mflag; /* Map output flag
+ */
+int xflag; /* Map file radix type flag
+ */
+int pflag; /* print linker command file flag
+ */
+int uflag; /* Listing relocation flag
+ */
+int wflag; /* Enable wide format listing
+ */
+int zflag; /* Disable symbol case sensitivity
+ */
+int radix; /* current number conversion radix:
+ * 2 (binary), 8 (octal), 10 (decimal),
+ * 16 (hexadecimal)
+ */
+int line; /* current line number
+ */
+int page; /* current page number
+ */
+int lop; /* current line number on page
+ */
+int pass; /* linker pass number
+ */
+a_uint pc; /* current relocation address
+ */
+int pcb; /* current bytes per pc word
+ */
+int rtcnt; /* count of elements in the
+ * rtval[] and rtflg[] arrays
+ */
+a_uint rtval[NTXT]; /* data associated with relocation
+ */
+int rtflg[NTXT]; /* indicates if rtval[] value is
+ * to be sent to the output file.
+ */
+int rterr[NTXT]; /* indicates if rtval[] value should
+ * be flagged as a relocation error.
+ */
+char rtbuf[NMAX]; /* S19/IHX output buffer
+ */
+struct bank * rtabnk; /* rtbuf[] processing
+ */
+int rtaflg; /* rtbuf[] processing
+ */
+a_uint rtadr0 = 0; /*
+ */
+a_uint rtadr1 = 0; /*
+ */
+a_uint rtadr2 = 0; /*
+ */
+int obj_flag = 0; /* Linked file/library object output flag
+ */
+int a_bytes; /* REL file T Line address length
+ */
+int hilo; /* REL file byte ordering
+ */
+a_uint a_mask; /* Address Mask
+ */
+a_uint s_mask; /* Sign Mask
+ */
+a_uint v_mask; /* Value Mask
+ */
+int gline; /* LST file relocation active
+ * for current line
+ */
+int gcntr; /* LST file relocation active
+ * counter
+ */
+/* sdld specific */
+char *optsdcc;
+char *optsdcc_module;
+int sflag; /* JCF: Memory usage output flag
+ */
+int packflag=0; /* JCF: Pack internal memory flag
+ */
+int stacksize=0; /* JCF: Stack size
+ */
+int aflag; /* Overlapping area warning flag
+ */
+int rflag; /* Extended linear address record flag.
+ */
+a_uint iram_size; /* internal ram size
+ */
+long xram_size = -1; /* external ram size
+ */
+long code_size = -1; /* code size
+ */
+/* end sdld specific */
+
+/*
+ * The structure lfile contains a pointer to a
+ * file specification string, an index which points
+ * to the file name (past the 'path'), the file type,
+ * an object output flag, and a link to the next
+ * lfile structure.
+ *
+ * struct lfile
+ * {
+ * struct lfile *f_flp; lfile link
+ * int f_type; File type
+ * char *f_idp; Pointer to file spec
+ * int f_obj; Object output flag
+ * };
+ */
+struct lfile *filep; /* The pointers (lfile *) filep,
+ * (lfile *) cfp, and (FILE *) sfp
+ * are used in conjunction with
+ * the routine nxtline() to read
+ * asmlnk commands from
+ * (1) the standard input or
+ * (2) or a command file
+ * and to read the REL files
+ * sequentially as defined by the
+ * asmlnk input commands.
+ *
+ * The pointer *filep points to the
+ * beginning of a linked list of
+ * lfile structures.
+ */
+struct lfile *cfp; /* The pointer *cfp points to the
+ * current lfile structure
+ */
+struct lfile *startp;/* aslink startup file structure
+ */
+struct lfile *linkp; /* pointer to first lfile structure
+ * containing an input REL file
+ * specification
+ */
+struct lfile *lfp; /* pointer to current lfile structure
+ * being processed by parse()
+ */
+FILE *ofp = NULL; /* Output file handle
+ * for word formats
+ */
+
+#if NOICE
+FILE *jfp = NULL; /* NoICE output file handle
+ */
+#endif
+
+#if SDCDB
+FILE *yfp = NULL; /* SDCDB output file handle
+ */
+#endif
+
+FILE *mfp = NULL; /* Map output file handle
+ */
+FILE *rfp = NULL; /* File handle for output
+ * address relocated ASxxxx
+ * listing file
+ */
+FILE *sfp = NULL; /* The file handle sfp points to the
+ * currently open file
+ */
+FILE *tfp = NULL; /* File handle for input
+ * ASxxxx listing file
+ */
+
+/*
+ * The structures of head, bank, area, areax, and sym
+ * are created as the REL files are read during the first
+ * pass of the linker. The struct head is created upon
+ * encountering a H directive in the REL file. The
+ * structure contains a link to a link file structure
+ * (struct lfile) which describes the file containing the H
+ * directive, a pointer to an array of merge mode
+ * definition pointers, the number of data/code areas
+ * contained in this header segment, the number of
+ * symbols referenced/defined in this header segment, a pointer
+ * to an array of pointers to areax structures (struct areax)
+ * created as each A directive is read, a pointer to an
+ * array of pointers to symbol structures (struct sym) for
+ * all referenced/defined symbols and a pointer to an array
+ * of pointers to bank structures (struct bank) referenced
+ * by this module. As H directives are read
+ * from the REL files a linked list of head structures is
+ * created by placing a link to the new head structure
+ * in the previous head structure.
+ *
+ * struct head
+ * {
+ * struct head *h_hp; Header link
+ * struct lfile *h_lfile; Associated file
+ * int h_narea; # of areas
+ * struct areax **a_list; Area list
+ * int h_nsym; # of symbols
+ * struct sym **s_list; Symbol list
+ * int h_nbank; # of banks
+ * struct bank **b_list; Bank list
+ * int h_nmode; # of modes
+ * struct mode **m_list; Mode list
+ * char * m_id; Module name
+ * };
+ */
+struct head *headp; /* The pointer to the first
+ * head structure of a linked list
+ */
+struct head *hp; /* Pointer to the current
+ * head structure
+ */
+
+/*
+ * The bank structure contains the parameter values for a
+ * specific program or data bank. The bank structure
+ * is a linked list of banks. The initial default bank
+ * is unnamed and is defined in lkdata.c, the next bank structure
+ * will be linked to this structure through the structure
+ * element 'struct bank *b_bp'. The structure contains the
+ * bank name, the bank base address (default = 0)
+ * the bank size, (default = 0, whole addressing space)
+ * and the file name suffix. (default is none) These optional
+ * parameters are from the .bank assembler directive.
+ * The bank structure also contains the bank data output
+ * file specificatiion, file handle pointer and the
+ * bank first output flag.
+ *
+ * struct bank
+ * {
+ * struct bank *b_bp; Bank link
+ * char * b_id; Bank Name
+ * char * b_fsfx; Bank File Suffix
+ * a_uint b_base; Bank base address
+ * a_uint b_size; Bank size
+ * a_uint b_map Bank mapping
+ * int b_flag; Bank flags
+ * char * b_fspec; Bank File Specification
+ * FILE * b_ofp; Bank File Handle
+ * int b_oflag; Bank has output flag
+ * int b_rtaflg Bank First Output flag
+ * };
+ */
+struct bank bank[1] = {
+ { NULL, "", "", 0, 0, 0, 0, "", NULL, 0, 1 }
+};
+
+struct bank *bankp = &bank[0];
+ /* The pointer to the first
+ * bank structure
+ */
+struct bank *bp; /* Pointer to the current
+ * bank structure
+ */
+
+/*
+ * A structure area is created for each 'unique' data/code
+ * area definition found as the REL files are read. The
+ * struct area contains the name of the area, a flag byte
+ * which contains the area attributes (REL/CON/OVR/ABS),
+ * the area base address set flag byte (-b option), and the
+ * area base address and total size which will be filled
+ * in at the end of the first pass through the REL files.
+ * The area structure also contains a link to the bank
+ * this area is a part of and a data output file handle
+ * pointer which is loaded from from the bank structure.
+ * As A directives are read from the REL files a linked
+ * list of unique area structures is created by placing a
+ * link to the new area structure in the previous area structure.
+ *
+ * struct area
+ * {
+ * struct area *a_ap; Area link
+ * struct areax *a_axp; Area extension link
+ * struct bank *a_bp; Bank link
+ * FILE * a_ofp; Area File Handle
+ * a_uint a_addr; Beginning address of area
+ * a_uint a_size; Total size of the area
+ * int a_bset; Area base address set
+ * int a_flag; Flags
+ * char * a_id; Name
+ * };
+ */
+struct area *areap; /* The pointer to the first
+ * area structure of a linked list
+ */
+struct area *ap; /* Pointer to the current
+ * area structure
+ */
+
+/*
+ * An areax structure is created for every A directive found
+ * while reading the REL files. The struct areax contains a
+ * link to the 'unique' area structure referenced by the A
+ * directive and to the head structure this area segment is
+ * a part of. The size of this area segment as read from the
+ * A directive is placed in the areax structure. The beginning
+ * address of this segment will be filled in at the end of the
+ * first pass through the REL files. As A directives are read
+ * from the REL files a linked list of areax structures is
+ * created for each unique area. The final areax linked
+ * list has at its head the 'unique' area structure linked
+ * to the linked areax structures (one areax structure for
+ * each A directive for this area).
+ *
+ * struct areax
+ * {
+ * struct areax *a_axp; Area extension link
+ * struct area *a_bap; Base area link
+ * struct head *a_bhp; Base header link
+ * a_uint a_addr; Beginning address of section
+ * a_uint a_size; Size of the area in section
+ * };
+ */
+struct areax *axp; /* Pointer to the current
+ * areax structure
+ */
+
+/*
+ * A sym structure is created for every unique symbol
+ * referenced/defined while reading the REL files. The
+ * struct sym contains the symbol's name, a flag value
+ * (not used in this linker), a symbol type denoting
+ * referenced/defined, and an address which is loaded
+ * with the relative address within the area in which
+ * the symbol was defined. The sym structure also
+ * contains a link to the area where the symbol was defined.
+ * The sym structures are linked into linked lists using
+ * the symbol link element.
+ *
+ * struct sym
+ * {
+ * struct sym *s_sp; Symbol link
+ * struct areax *s_axp; Symbol area link
+ * char s_type; Symbol subtype
+ * char s_flag; Flag byte
+ * a_uint s_addr; Address
+ * char *s_id; Name (JLH)
+ * char *m_id; Module
+ * };
+ */
+struct sym *symhash[NHASH]; /* array of pointers to NHASH
+ * linked symbol lists
+ */
+/*
+ * The struct base contains a pointer to a
+ * base definition string and a link to the next
+ * base structure.
+ *
+ * struct base
+ * {
+ * struct base *b_base; Base link
+ * char *b_strp; String pointer
+ * };
+ */
+struct base *basep; /* The pointer to the first
+ * base structure
+ */
+struct base *bsp; /* Pointer to the current
+ * base structure
+ */
+
+/*
+ * The struct globl contains a pointer to a
+ * global definition string and a link to the next
+ * global structure.
+ *
+ * struct globl
+ * {
+ * struct globl *g_globl; Global link
+ * char *g_strp; String pointer
+ * };
+ */
+struct globl *globlp;/* The pointer to the first
+ * globl structure
+ */
+struct globl *gsp; /* Pointer to the current
+ * globl structure
+ */
+
+/*
+ * A structure sdp is created for each 'unique' paged
+ * area definition found as the REL files are read.
+ * As P directives are read from the REL files a linked
+ * list of unique sdp structures is created by placing a
+ * link to the new sdp structure in the previous area structure.
+ *
+ * struct sdp
+ * {
+ * struct area *s_area; Paged Area link
+ * struct areax *s_areax; Paged Area Extension Link
+ * a_uint s_addr; Page address offset
+ * };
+ */
+struct sdp sdp; /* Base Page Structure */
+
+/*
+ * The structure rerr is loaded with the information
+ * required to report an error during the linking
+ * process. The structure contains an index value
+ * which selects the areax structure from the header
+ * areax structure list, a mode value which selects
+ * symbol or area relocation, the base address in the
+ * area section, an area/symbol list index value, and
+ * an area/symbol offset value.
+ *
+ * struct rerr
+ * {
+ * int aindex; Linking area
+ * int mode; Relocation mode
+ * a_uint rtbase; Base address in section
+ * int rindex; Area/Symbol relocation index
+ * a_uint rval; Area/Symbol offset value
+ * };
+ */
+struct rerr rerr; /* Structure containing the
+ * linker error information
+ */
+
+/*
+ * The structure lbpath is created for each library
+ * path specification input by the -k option. The
+ * lbpath structures are linked into a list using
+ * the next link element.
+ *
+ * struct lbpath {
+ * struct lbpath *next;
+ * char *path;
+ * };
+ */
+struct lbpath *lbphead; /* pointer to the first
+ * library path structure
+ */
+
+/*
+ * The structure lbname is created for all combinations of the
+ * library path specifications (input by the -k option) and the
+ * library file specifications (input by the -l option) that
+ * lead to an existing file. The element path points to
+ * the path string, element libfil points to the library
+ * file string, and the element libspc is the concatenation
+ * of the valid path and libfil strings.
+ *
+ * The lbpath structures are linked into a list
+ * using the next link element.
+ *
+ * Each library file contains a list of object files
+ * that are contained in the particular library. e.g.:
+ *
+ * \iolib\termio
+ * \inilib\termio
+ *
+ * Only one specification per line is allowed.
+ *
+ * struct lbname {
+ * struct lbname *next;
+ * char *path;
+ * char *libfil;
+ * char *libspc;
+ * char f_obj;
+ * };
+ */
+struct lbname *lbnhead; /* pointer to the first
+ * library name structure
+ */
+
+/*
+ * The function fndsym() searches through all combinations of the
+ * library path specifications (input by the -k option) and the
+ * library file specifications (input by the -l option) that
+ * lead to an existing file for a symbol definition.
+ *
+ * The structure lbfile is created for the first library
+ * object file which contains the definition for the
+ * specified undefined symbol.
+ *
+ * The element libspc points to the library file path specification
+ * and element relfil points to the object file specification string.
+ * The element filspc is the complete path/file specification for
+ * the library file to be imported into the linker. The f_obj
+ * flag specifies if the object code from this file is
+ * to be output by the linker. The file specification
+ * may be formed in one of two ways:
+ *
+ * (1) If the library file contained an absolute
+ * path/file specification then this becomes filspc.
+ * (i.e. C:\...)
+ *
+ * (2) If the library file contains a relative path/file
+ * specification then the concatenation of the path
+ * and this file specification becomes filspc.
+ * (i.e. \...)
+ *
+ * The lbpath structures are linked into a list
+ * using the next link element.
+ *
+ * struct lbfile {
+ * struct lbfile *next;
+ * char *libspc;
+ * char *relfil;
+ * char *filspc;
+ * int f_obj;
+ * };
+ */
+struct lbfile *lbfhead; /* pointer to the first
+ * library file structure
+ */
+/* sdld 8051 specific */
+char idatamap[256];
+/* end sdld 8051 specific */
+
+/*
+ * array of character types, one per
+ * ASCII character
+ */
+char ctype[128] = {
+/*NUL*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
+/*BS*/ ILL, SPACE, ILL, ILL, SPACE, ILL, ILL, ILL,
+/*DLE*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
+/*CAN*/ ILL, ILL, ILL, ILL, ILL, ILL, ILL, ILL,
+/*SPC*/ SPACE, ETC, ETC, ETC, LETTER, BINOP, BINOP, ETC,
+/*(*/ ETC, ETC, BINOP, BINOP, ETC, BINOP, LETTER, BINOP,
+/*0*/ DGT2, DGT2, DGT8, DGT8, DGT8, DGT8, DGT8, DGT8,
+/*8*/ DGT10, DGT10, ETC, ETC, BINOP, ETC, BINOP, ETC,
+/*@*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER,
+/*H*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*P*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*X*/ LETTER, LETTER, LETTER, BINOP, ETC, ETC, BINOP, LETTER,
+/*`*/ ETC, LTR16, LTR16, LTR16, LTR16, LTR16, LTR16, LETTER,
+/*h*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*p*/ LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER, LETTER,
+/*x*/ LETTER, LETTER, LETTER, ETC, BINOP, ETC, ETC, ETC
+};
+
+/*
+ * an array of characters which
+ * perform the case translation function
+ */
+char ccase[128] = {
+/*NUL*/ '\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
+/*BS*/ '\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
+/*DLE*/ '\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
+/*CAN*/ '\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
+/*SPC*/ '\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
+/*(*/ '\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
+/*0*/ '\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
+/*8*/ '\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
+/*@*/ '\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+/*H*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+/*P*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+/*X*/ '\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
+/*`*/ '\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
+/*h*/ '\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
+/*p*/ '\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
+/*x*/ '\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177'
+};
--- /dev/null
+/* lkelf.c - Create an executable ELF/DWARF file
+
+ Copyright (C) 2004 Erik Petrich, epetrich at users dot sourceforge dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <asxxxx_config.h>
+
+#include "aslink.h"
+
+static int execStartMSB;
+static int execStartLSB;
+static char execStartMSBfound;
+static char execStartLSBfound;
+
+typedef TYPE_UDWORD Elf32_Addr;
+typedef TYPE_WORD Elf32_Half;
+typedef TYPE_UDWORD Elf32_Off;
+typedef TYPE_DWORD Elf32_Sword;
+typedef TYPE_UDWORD Elf32_Word;
+
+enum
+{
+ EI_MAG0 = 0,
+ EI_MAG1,
+ EI_MAG2,
+ EI_MAG3,
+ EI_CLASS,
+ EI_DATA,
+ EI_VERSION,
+ EI_PAD,
+ EI_NIDENT = 16
+};
+
+enum
+{
+ ELFMAG0 = 0x7f,
+ ELFMAG1 = 'E',
+ ELFMAG2 = 'L',
+ ELFMAG3 = 'F'
+};
+
+enum
+{
+ ET_NONE = 0,
+ ET_REL,
+ ET_EXEC,
+ ET_DYN,
+ ET_CORE
+};
+
+/* These e_machine values are from "Motorola 8- and 16-bit Embedded */
+/* Application Binary Interface (M8/16EABI)" version 2.0 */
+enum
+{
+ EM_NONE = 0,
+ EM_68HC05 = 72,
+ EM_68HC08 = 71,
+ EM_68HC11 = 70,
+ EM_68HC12 = 53,
+ EM_68HC16 = 69
+};
+
+enum
+{
+ EV_NONE = 0,
+ EV_CURRENT
+};
+
+enum
+{
+ ELFCLASSNONE = 0,
+ ELFCLASS32,
+ ELFCLASS64
+};
+
+enum
+{
+ ELFDATANONE = 0,
+ ELFDATA2LSB,
+ ELFDATA2MSB
+};
+
+enum
+{
+ SHT_NULL = 0,
+ SHT_PROGBITS,
+ SHT_SYMTAB,
+ SHT_STRTAB,
+ SHT_RELA,
+ SHT_HASH,
+ SHT_DYNAMIC,
+ SHT_NOTE,
+ SHT_NOBITS,
+ SHT_REL,
+ SHT_SHLIB,
+ SHT_DYNSYM
+};
+
+enum
+{
+ SHF_WRITE = (1 << 0),
+ SHF_ALLOC = (1 << 1),
+ SHF_EXECINSTR = (1 << 2),
+};
+
+enum
+{
+ PT_NULL = 0,
+ PT_LOAD
+};
+
+enum
+{
+ PF_X = (1 << 0),
+ PF_W = (1 << 1),
+ PF_R = (1 << 2)
+};
+
+typedef struct
+{
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+} Elf32_Ehdr;
+
+typedef struct
+{
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+} Elf32_Shdr;
+
+typedef struct
+{
+ Elf32_Word p_type;
+ Elf32_Off p_offset;
+ Elf32_Addr p_vaddr;
+ Elf32_Addr p_paddr;
+ Elf32_Word p_filesz;
+ Elf32_Word p_memsz;
+ Elf32_Word p_flags;
+ Elf32_Word p_align;
+} Elf32_Phdr;
+
+typedef struct strtabString
+{
+ char * string;
+ struct strtabString * prev;
+ struct strtabString * next;
+ Elf32_Word index;
+} strtabString;
+
+typedef struct
+{
+ strtabString * first;
+ strtabString * last;
+} strtabList;
+
+static strtabList shstrtab;
+
+
+typedef struct listEntry
+{
+ void * item;
+ struct listEntry * prev;
+ struct listEntry * next;
+} listEntry;
+
+typedef struct
+{
+ listEntry * first;
+ listEntry * last;
+ int count;
+} listHeader;
+
+
+
+static void
+listAdd (listHeader * lhp, void * item)
+{
+ listEntry * lep;
+
+ lep = (listEntry *)new (sizeof (*lep));
+ lep->item = item;
+ lep->prev = lhp->last;
+ if (lep->prev)
+ lep->prev->next = lep;
+
+ lhp->last = lep;
+ if (!lhp->first)
+ lhp->first = lep;
+
+ lhp->count++;
+}
+
+static listHeader *
+listNew (void)
+{
+ listHeader * lhp;
+
+ lhp = (listHeader *)new (sizeof (*lhp));
+
+ return lhp;
+}
+
+
+#if 0
+static Elf32_Word
+strtabFind (strtabList * strtab, char * str)
+{
+ strtabString * sp;
+ sp = strtab->first;
+
+ while (sp)
+ {
+ if (!strcmp (str, sp->string))
+ return sp->index;
+ sp = sp->next;
+ }
+
+ return 0;
+}
+#endif
+
+/*-------------------------------------------------------------------*/
+/* strtabFindOrAdd - Finds a string in a string table or adds the */
+/* string if it does not already exist. Returns the offset of the */
+/* string in the table. */
+/*-------------------------------------------------------------------*/
+static Elf32_Word
+strtabFindOrAdd (strtabList * strtab, char * str)
+{
+ strtabString * sp;
+ sp = strtab->first;
+
+ while (sp)
+ {
+ if (!strcmp (str, sp->string))
+ return sp->index;
+ sp = sp->next;
+ }
+
+ sp = (strtabString *)new (sizeof(*sp));
+ if (strtab->last)
+ sp->index = strtab->last->index + 1 + strlen (strtab->last->string);
+ else
+ sp->index = 1;
+ sp->string = new (1+strlen (str));
+ strcpy (sp->string, str);
+
+ sp->prev = strtab->last;
+ if (sp->prev)
+ sp->prev->next = sp;
+ strtab->last = sp;
+ if (!strtab->first)
+ strtab->first = sp;
+
+ return sp->index;
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElfStrtab - writes a string table to a file */
+/*-------------------------------------------------------------------*/
+static void
+fputElfStrtab (strtabList *strtab, FILE *fp)
+{
+ strtabString * sp;
+
+ fputc (0, fp); /* index 0 must be the null character */
+
+ sp = strtab->first;
+ while (sp)
+ {
+ fputs (sp->string, fp);
+ fputc (0, fp);
+ sp = sp->next;
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Word - writes an Elf32_Word value to a file */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Word (Elf32_Word x, FILE *fp)
+{
+ if (hilo == 0)
+ {
+ fputc (x & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ fputc ((x >> 16) & 0xff, fp);
+ fputc ((x >> 24) & 0xff, fp);
+ }
+ else
+ {
+ fputc ((x >> 24) & 0xff, fp);
+ fputc ((x >> 16) & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ fputc (x & 0xff, fp);
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Off - writes an Elf32_Off value to a file */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Off (Elf32_Off x, FILE *fp)
+{
+ if (hilo == 0)
+ {
+ fputc (x & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ fputc ((x >> 16) & 0xff, fp);
+ fputc ((x >> 24) & 0xff, fp);
+ }
+ else
+ {
+ fputc ((x >> 24) & 0xff, fp);
+ fputc ((x >> 16) & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ fputc (x & 0xff, fp);
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Addr - writes an Elf32_Addr value to a file */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Addr (Elf32_Addr x, FILE *fp)
+{
+ if (hilo == 0)
+ {
+ fputc (x & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ fputc ((x >> 16) & 0xff, fp);
+ fputc ((x >> 24) & 0xff, fp);
+ }
+ else
+ {
+ fputc ((x >> 24) & 0xff, fp);
+ fputc ((x >> 16) & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ fputc (x & 0xff, fp);
+ }
+}
+
+/*-------------------------------------------------------------------*/
+/* fputElf32_Half - writes an Elf32_Half value to a file */
+/*-------------------------------------------------------------------*/
+static void
+fputElf32_Half (Elf32_Half x, FILE *fp)
+{
+ if (hilo == 0)
+ {
+ fputc (x & 0xff, fp);
+ fputc ((x >> 8) & 0xff, fp);
+ }
+ else
+ {
+ fputc ((x >> 8) & 0xff, fp);
+ fputc (x & 0xff, fp);
+ }
+}
+
+/*------------------------------------------------------------------------*/
+/* fputElf32_Ehdr - writes an Elf32_Ehdr struct (ELF header) to a file */
+/*------------------------------------------------------------------------*/
+static void
+fputElf32_Ehdr (Elf32_Ehdr * ehdr, FILE * fp)
+{
+ int i;
+
+ for (i=0; i<EI_NIDENT; i++)
+ fputc (ehdr->e_ident[i], fp);
+
+ fputElf32_Half (ehdr->e_type, fp);
+ fputElf32_Half (ehdr->e_machine, fp);
+ fputElf32_Word (ehdr->e_version, fp);
+ fputElf32_Addr (ehdr->e_entry, fp);
+ fputElf32_Off (ehdr->e_phoff, fp);
+ fputElf32_Off (ehdr->e_shoff, fp);
+ fputElf32_Word (ehdr->e_flags, fp);
+ fputElf32_Half (ehdr->e_ehsize, fp);
+ fputElf32_Half (ehdr->e_phentsize, fp);
+ fputElf32_Half (ehdr->e_phnum, fp);
+ fputElf32_Half (ehdr->e_shentsize, fp);
+ fputElf32_Half (ehdr->e_shnum, fp);
+ fputElf32_Half (ehdr->e_shstrndx, fp);
+}
+
+/*-------------------------------------------------------------------------*/
+/* fputElf32_Ehdr - writes an Elf32_Shdr struct (section header) to a file */
+/*-------------------------------------------------------------------------*/
+static void
+fputElf32_Shdr (Elf32_Shdr * shdr, FILE * fp)
+{
+ fputElf32_Word (shdr->sh_name, fp);
+ fputElf32_Word (shdr->sh_type, fp);
+ fputElf32_Word (shdr->sh_flags, fp);
+ fputElf32_Addr (shdr->sh_addr, fp);
+ fputElf32_Off (shdr->sh_offset, fp);
+ fputElf32_Word (shdr->sh_size, fp);
+ fputElf32_Word (shdr->sh_link, fp);
+ fputElf32_Word (shdr->sh_info, fp);
+ fputElf32_Word (shdr->sh_addralign, fp);
+ fputElf32_Word (shdr->sh_entsize, fp);
+}
+
+/*-------------------------------------------------------------------------*/
+/* fputElf32_Ehdr - writes an Elf32_Phdr struct (segment header) to a file */
+/*-------------------------------------------------------------------------*/
+static void
+fputElf32_Phdr (Elf32_Phdr * phdr, FILE * fp)
+{
+ fputElf32_Word (phdr->p_type, fp);
+ fputElf32_Off (phdr->p_offset, fp);
+ fputElf32_Addr (phdr->p_vaddr, fp);
+ fputElf32_Addr (phdr->p_paddr, fp);
+ fputElf32_Word (phdr->p_filesz, fp);
+ fputElf32_Word (phdr->p_memsz, fp);
+ fputElf32_Word (phdr->p_flags, fp);
+ fputElf32_Word (phdr->p_align, fp);
+}
+
+
+/*--------------------------------------------------------------------------*/
+/* elfGenerateAbs - generates segments and sections for an absolute area. */
+/* This is a little more complicated than a relative area since it may */
+/* contain noncontiguous regions. */
+/*--------------------------------------------------------------------------*/
+static void
+elfGenerateAbs (struct area *ap, listHeader * segments, listHeader * sections)
+{
+ Elf32_Addr ofs;
+ Elf32_Addr addr;
+ Elf32_Word size;
+ Elf32_Phdr * phdrp;
+ Elf32_Shdr * shdrp;
+
+ if (!ap->a_image)
+ {
+ return;
+ }
+
+ ofs = 0;
+ for (;;)
+ {
+ /* Find the start of a contiguously */
+ /* used region within this area */
+ while (ofs < ap->a_imagesize && !ap->a_used[ofs])
+ ofs++;
+ if (ofs >= ap->a_imagesize)
+ return;
+
+ /* Find the end of the region */
+ addr = ap->a_addr + ofs;
+ while (ofs < ap->a_imagesize && ap->a_used[ofs])
+ ofs++;
+ size = ap->a_addr + ofs - addr;
+
+ /* create a segment header for this region if loadable */
+ if (!(ap->a_flag & A_NOLOAD))
+ {
+ phdrp = (Elf32_Phdr *)new (sizeof (*phdrp));
+ phdrp->p_type = PT_LOAD;
+ phdrp->p_offset = ftell (ofp);
+ phdrp->p_vaddr = addr;
+ phdrp->p_paddr = addr;
+ phdrp->p_filesz = size;
+ phdrp->p_memsz = size;
+ phdrp->p_flags = PF_R;
+ if (ap->a_flag & A_CODE)
+ phdrp->p_flags |= PF_X;
+ phdrp->p_align = 1;
+ listAdd (segments, phdrp);
+ }
+
+ /* create a section header for this region */
+ shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+ shdrp->sh_name = strtabFindOrAdd (&shstrtab, ap->a_id);
+ shdrp->sh_type = SHT_PROGBITS;
+ shdrp->sh_flags = 0;
+ if (!(ap->a_flag & A_NOLOAD))
+ shdrp->sh_flags |= SHF_ALLOC;
+ if (ap->a_flag & A_CODE)
+ shdrp->sh_flags |= SHF_EXECINSTR;
+ shdrp->sh_addr = addr;
+ shdrp->sh_offset = ftell (ofp);
+ shdrp->sh_size = size;
+ shdrp->sh_link = 0;
+ shdrp->sh_info = 0;
+ shdrp->sh_addralign = 0;
+ shdrp->sh_entsize = 0;
+ listAdd (sections, shdrp);
+
+ fwrite (&ap->a_image[addr-ap->a_addr], 1, size, ofp);
+ }
+}
+
+/*--------------------------------------------------------------------------*/
+/* elfGenerateRel - generates a segment and section for a relative area. */
+/*--------------------------------------------------------------------------*/
+static void
+elfGenerateRel (struct area *ap, listHeader * segments, listHeader * sections)
+{
+ Elf32_Phdr * phdrp;
+ Elf32_Shdr * shdrp;
+
+ if (!ap->a_image)
+ {
+ return;
+ }
+
+ /* create a segment header for this area if loadable */
+ if (!(ap->a_flag & A_NOLOAD))
+ {
+ phdrp = (Elf32_Phdr *)new (sizeof (*phdrp));
+ phdrp->p_type = PT_LOAD;
+ phdrp->p_offset = ftell (ofp);
+ phdrp->p_vaddr = ap->a_addr;
+ phdrp->p_paddr = ap->a_addr;
+ phdrp->p_filesz = ap->a_size;
+ phdrp->p_memsz = ap->a_size;
+ phdrp->p_flags = PF_R;
+ if (ap->a_flag & A_CODE)
+ phdrp->p_flags |= PF_X;
+ phdrp->p_align = 1;
+ listAdd (segments, phdrp);
+ }
+
+ /* create a section header for this area */
+ shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+ shdrp->sh_name = strtabFindOrAdd (&shstrtab, ap->a_id);
+ shdrp->sh_type = SHT_PROGBITS;
+ shdrp->sh_flags = 0;
+ if (!(ap->a_flag & A_NOLOAD))
+ shdrp->sh_flags |= SHF_ALLOC;
+ if (ap->a_flag & A_CODE)
+ shdrp->sh_flags |= SHF_EXECINSTR;
+ shdrp->sh_addr = ap->a_addr;
+ shdrp->sh_offset = ftell (ofp);
+ shdrp->sh_size = ap->a_size;
+ shdrp->sh_link = 0;
+ shdrp->sh_info = 0;
+ shdrp->sh_addralign = 0;
+ shdrp->sh_entsize = 0;
+ listAdd (sections, shdrp);
+
+ fwrite (ap->a_image, 1, ap->a_size, ofp);
+}
+
+/*--------------------------------------------------------------------------*/
+/* elfGenerate - generates the complete ELF file */
+/*--------------------------------------------------------------------------*/
+static void
+elfGenerate (void)
+{
+ listHeader * sections = listNew();
+ listHeader * segments = listNew();
+ struct area *ap;
+ Elf32_Ehdr ehdr;
+ Elf32_Shdr * shdrp;
+ Elf32_Phdr * phdrp;
+ listEntry * lep;
+ int i;
+ Elf32_Word shstrtabName;
+
+ /* create the null section header for index 0 */
+ shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+ shdrp->sh_name = 0;
+ shdrp->sh_type = SHT_NULL;
+ shdrp->sh_flags = 0;
+ shdrp->sh_addr = 0;
+ shdrp->sh_offset = 0;
+ shdrp->sh_size = 0;
+ shdrp->sh_link = 0;
+ shdrp->sh_info = 0;
+ shdrp->sh_addralign = 0;
+ shdrp->sh_entsize = 0;
+ listAdd (sections, shdrp);
+
+ /* Initialize the ELF header */
+ for (i=0; i<EI_NIDENT; i++)
+ ehdr.e_ident[i] = 0;
+ ehdr.e_ident[EI_MAG0] = ELFMAG0;
+ ehdr.e_ident[EI_MAG1] = ELFMAG1;
+ ehdr.e_ident[EI_MAG2] = ELFMAG2;
+ ehdr.e_ident[EI_MAG3] = ELFMAG3;
+ ehdr.e_ident[EI_CLASS] = ELFCLASS32;
+ if (hilo == 0)
+ ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
+ else
+ ehdr.e_ident[EI_DATA] = ELFDATA2MSB;
+ ehdr.e_ident[EI_VERSION] = 1;
+ ehdr.e_type = ET_EXEC;
+ ehdr.e_machine = EM_68HC08; /* FIXME: get rid of hardcoded value - EEP */
+ ehdr.e_phentsize = sizeof (*phdrp);
+ ehdr.e_shentsize = sizeof (*shdrp);
+ ehdr.e_ehsize = sizeof (ehdr);
+ ehdr.e_phnum = 0;
+ ehdr.e_shnum = 0;
+ ehdr.e_shstrndx = 0;
+ ehdr.e_version = 1;
+ ehdr.e_entry = 0;
+ if (execStartMSBfound && execStartLSBfound)
+ ehdr.e_entry = (execStartMSB << 8) + execStartLSB;
+
+ /* Write out the ELF header as a placeholder; we will update */
+ /* it with the final values when everything is complete */
+ fputElf32_Ehdr (&ehdr, ofp);
+
+ /* Iterate over the linker areas to generate */
+ /* the ELF sections and segments */
+ ap = areap;
+ while (ap)
+ {
+ if (ap->a_size)
+ {
+ if (ap->a_flag & A3_ABS)
+ elfGenerateAbs (ap, segments, sections);
+ else
+ elfGenerateRel (ap, segments, sections);
+ }
+ ap = ap->a_ap;
+ }
+
+ /* Create the string table section after the other sections */
+ shdrp = (Elf32_Shdr *)new (sizeof (*shdrp));
+ shdrp->sh_name = strtabFindOrAdd (&shstrtab, ".shstrtab");
+ shdrp->sh_type = SHT_STRTAB;
+ shdrp->sh_flags = 0;
+ shdrp->sh_addr = 0;
+ shdrp->sh_offset = ftell (ofp);
+ shdrp->sh_size = shstrtab.last->index + strlen (shstrtab.last->string) + 1;
+ shdrp->sh_link = 0;
+ shdrp->sh_info = 0;
+ shdrp->sh_addralign = 0;
+ shdrp->sh_entsize = 0;
+ listAdd (sections, shdrp);
+ fputElfStrtab (&shstrtab, ofp);
+
+ /* Find the index of the section string table */
+ /* header and save it in the ELF header */
+ ehdr.e_shstrndx = 0;
+ shstrtabName = shdrp->sh_name;
+ lep = sections->first;
+ while (lep)
+ {
+ shdrp = lep->item;
+ if (shdrp->sh_name == shstrtabName)
+ break;
+ ehdr.e_shstrndx++;
+ lep = lep->next;
+ }
+
+ /* Write out the segment headers */
+ ehdr.e_phnum = segments->count;
+ ehdr.e_phoff = ftell (ofp);
+ lep = segments->first;
+ while (lep)
+ {
+ phdrp = lep->item;
+ fputElf32_Phdr (phdrp, ofp);
+ lep = lep->next;
+ }
+
+ /* Write out the section headers */
+ ehdr.e_shnum = sections->count;
+ ehdr.e_shoff = ftell (ofp);
+ lep = sections->first;
+ while (lep)
+ {
+ shdrp = lep->item;
+ fputElf32_Shdr (shdrp, ofp);
+ lep = lep->next;
+ }
+
+ /* All the values in the ELF header have now been computed; write */
+ /* over the placeholder header with the final values */
+ fseek (ofp, 0, SEEK_SET);
+ fputElf32_Ehdr (&ehdr, ofp);
+ fseek (ofp, 0, SEEK_END);
+}
+
+/*--------------------------------------------------------------------------*/
+/* elf - incrementally called by the linker core to generate ELF file data. */
+/* The parameter is nonzero when there is data available and zero when */
+/* the linker is finished. */
+/*--------------------------------------------------------------------------*/
+void
+elf (int i)
+{
+ a_uint address;
+
+ /* Buffer the data until we have it all */
+ if (i)
+ {
+ if (hilo == 0)
+ address = rtval[0] + (rtval[1] << 8); /* little endian order */
+ else
+ address = rtval[1] + (rtval[0] << 8); /* big endian order */
+
+ /* If this area doesn't have an image buffer, create one */
+ if (!ap->a_image)
+ {
+ if (ap->a_flag & A3_ABS)
+ ap->a_imagesize = ap->a_addr + ap->a_size;
+ else
+ ap->a_imagesize = ap->a_size;
+ ap->a_image = new (ap->a_imagesize);
+ if (ap->a_flag & A3_ABS)
+ ap->a_used = new (ap->a_imagesize);
+ }
+
+ /* Copy the data into the image buffer */
+ for (i = 2; i < rtcnt ; i++)
+ {
+ if (rtflg[i])
+ {
+ if (address-ap->a_addr >= ap->a_imagesize)
+ {
+ a_uint newsize;
+
+ if (ap->a_flag & A3_ABS)
+ {
+ newsize = ap->a_imagesize;
+ while (address-ap->a_addr >= newsize)
+ newsize = (newsize & ~4095)+4096;
+ ap->a_image = (char *) realloc (ap->a_image, newsize);
+ ap->a_used = (char *) realloc (ap->a_used, newsize);
+ if (!ap->a_image || !ap->a_used)
+ {
+ fprintf (stderr, "Out of space!\n");
+ lkexit (ER_FATAL);
+ }
+ memset (ap->a_image+ap->a_imagesize, 0, newsize-ap->a_imagesize);
+ memset (ap->a_used+ap->a_imagesize, 0, newsize-ap->a_imagesize);
+ ap->a_imagesize = newsize;
+ }
+ else
+ {
+ fprintf (stderr, "Unexpected area %s overflow. Address = 0x%x but allocated range is 0x%x - 0x%x\n",
+ ap->a_id, address, ap->a_addr, ap->a_addr+ap->a_imagesize-1);
+ lkexit (ER_FATAL);
+ }
+ }
+ ap->a_image[address-ap->a_addr] = rtval[i];
+ if (ap->a_used)
+ ap->a_used[address-ap->a_addr] = 1;
+
+ /* Make note of the reset vector */
+ if (!(ap->a_flag & A_NOLOAD))
+ {
+ if (address == 0xfffe)
+ {
+ execStartMSB = rtval[i];
+ execStartMSBfound = 1;
+ }
+ if (address == 0xffff)
+ {
+ execStartLSB = rtval[i];
+ execStartLSBfound = 1;
+ }
+ }
+ address++;
+ }
+ }
+ }
+ else
+ elfGenerate();
+}
--- /dev/null
+/* lkeval.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+#include "aslink.h"
+
+/*)Module lkeval.c
+ *
+ * The module lkeval.c contains the routines to evaluate
+ * arithmetic/numerical expressions. The functions in
+ * lkeval.c perform a recursive evaluation of the arithmetic
+ * expression read from the input text line.
+ * The expression may include binary/unary operators, brackets,
+ * symbols, labels, and constants in hexadecimal, decimal, octal
+ * and binary. Arithmetic operations are prioritized and
+ * evaluated by normal arithmetic conventions.
+ *
+ * lkeval.c contains the following functions:
+ * int digit()
+ * a_uint eval()
+ * a_uint expr()
+ * int oprio()
+ * a_uint term()
+ *
+ * lkeval.c contains no local/static variables
+ */
+
+/*)Function a_uint eval()
+ *
+ * The function eval() evaluates a character string to a
+ * numerical value.
+ *
+ * Notes about the arithmetic:
+ * The coding emulates X-Bit unsigned
+ * arithmetic operations. This allows
+ * program compilation without regard to the
+ * intrinsic integer length of the host
+ * machine.
+ *
+ * local variables:
+ * int c character from input string
+ * int v value of character in current radix
+ * a_uint n evaluation value
+ *
+ * global variables:
+ * int radix current number conversion radix
+ *
+ * functions called:
+ * int digit() lkeval.c
+ * int get() lklex.c
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * Input test is scanned and evaluated to a
+ * numerical value.
+ */
+
+a_uint
+eval(void)
+{
+ int c, v;
+ a_uint n;
+
+ c = getnb();
+ n = 0;
+ while ((v = digit(c, radix)) >= 0) {
+ n = n*radix + v;
+ c = get();
+ }
+ unget(c);
+ return (n & a_mask);
+}
+
+/*)Function a_uint expr(n)
+ *
+ * int n a firewall priority; all top
+ * level calls (from the user)
+ * should be made with n set to 0.
+ *
+ * The function expr() evaluates an expression and
+ * returns the value.
+ *
+ * Notes about the arithmetic:
+ * The coding emulates X-Bit unsigned
+ * arithmetic operations. This allows
+ * program compilation without regard to the
+ * intrinsic integer length of the host
+ * machine.
+ *
+ * local variables:
+ * int c current input text character
+ * int p current operator priority
+ * a_uint v value returned by term()
+ * a_uint ve value returned by a
+ * recursive call to expr()
+ *
+ * global variables:
+ * char ctype[] array of character types, one per
+ * ASCII character
+ * int lkerr error flag
+ * FILE * stderr c_library
+ *
+ * functions called:
+ * VOID expr() lkeval.c
+ * int fprintf() c_library
+ * int getnb() lklex.c
+ * int oprio() lkeval.c
+ * VOID term() lkeval.c
+ * VOID unget() lklex.c
+ *
+ *
+ * side effects:
+ * An expression is evaluated by scanning the input
+ * text string.
+ */
+
+a_uint
+expr (int n)
+{
+ int c, p;
+ a_uint v, ve;
+
+ v = term();
+ while (ctype[c = getnb()] & BINOP) {
+ if ((p = oprio(c)) <= n)
+ break;
+ if ((c == '>' || c == '<') && c != get()) {
+ fprintf(stderr, "Invalid expression");
+ lkerr++;
+ return(v);
+ }
+ ve = expr(p);
+
+ /*
+ * X-Bit Unsigned Arithmetic
+ */
+ v &= a_mask;
+ ve &= a_mask;
+
+ if (c == '+') {
+ v += ve;
+ } else
+ if (c == '-') {
+ v -= ve;
+ } else {
+ switch (c) {
+
+ case '*':
+ v *= ve;
+ break;
+
+ case '/':
+ if (ve == 0) {
+ v = 0;
+ } else {
+ v /= ve;
+ }
+ break;
+
+ case '&':
+ v &= ve;
+ break;
+
+ case '|':
+ v |= ve;
+ break;
+
+ case '%':
+ if (ve == 0) {
+ v = 0;
+ } else {
+ v %= ve;
+ }
+ break;
+
+ case '^':
+ v ^= ve;
+ break;
+
+ case '<':
+ v <<= ve;
+ break;
+
+ case '>':
+ v >>= ve;
+ break;
+ }
+ }
+ v = (v & a_mask);
+ }
+ unget(c);
+ return(v);
+}
+
+/*)Function a_uint term()
+ *
+ * The function term() evaluates a single constant
+ * or symbol value prefaced by any unary operator
+ * ( +, -, ~, ', ", >, or < ).
+ *
+ * Notes about the arithmetic:
+ * The coding emulates X-Bit unsigned
+ * arithmetic operations. This allows
+ * program compilation without regard to the
+ * intrinsic integer length of the host
+ * machine.
+ *
+ * local variables:
+ * int c current character
+ * char id[] symbol name
+ * int n value of digit in current radix
+ * int r current evaluation radix
+ * sym * sp pointer to a sym structure
+ * a_uint v evaluation value
+ *
+ * global variables:
+ * char ctype[] array of character types, one per
+ * ASCII character
+ * int lkerr error flag
+ *
+ * functions called:
+ * int digit() lkeval.c
+ * VOID expr() lkeval.c
+ * int fprintf() c_library
+ * int get() lklex.c
+ * VOID getid() lklex.c
+ * int getmap() lklex.c
+ * int getnb() lklex.c
+ * sym * lkpsym() lksym.c
+ * a_uint symval() lksym.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * An arithmetic term is evaluated by scanning input text.
+ */
+
+a_uint
+term(void)
+{
+ int c, r, n;
+ a_uint v;
+ struct sym *sp;
+ char id[NCPS];
+
+ c = getnb();
+ if (c == '#') { c = getnb(); }
+ if (c == '(') {
+ v = expr(0);
+ if (getnb() != ')') {
+ fprintf(stderr, "Missing delimiter");
+ lkerr++;
+ }
+ return(v);
+ }
+ if (c == '-') {
+ return(~expr(100)+1);
+ }
+ if (c == '~') {
+ return(~expr(100));
+ }
+ if (c == '\'') {
+ v = getmap(-1)&0377;
+ c = get();
+ if (c != '\'') { unget(c); }
+ return(v);
+ }
+ if (c == '\"') {
+ if (hilo) {
+ v = (getmap(-1)&0377)<<8;
+ v |= getmap(-1)&0377;
+ } else {
+ v = getmap(-1)&0377;
+ v |= (getmap(-1)&0377)<<8;
+ }
+ c = get();
+ if (c != '\"') { unget(c); }
+ return(v & a_mask);
+ }
+ if (c == '>' || c == '<') {
+ v = expr(100);
+ if (c == '>')
+ v >>= 8;
+ return(v&0377);
+ }
+ if (ctype[c] & DIGIT) {
+ r = 10;
+ if (c == '0') {
+ c = get();
+ switch (c) {
+ case 'b':
+ case 'B':
+ r = 2;
+ c = get();
+ break;
+ case '@':
+ case 'o':
+ case 'O':
+ case 'q':
+ case 'Q':
+ r = 8;
+ c = get();
+ break;
+ case 'd':
+ case 'D':
+ r = 10;
+ c = get();
+ break;
+ case 'h':
+ case 'H':
+ case 'x':
+ case 'X':
+ r = 16;
+ c = get();
+ break;
+ default:
+ break;
+ }
+ }
+ v = 0;
+ while ((n = digit(c, r)) >= 0) {
+ v = r*v + n;
+ c = get();
+ }
+ unget(c);
+ return(v & a_mask);
+ }
+ if (ctype[c] & LETTER) {
+ getid(id, c);
+ if ((sp = lkpsym(id, 0)) == NULL) {
+ fprintf(stderr, "Undefined symbol %s\n", id);
+ lkerr++;
+ return(0);
+ } else {
+ return(symval(sp));
+ }
+ }
+ fprintf(stderr, "Unknown operator %c\n", c);
+ lkerr++;
+ return(0);
+}
+
+/*)Function int digit(c, r)
+ *
+ * int c digit character
+ * int r current radix
+ *
+ * The function digit() returns the value of c
+ * in the current radix r. If the c value is not
+ * a number of the current radix then a -1 is returned.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * char ctype[] array of character types, one per
+ * ASCII character
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+int
+digit(int c, int r)
+{
+ if (r == 16) {
+ if (ctype[c] & RAD16) {
+ if (c >= 'A' && c <= 'F')
+ return (c - 'A' + 10);
+ if (c >= 'a' && c <= 'f')
+ return (c - 'a' + 10);
+ return (c - '0');
+ }
+ } else
+ if (r == 10) {
+ if (ctype[c] & RAD10)
+ return (c - '0');
+ } else
+ if (r == 8) {
+ if (ctype[c] & RAD8)
+ return (c - '0');
+ } else
+ if (r == 2) {
+ if (ctype[c] & RAD2)
+ return (c - '0');
+ }
+ return (-1);
+}
+
+/*)Function int oprio(c)
+ *
+ * int c operator character
+ *
+ * The function oprio() returns a relative priority
+ * for all valid unary and binary operators.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+int
+oprio(int c)
+{
+ if (c == '*' || c == '/' || c == '%')
+ return (10);
+ if (c == '+' || c == '-')
+ return (7);
+ if (c == '<' || c == '>')
+ return (5);
+ if (c == '^')
+ return (4);
+ if (c == '&')
+ return (3);
+ if (c == '|')
+ return (1);
+ return (0);
+}
--- /dev/null
+/* lkhead.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+#include "aslink.h"
+
+/*Module lkhead.c
+ *
+ * The module lkhead.c contains the function newhead() which
+ * creates a head structure, the function module() which
+ * loads the module name into the current head structure,
+ * and newmode() which loads the linker merge modes.
+ *
+ * lkhead.c contains the following functions:
+ * VOID newhead()
+ * VOID newmode()
+ * VOID module()
+ *
+ * lkhead.c contains no local variables.
+ */
+
+/*)Function VOID newhead()
+ *
+ * The function newhead() creates a head structure. All head
+ * structures are linked to form a linked list of head structures
+ * with the current head structure at the tail of the list.
+ *
+ * local variables:
+ * int i evaluation value
+ * char id[] temporary string
+ * head * thp temporary pointer
+ * to a header structure
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * lfile *cfp The pointer *cfp points to the
+ * current lfile structure
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * head *hp Pointer to the current
+ * head structure
+ *
+ * functions called:
+ * a_uint expr() lkeval.c
+ * a_uint eval() lkeval.c
+ * VOID getid() lklex.c
+ * VOID * new() lksym.c
+ * VOID lkparea() lkarea.c
+ * int more() lklex.c
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * A new head structure is created and linked to any
+ * existing linked head structure. The head structure
+ * parameters of file handle, number of areas, number
+ * of global symbols, number of banks and number of
+ * merge modes are loaded into the structure. The
+ * area, bank, symbol, and mode structure lists are created.
+ * The default area "_abs_" is created when the first
+ * head structure is created and an areax structure is
+ * created for every head structure called.
+ */
+
+/*
+ * Create a new header entry.
+ *
+ * H n areas n global symbols n banks n modes
+ * | | | |
+ * | | | `----- G Lines
+ * | | `------------- B Lines
+ * | `------------------------------ hp->h_nsym
+ * `-------------------------------------- hp->h_narea
+ *
+ */
+VOID
+newhead()
+{
+ int i;
+ char id[NCPS];
+ struct head *thp;
+
+ hp = (struct head *) new (sizeof(struct head));
+ if (headp == NULL) {
+ headp = hp;
+ } else {
+ thp = headp;
+ while (thp->h_hp)
+ thp = thp->h_hp;
+ thp->h_hp = hp;
+ }
+ /*
+ * Initialize the header
+ */
+ hp->h_lfile = cfp; /* Set file pointer */
+ hp->m_id = ""; /* No Module */
+ /*
+ * Scan for Parameters
+ */
+ while (more()) {
+ i = (int) eval();
+ getid(id, -1);
+ /*
+ * Area pointer list
+ */
+ if (symeq("areas", id, 1)) {
+ hp->h_narea = i;
+ if (i)
+ hp->a_list = (struct areax **) new (i*sizeof(struct areax *));
+ } else
+ /*
+ * Symbol pointer list
+ */
+ if (symeq("global", id, 1)) {
+ hp->h_nsym = i;
+ if (i)
+ hp->s_list = (struct sym **) new (i*sizeof(struct sym *));
+ skip(-1);
+ } else
+ /*
+ * Bank pointer list
+ */
+ if (symeq("banks", id, 1)) {
+ hp->h_nbank = i;
+ if (i)
+ hp->b_list = (struct bank **) new (i*sizeof(struct bank *));
+ } else
+ /*
+ * Mode pointer list
+ */
+ if (symeq("modes", id, 1)) {
+ hp->h_nmode = i;
+ if (i)
+ hp->m_list = (struct mode **) new (i*sizeof(struct mode *));
+ }
+ }
+ /*
+ * Setup Absolute DEF linkage.
+ */
+ lkparea(_abs_);
+ ap->a_flag = A3_ABS;
+ axp->a_addr = 0;
+}
+
+
+/*)Function VOID newmode()
+ *
+ * The function newmode() creates / fills in a merge mode
+ * definition for this module.
+ *
+ * The MODE structure contains the specification of one of the
+ * assemblers' relocation modes. Each assembler must specify
+ * at least one relocation mode. The relocation specification
+ * allows arbitrarily defined active bits and bit positions.
+ * The 32 element arrays are indexed from 0 to 31.
+ * Index 0 corresponds to bit 0, ..., and 31 corresponds to bit 31
+ * of a normal integer value.
+ *
+ * The value an array element defines if the normal integer bit is
+ * active (bit <7> is set, 0x80) and what destination bit
+ * (bits <4:0>, 0 - 31) should be loaded with this normal
+ * integer bit.
+ *
+ * The mode structure also contains a flag indicating if bit
+ * positioning is required, a mask word containing the active
+ * bits for merging, and an address paging mask.
+ *
+ * local variables:
+ * int index bit index of mode definition
+ * int n counter
+ * struct mode *mp pointer to a mode structure
+ *
+ * global variables:
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * head *hp Pointer to the current
+ * head structure
+ * FILE * stderr standard library error handle
+ *
+ * functions called:
+ * a_uint eval() lkexpr.c
+ * int fprintf() c_library
+ * VOID lkexit() lkmain.c
+ * int more() lklex.c
+ * char * new() lksym.c
+ *
+ * side effects:
+ * The merge mode structure is created / updated with
+ * the definition values.
+ */
+
+VOID
+newmode()
+{
+ int index, n;
+ a_uint v;
+ struct mode *mp;
+
+ if (headp == NULL) {
+ fprintf(stderr, "No header defined\n");
+ lkexit(ER_FATAL);
+ }
+ /*
+ * Mode number
+ */
+ n = (int) eval();
+ if (n >= hp->h_nmode) {
+ fprintf(stderr, "Header mode list overflow\n");
+ lkexit(ER_FATAL);
+ }
+ /*
+ * Bit index
+ */
+ index = (int) eval();
+ if (index == 0) {
+ mp = (struct mode *) new (sizeof(struct mode));
+ hp->m_list[n] = mp;
+ /*
+ * Initialize Mode
+ */
+ for (n=0; n<32; n++) {
+ mp->m_def[n] = n;
+ }
+ } else {
+ mp = hp->m_list[n];
+ }
+ /*
+ * Load Bits
+ */
+ while (more() && (index < 32)) {
+ n = (int) eval();
+ if (mp->m_def[index] != (n & 0x1F)) {
+ mp->m_flag |= 1;
+ }
+ mp->m_def[index] = n;
+ if (n & 0x80) {
+ mp->m_dbits |= (((a_uint) 1) << (n & 0x1F));
+ mp->m_sbits |= (((a_uint) 1) << index);
+ }
+ index += 1;
+ }
+ /*
+ * Set Missing Low Order Bits
+ */
+ for (n=0; n<32; n++) {
+ v = 1 << n;
+ if (mp->m_sbits & v) {
+ break;
+ } else {
+ mp->m_sbits |= v;
+ }
+ }
+}
+
+
+/*)Function VOID module()
+ *
+ * The function module() copies the module name into
+ * the current head structure.
+ *
+ * local variables:
+ * char id[] module id string
+ *
+ * global variables:
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * head *hp Pointer to the current
+ * head structure
+ * int lkerr error flag
+ * FILE * stderr c_library
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID getid() lklex.c
+ * char * strsto() lksym.c
+ *
+ * side effects:
+ * The module name is copied into the head structure.
+ */
+
+VOID
+module()
+{
+ char id[NCPS];
+
+ if (headp) {
+ getid(id, -1);
+ hp->m_id = strsto(id);
+ } else {
+ fprintf(stderr, "No header defined\n");
+ lkerr++;
+ }
+}
--- /dev/null
+/* lkihx.c
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include "sdld.h"
+#include "aslink.h"
+
+/*)Module lkihx.c
+ *
+ * The module lkihx.c contains the function to
+ * output the relocated object code in the
+ * Intel Hex format.
+ *
+ * lkihx.c contains the following functions:
+ * VOID hexRecord(addr, rtvalIndex)
+ * VOID ihx(i)
+ * VOID ihxExtendedLinearAddress(a)
+ *
+ * local variables: hexPageOverrun, lastHexAddr
+ */
+
+/*Intel Format
+ * Record Mark Field - This field signifies the start of a
+ * record, and consists of an ascii colon
+ * (:).
+ *
+ * Record Length Field - This field consists of two ascii
+ * characters which indicate the number of
+ * data bytes in this record. The
+ * characters are the result of converting
+ * the number of bytes in binary to two
+ * ascii characters, high digit first. An
+ * End of File record contains two ascii
+ * zeros in this field.
+ *
+ * Load Address Field - This field consists of the four ascii
+ * characters which result from converting
+ * the the binary value of the address in
+ * which to begin loading this record. The
+ * order is as follows:
+ *
+ * High digit of high byte of address.
+ * Low digit of high byte of address.
+ * High digit of low byte of address.
+ * Low digit of low byte of address.
+ *
+ * In an End of File record this field con-
+ * sists of four ascii zeros, in a start
+ * address record this is the program entry
+ * address (low), or in a segment record
+ * this is the high order address.
+ *
+ * Record Type Field - This field identifies the record type,
+ * which is either 0 for data records, 1
+ * for an End of File record, 3 for a
+ * start address, or 4 for a
+ * segment record. It consists
+ * of two ascii characters, with the high
+ * digit of the record type first, followed
+ * by the low digit of the record type.
+ *
+ * Data Field - This field consists of the actual data,
+ * converted to two ascii characters, high
+ * digit first. There are no data bytes in
+ * the End of File record.
+ *
+ * Checksum Field - The checksum field is the 8 bit binary
+ * sum of the record length field, the load
+ * address field, the record type field,
+ * and the data field. This sum is then
+ * negated (2's complement) and converted
+ * to two ascii characters, high digit
+ * first.
+ */
+
+/* Static variable which holds the count of hex page overruns
+ * (crossings of the 64kB boundary). Cleared at explicit extended
+ * address output.
+ */
+static int hexPageOverrun = 0;
+
+/* Global which holds the last (16 bit) address of hex record.
+ * Cleared at begin of new area or when the extended address is output.
+ */
+unsigned int lastHexAddr = 0;
+
+
+/*)Function hexRecord(addr, rtvalIndex)
+ *
+ * unsigned addr starting address of hex record
+ * int rtvalIndex starting index into the rtval[] array
+ *
+ * The function hexRecord() outputs the relocated data
+ * in the standard Intel Hex format (with inserting
+ * the extended address record if necessary).
+ *
+ * local variables:
+ * a_uint chksum byte checksum
+ * int i index for loops
+ * int overrun temporary storage for hexPageOverrun
+ * int bytes counter for bytes written
+ *
+ * global variables:
+ * FILE * ofp output file handle
+ * int rtcnt count of data words
+ * int rtflg[] output the data flag
+ * a_uint rtval[] relocated data
+ *
+ * functions called:
+ * int fprintf() c_library
+ * ihxExtendedLinearAddress() lkihx.c
+ * hexRecord() lkihx.c (recursion)
+ *
+ * side effects:
+ * hexPageOverrun is eventually incremented,
+ * lastHexAddr is updated
+ */
+
+VOID
+hexRecord(unsigned addr, int rtvalIndex)
+{
+ a_uint chksum;
+ int i, overrun, bytes;
+
+ for (i = rtvalIndex, chksum = 0; i < rtcnt; i++) {
+ if (rtflg[i]) {
+ if (addr + ++chksum > 0xffff)
+ break;
+ }
+ }
+ if (chksum == 0)
+ return; // nothing to output
+
+ /* Is this record in the same bank as previous? */
+ if ((TARGET_IS_8051 && ((lastHexAddr>>16) != (addr>>16)) && (rflag)) ||
+ (TARGET_IS_6808 && lastHexAddr > addr) {
+ overrun = hexPageOverrun + 1;
+ ihxExtendedLinearAddress(lastExtendedAddress + overrun);
+ hexPageOverrun = overrun;
+ hexRecord(addr, rtvalIndex);
+ return;
+ }
+
+ lastHexAddr = addr;
+ fprintf(ofp, "%02X:%02X%04X00", addr >>16, chksum, addr);
+ chksum += (addr >> 8) + (addr & 0xff);
+ for (i = rtvalIndex, bytes = 0; i < rtcnt; i++) {
+ if (rtflg[i]) {
+ fprintf(ofp, "%02X", rtval[i]);
+ chksum += rtval[i];
+ if (TARGET_IS_8051) {
+ if (addr + ++bytes > 0xffff) {
+ if (rflag) {
+ fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
+ overrun = hexPageOverrun + 1;
+ ihxExtendedLinearAddress(lastExtendedAddress + overrun);
+ hexPageOverrun = overrun;
+ hexRecord(0, i + 1);
+ return;
+ } else {
+ fprintf(stderr,
+ "warning: extended linear address encountered; "
+ "you probably want the -r flag.\n");
+ }
+ }
+ }
+ }
+ }
+ fprintf(ofp, "%02X\n", (0-chksum) & 0xff);
+}
+
+/*)Function ihx(i)
+ *
+ * int i 0 - process data
+ * 1 - end of data
+ *
+ * The function ihx() calls the hexRecord() function for processing data
+ * or writes the End of Data record to the file defined by ofp.
+ *
+ * local variables:
+ * a_uint n auxiliary variable
+ *
+ * global variables:
+ * int hilo byte order
+ * FILE * ofp output file handle
+ * a_uint rtval[] relocated data
+ *
+ * functions called:
+ * VOID hexRecord() lkihx.c
+ * int fprintf() c_library
+ *
+ * side effects:
+ * The sequence of rtval[0], rtval[1] is eventually changed.
+ */
+
+VOID
+ihx(int i)
+{
+ a_uint n;
+ if (i) {
+ if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
+ return;
+
+ if (hilo == 0) {
+ n = rtval[0];
+ rtval[0] = rtval[1];
+ rtval[1] = n;
+ }
+ hexRecord((rtval[0]<<8) + rtval[1], 2);
+ } else {
+ if (TARGET_IS_8051 && rflag) /* linear start address, hardcoded as reset vector (0x0000) */
+ fprintf(ofp, ":0400000500000000F7\n");
+ fprintf(ofp, ":00000001FF\n");
+ }
+}
+
+/*)Function ihxNewArea(i)
+ * The function ihxNewArea() is called when processing of new area is started.
+ * It resets the value of lastHexAddr.
+ */
+
+VOID
+ihxNewArea()
+{
+ lastHexAddr = 0;
+}
+
+/*)Function ihxExtendedLinearAddress(i)
+ *
+ * a_uint i 16 bit extended linear address.
+ *
+ * The function ihxExtendedLinearAddress() writes an extended
+ * linear address record (type 04) to the output file.
+ *
+ * local variables:
+ * a_uint chksum byte checksum
+ *
+ * global variables:
+ * FILE * ofp output file handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * The data is output to the file defined by ofp.
+ * hexPageOverrun and lastHexAddr is cleared
+ */
+VOID
+ihxExtendedLinearAddress(a_uint a)
+{
+ a_uint chksum;
+
+ /* The checksum is the complement of the bytes in the
+ * record: the 2 is record length, 4 is the extended linear
+ * address record type, plus the two address bytes.
+ */
+ chksum = 2 + 4 + (a & 0xff) + ((a >> 8) & 0xff);
+
+ fprintf(ofp, ":02000004%04X%02X\n", a & 0xffff, (0-chksum) & 0xff);
+ hexPageOverrun = 0;
+ lastHexAddr = 0;
+}
--- /dev/null
+/* lklex.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+#include "aslink.h"
+
+/*)Module lklex.c
+ *
+ * The module lklex.c contains the general lexical analysis
+ * functions used to scan the text lines from the .rel files.
+ *
+ * lklex.c contains the following functions:
+ * VOID chopcrlf()
+ * char endline()
+ * int get()
+ * VOID getfid()
+ * VOID getid()
+ * VOID getSid()
+ * int getmap()
+ * int getnb()
+ * int more()
+ * int nxtline()
+ * VOID skip()
+ * VOID unget()
+ *
+ * lklex.c contains no local variables.
+ */
+
+/*)Function VOID getid(id,c)
+ *
+ * char * id a pointer to a string of
+ * maximum length NCPS-1
+ * int c mode flag
+ * >=0 this is first character to
+ * copy to the string buffer
+ * <0 skip white space
+ *
+ * The function getid() scans the current input text line
+ * from the current position copying the next LETTER | DIGIT string
+ * into the external string buffer (id). The string ends when a non
+ * LETTER or DIGIT character is found. The maximum number of characters
+ * copied is NCPS-1. If the input string is larger than NCPS-1
+ * characters then the string is truncated. The string is always
+ * NULL terminated. If the mode argument (c) is >=0 then (c) is
+ * the first character copied to the string buffer, if (c) is <0
+ * then intervening white space (SPACES and TABS) are skipped.
+ *
+ * local variables:
+ * char * p pointer to external string buffer
+ * int c current character value
+ *
+ * global variables:
+ * char ctype[] a character array which defines the
+ * type of character being processed.
+ * This index is the character
+ * being processed.
+ *
+ * called functions:
+ * int get() lklex.c
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * use of getnb(), get(), and unget() updates the
+ * global pointer ip the position in the current
+ * input text line.
+ */
+
+VOID
+getid(char *id, int c)
+{
+ char *p;
+
+ if (c < 0) {
+ c = getnb();
+ }
+ p = id;
+ do {
+ if (p < &id[NCPS-1])
+ *p++ = c;
+ } while (ctype[c=get()] & (LETTER|DIGIT));
+ unget(c);
+ *p++ = 0;
+}
+
+/*)Function VOID getSid (char *id)
+ *
+ * char * id a pointer to a string of
+ * maximum length NCPS-1
+ *
+ * getSid is derived from getid. It is called from newsym()
+ * in lksym.c, when an S-record has to be scanned. getSid accepts
+ * much more characters than getid, which is necessary for SDCC.
+ *
+ * The function getSid() scans the current input text line
+ * from the current position copying the next string
+ * into the external string buffer (id). The string ends when a space
+ * character (space, tab, \0) is found. The maximum number of
+ * characters copied is NCPS. If the input string is larger than
+ * NCPS characters then the string is truncated, if the input string
+ * is shorter than NCPS characters then the string is NULL filled.
+ * Intervening white space (SPACES and TABS) are skipped.
+ *
+ * local variables:
+ * char * p pointer to external string buffer
+ * int c current character value
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * int get() lklex.c
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * use of getnb(), get(), and unget() updates the
+ * global pointer ip the position in the current
+ * input text line.
+ */
+
+VOID
+getSid (char *id)
+{
+ int c;
+ char *p;
+
+ c = getnb();
+ p = id;
+ do {
+ if (p < &id[NCPS-1])
+ *p++ = c;
+ c = get();
+ } while (c != '\0' && c != ' ' && c != '\t');
+ unget(c);
+ *p++ = 0;
+}
+
+/*)Function VOID getfid(str,c)
+ *
+ * char * str a pointer to a string of
+ * maximum length FILSPC-1
+ * int c this is first character to
+ * copy to the string buffer
+ *
+ * asxxxx version:
+ *
+ * The function getfid() copies a string of characters from
+ * the current text line into the external string buffer (str).
+ * The maximum number of characters copied is FILSPC-1. The
+ * string is terminated by a 'space', 'tab' or end of string.
+ *
+ * sdld version:
+ *
+ * The function getfid() scans the current input text line from
+ * the current position copying the next string into the external
+ * string buffer (str). The string ends when end of line is found.
+ * Trailing spaces are removed. The maximum number of characters
+ * copied is FILSPC-1. If the input string is larger than FILSPC-1
+ * characters then the string is truncated. The string is NULL
+ * terminated.
+ *
+ * local variables:
+ * char * p pointer to external string buffer
+ * int c current character value
+ *
+ * global variables:
+ * char ctype[] a character array which defines the
+ * type of character being processed.
+ * This index is the character
+ * being processed.
+ *
+ * called functions:
+ * int get() lklex.c
+ *
+ * side effects:
+ * use of get() updates the global pointer ip
+ * the position in the current input text line.
+ */
+
+VOID
+getfid(char *str, int c)
+{
+ char *p;
+
+ p = str;
+ if (!is_sdld()) {
+ do {
+ if (p < &str[FILSPC-1])
+ *p++ = c;
+ c = get();
+ } while ((c != 0) && (c != ' ') && (c != '\t'));
+ *p++ = 0;
+ }
+ else {
+ do {
+ if (p < &str[FILSPC-1])
+ *p++ = c;
+ c = get();
+ /* skip comment */
+ if (c == ';')
+ while (c)
+ c = get();
+ } while (c);
+ /* trim trailing spaces */
+ --p;
+ while (p >= str && ctype[*p & 0x007F] == SPACE)
+ --p;
+ /* terminate the string */
+ *(++p) = '\0';
+ }
+}
+
+/*)Function int getnb()
+ *
+ * The function getnb() scans the current input text
+ * line returning the first character not a SPACE or TAB.
+ *
+ * local variables:
+ * int c current character from input
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * int get() lklex.c
+ *
+ * side effects:
+ * use of get() updates the global pointer ip, the position
+ * in the current input text line
+ */
+
+int
+getnb()
+{
+ int c;
+
+ while ((c=get())==' ' || c=='\t')
+ ;
+ return (c);
+}
+
+/*)Function VOID skip(c)
+ *
+ * The function skip() scans the input text skipping all
+ * letters and digits.
+ *
+ * local variables:
+ * int c last character read
+ * none
+ *
+ * global variables:
+ * char ctype[] array of character types, one per
+ * ASCII character
+ *
+ * functions called:
+ * int get() lklex.c
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * Input letters and digits are skipped.
+ */
+
+VOID
+skip(c)
+int c;
+{
+ if (c < 0)
+ c = getnb();
+ while (ctype[c=get()] & (LETTER|DIGIT)) { ; }
+ unget(c);
+}
+
+/*)Function int get()
+ *
+ * The function get() returns the next character in the
+ * input text line, at the end of the line a
+ * NULL character is returned.
+ *
+ * local variables:
+ * int c current character from
+ * input text line
+ *
+ * global variables:
+ * char * ip pointer into the current
+ * input text line
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * updates ip to the next character position in the
+ * input text line. If ip is at the end of the
+ * line, ip is not updated.
+ */
+
+int
+get()
+{
+ int c;
+
+ if ((c = *ip) != 0)
+ ++ip;
+ return (c & 0x007F);
+}
+
+/*)Function VOID unget(c)
+ *
+ * int c value of last character
+ * read from input text line
+ *
+ * If (c) is not a NULL character then the global pointer ip
+ * is updated to point to the preceeding character in the
+ * input text line.
+ *
+ * NOTE: This function does not push the character (c)
+ * back into the input text line, only
+ * the pointer ip is changed.
+ *
+ * local variables:
+ * int c last character read
+ * from input text line
+ *
+ * global variables:
+ * char * ip position into the current
+ * input text line
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * ip decremented by 1 character position
+ */
+
+VOID
+unget(c)
+int c;
+{
+ if (c != 0)
+ --ip;
+}
+
+/*)Function int getmap(d)
+ *
+ * int d value to compare with the
+ * input text line character
+ *
+ * The function getmap() converts the 'C' style characters \b, \f,
+ * \n, \r, and \t to their equivalent ascii values and also
+ * converts 'C' style octal constants '\123' to their equivalent
+ * numeric values. If the first character is equivalent to (d) then
+ * a (-1) is returned, if the end of the line is detected then
+ * a 'q' error terminates the parse for this line, or if the first
+ * character is not a \ then the character value is returned.
+ *
+ * local variables:
+ * int c value of character
+ * from input text line
+ * int n looping counter
+ * int v current value of numeric conversion
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * int get() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * use of get() updates the global pointer ip the position
+ * in the current input text line
+ */
+
+int
+getmap(d)
+int d;
+{
+ int c, n, v;
+
+ if ((c = get()) == '\0')
+ return (-1);
+ if (c == d)
+ return (-1);
+ if (c == '\\') {
+ c = get();
+ switch (c) {
+
+ case 'b':
+ c = '\b';
+ break;
+
+ case 'f':
+ c = '\f';
+ break;
+
+ case 'n':
+ c = '\n';
+ break;
+
+ case 'r':
+ c = '\r';
+ break;
+
+ case 't':
+ c = '\t';
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ n = 0;
+ v = 0;
+ while (++n<=3 && c>='0' && c<='7') {
+ v = (v<<3) + c - '0';
+ c = get();
+ }
+ unget(c);
+ c = v;
+ break;
+ }
+ }
+ return (c);
+}
+
+/*)Function int nxtline()
+ *
+ * The function nxtline() reads a line of input text from a
+ * .rel source text file, a .lnk command file or from stdin.
+ * Lines of text are processed from a single .lnk file or
+ * multiple .rel files until all files have been read.
+ * The input text line is copied into the global string ib[]
+ * and converted to a NULL terminated string. The function
+ * nxtline() returns a (1) after succesfully reading a line
+ * or a (0) if all files have been read.
+ * This function also opens each input .lst file and output
+ * .rst file as each .rel file is processed.
+ *
+ * local variables:
+ * int ftype file type
+ * char * fid file name
+ *
+ * global variables:
+ * lfile *cfp The pointer *cfp points to the
+ * current lfile structure
+ * lfile *filep The pointer *filep points to the
+ * beginning of a linked list of
+ * lfile structures.
+ * int gline get a line from the LST file
+ * to translate for the RST file
+ * char ib[NINPUT] REL file text line
+ * int pass linker pass number
+ * int pflag print linker command file flag
+ * FILE *rfp The file handle to the current
+ * output RST file
+ * FILE *sfp The file handle sfp points to the
+ * currently open file
+ * FILE * stdin c_library
+ * FILE * stdout c_library
+ * FILE *tfp The file handle to the current
+ * LST file being scanned
+ * int uflag update listing flag
+ * int obj_flag linked file/library object output flag
+ *
+ * called functions:
+ * VOID chopcrlf() lklex.c
+ * FILE * afile() lkmain.c
+ * int fclose() c_library
+ * char * fgets() c_library
+ * int fprintf() c_library
+ * VOID lkulist() lklist.c
+ * VOID lkexit() lkmain.c
+ *
+ * side effects:
+ * The input stream is scanned. The .rel files will be
+ * opened and closed sequentially scanning each in turn.
+ */
+
+int
+nxtline()
+{
+ int ftype;
+ char *fid;
+
+loop: if (pflag && cfp && cfp->f_type == F_STD)
+ fprintf(stdout, "ASlink >> ");
+
+ if (sfp == NULL || fgets(ib, sizeof(ib), sfp) == NULL) {
+ obj_flag = 0;
+ if (sfp) {
+ if(sfp != stdin) {
+ fclose(sfp);
+ }
+ sfp = NULL;
+ lkulist(0);
+ }
+ if (cfp == NULL) {
+ cfp = filep;
+ } else {
+ cfp = cfp->f_flp;
+ }
+ if (cfp) {
+ ftype = cfp->f_type;
+ fid = cfp->f_idp;
+ if (ftype == F_STD) {
+ sfp = stdin;
+ } else
+ if (ftype == F_LNK) {
+ sfp = afile(fid, strrchr(fid, FSEPX) ? "" : "lnk", 0);
+ } else
+ if (ftype == F_REL) {
+ obj_flag = cfp->f_obj;
+ sfp = afile(fid, "", 0);
+ if (sfp && (obj_flag == 0)) {
+ if (uflag && (pass != 0)) {
+ if (is_sdld())
+ SaveLinkedFilePath(fid); //Save the linked path for aomf51
+ if ((tfp = afile(fid, "lst", 0)) != NULL) {
+ if ((rfp = afile(fid, "rst", 1)) == NULL) {
+ fclose(tfp);
+ tfp = NULL;
+ }
+ }
+ }
+ }
+
+#if SDCDB
+ if (sfp && (pass == 0)) {
+ SDCDBcopy(fid);
+ }
+#endif
+
+ gline = 1;
+ } else {
+ fprintf(stderr, "Invalid file type\n");
+ lkexit(ER_FATAL);
+ }
+ if (sfp == NULL) {
+ lkexit(ER_FATAL);
+ }
+ goto loop;
+ } else {
+ filep = NULL;
+ return(0);
+ }
+ }
+ chopcrlf(ib);
+ return (1);
+}
+
+/*)Function int more()
+ *
+ * The function more() scans the input text line
+ * skipping white space (SPACES and TABS) and returns a (0)
+ * if the end of the line or a comment delimeter (;) is found,
+ * or a (1) if their are additional characters in the line.
+ *
+ * local variables:
+ * int c next character from
+ * the input text line
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * use of getnb() and unget() updates the global pointer ip
+ * the position in the current input text line
+ */
+
+int
+more()
+{
+ int c;
+
+ c = getnb();
+ unget(c);
+ return( (c == '\0' || c == ';') ? 0 : 1 );
+}
+
+/*)Function char endline()
+ *
+ * The function endline() scans the input text line
+ * skipping white space (SPACES and TABS) and returns the next
+ * character or a (0) if the end of the line is found or a
+ * comment delimiter (;) is found.
+ *
+ * local variables:
+ * int c next character from
+ * the input text line
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * int getnb() lklex.c
+ *
+ * side effects:
+ * Use of getnb() updates the global pointer ip the
+ * position in the current input text line.
+ */
+
+char
+endline()
+{
+ int c;
+
+ c = getnb();
+ return( (c == '\0' || c == ';') ? 0 : c );
+}
+
+/*)Function VOID chopcrlf(str)
+ *
+ * char *str string to chop
+ *
+ * The function chop_crlf() removes trailing LF or CR/LF from
+ * str, if present.
+ *
+ * local variables:
+ * int i string length
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+VOID
+chopcrlf(str)
+char *str;
+{
+ int i;
+
+ i = strlen(str);
+ if (i >= 1 && str[i-1] == '\n') str[i-1] = 0;
+ if (i >= 2 && str[i-2] == '\r') str[i-2] = 0;
+}
--- /dev/null
+/* lklib.c
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+ Copyright (C) 2008-2009 Borut Razem, borut dot razem at siol dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <string.h>
+
+#include "sdld.h"
+#include "lk_readnl.h"
+#include "aslink.h"
+#include "lklibr.h"
+#include "lkrel.h"
+
+static int
+is_lib (FILE * libfp)
+{
+ return 1;
+}
+
+#ifdef INDEXLIB
+/* buildlibraryindex - build an in-memory cache of the symbols contained in
+ * the libraries
+ */
+static pmlibraryfile
+buildlibraryindex_lib (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
+{
+ char relfil[NINPUT];
+
+ while (lk_readnl (relfil, sizeof (relfil), libfp) != NULL)
+ {
+ FILE *fp;
+ char str[PATH_MAX];
+
+ if (lbnh->path != NULL)
+ {
+ strcpy (str, lbnh->path);
+#ifdef OTHERSYSTEM
+ if ((*str != '\0') && (str[strlen (str) - 1] != '/') && (str[strlen (str) - 1] != LKDIRSEP))
+ {
+ strcat (str, LKDIRSEPSTR);
+ }
+#endif
+ }
+ else
+ str[0] = '\0';
+
+ if ((relfil[0] == '/') || (relfil[0] == LKDIRSEP))
+ {
+ strcat (str, relfil + 1);
+ }
+ else
+ {
+ strcat (str, relfil);
+ }
+
+ if (strchr (relfil, FSEPX) == NULL)
+ {
+ sprintf (&str[strlen (str)], "%c%s", FSEPX, LKOBJEXT);
+ }
+
+ if ((fp = fopen (str, "rb")) != NULL)
+ {
+ /* Opened OK - create a new libraryfile object for it */
+ if (libr == NULL)
+ {
+ libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+ }
+ else
+ {
+ This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+ This = This->next;
+ }
+ This->next = NULL;
+ This->loaded = -1;
+ This->libspc = lbnh->libspc;
+ This->relfil = strdup (relfil);
+ This->filspc = strdup (str);
+ This->type = type;
+
+ /* Start a new linked list of symbols for this module: */
+ This->symbols = NULL;
+
+ add_rel_index (fp, -1, This);
+ fclose (fp);
+ } /* Closes if object file opened OK */
+ else
+ {
+ fprintf (stderr, "?ASlink-Warning-Cannot open library module %s\n", str);
+ }
+ } /* Ends while - processing all in libr */
+
+ return This;
+}
+
+#else
+
+static int
+fndsym_lib (const char *name, struct lbname *lbnh, FILE * libfp, int type)
+{
+ char relfil[NINPUT];
+
+ D ("Searching symbol: %s\n", name);
+
+ while (lk_readnl (relfil, sizeof (relfil), libfp) != NULL)
+ {
+ char str[PATH_MAX];
+ FILE *fp;
+
+ if (lbnh->path != NULL)
+ {
+ strcpy (str, lbnh->path);
+#ifdef OTHERSYSTEM
+ if ((*str != '\0') && (str[strlen (str) - 1] != '/') && (str[strlen (str) - 1] != LKDIRSEP))
+ {
+ strcat (str, LKDIRSEPSTR);
+ }
+#endif
+ }
+ else
+ str[0] = '\0';
+
+ if ((relfil[0] == '/') || (relfil[0] == LKDIRSEP))
+ {
+ strcat (str, relfil + 1);
+ }
+ else
+ {
+ strcat (str, relfil);
+ }
+
+ if (strchr (relfil, FSEPX) == NULL)
+ {
+ sprintf (&str[strlen (str)], "%c%s", FSEPX, LKOBJEXT);
+ }
+
+ if ((fp = fopen (str, "rb")) != NULL)
+ {
+ /* Opened OK - create a new libraryfile object for it */
+ int ret = add_rel_file (name, lbnh, relfil, str, -1, fp, -1, type);
+ fclose (fp);
+ if (ret)
+ {
+ D ("Loaded module %s from file %s.\n", str, str);
+ /* if cdb information required & adb file present */
+ if (yflag && yfp)
+ {
+ FILE *xfp = afile (str, "adb", 0); //JCF: Nov 30, 2002
+ if (xfp)
+ {
+ SaveLinkedFilePath (str);
+ copyfile (yfp, xfp);
+ fclose (xfp);
+ }
+ }
+ return 1; /* Found the symbol, so success! */
+ }
+ } /* Closes if object file opened OK */
+ else
+ {
+ fprintf (stderr, "?ASlink-Warning-Cannot open library module %s\n", str);
+ }
+ } /* Ends while - processing all in libr */
+
+ return 0; /* The symbol is not in this library */
+}
+#endif
+
+/*)Function VOID loadfile_lib(filspc)
+ *
+ * char *filspc library object file specification
+ *
+ * The function loadfile() links the library object module.
+ *
+ * local variables:
+ * FILE *fp file handle
+ * int i input line length
+ * char str[] file input line
+ *
+ * global variables:
+ * char *ip pointer to linker input string
+ *
+ * functions called:
+ * int fclose() c_library
+ * char *lk_readnl() lk_readnl.c
+ * FILE * fopen() c_library
+ * VOID link_main() lkmain.c
+ * int strlen() c_library
+ *
+ * side effects:
+ * If file exists it is linked.
+ */
+
+static VOID
+loadfile_lib (struct lbfile *lbfh)
+{
+ FILE *fp;
+#ifdef __CYGWIN__
+ char posix_path[PATH_MAX];
+ void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
+ cygwin_conv_to_full_posix_path (lbfh->filspc, posix_path);
+ fp = fopen (posix_path, "rb");
+#else
+ fp = fopen (lbfh->filspc, "rb");
+#endif
+
+ if (fp != NULL)
+ {
+ load_rel (fp, -1);
+ fclose (fp);
+ }
+ else
+ {
+ fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->filspc);
+ fclose (fp);
+ lkexit (1);
+ }
+}
+
+struct aslib_target aslib_target_lib = {
+ &is_lib,
+#ifdef INDEXLIB
+ &buildlibraryindex_lib,
+#else
+ &fndsym_lib,
+#endif
+ &loadfile_lib,
+};
--- /dev/null
+/* lklibr.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenhat cmf dot nrl dot navy dot mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <ctype.h>
+#include <assert.h>
+
+#include "aslink.h"
+#include "lkrel.h"
+#include "lklibr.h"
+
+/*)Module lklibr.c
+ *
+ * The module lklibr.c contains the functions which
+ * (1) specify the path(s) to library files [.LIB]
+ * (2) specify the library file(s) [.LIB] to search
+ * (3) search the library files for specific symbols
+ * and link the module containing this symbol
+ *
+ * lklibr.c contains the following functions:
+ * VOID addpath()
+ * VOID addlib()
+ * VOID addfile()
+ * VOID search()
+ * VOID fndsym()
+ * VOID library()
+ * VOID loadfile()
+ *
+ */
+
+#define EQ(A,B) !strcmp((A),(B))
+#define NELEM(x) (sizeof (x) / sizeof (*x))
+
+#ifdef INDEXLIB
+/* First entry in the library object symbol cache */
+pmlibraryfile libr = NULL;
+
+int buildlibraryindex (void);
+void freelibraryindex (void);
+#endif /* INDEXLIB */
+
+struct aslib_target *aslib_targets[] = {
+ &aslib_target_sdcclib,
+ &aslib_target_ar,
+ &aslib_target_lib,
+};
+
+/*)Function VOID addpath()
+ *
+ * The function addpath() creates a linked structure containing
+ * the paths to various object module library files.
+ *
+ * local variables:
+ * lbpath *lbph pointer to new path structure
+ * lbpath *lbp temporary pointer
+ *
+ * global variables:
+ * lbpath *lbphead The pointer to the first
+ * path structure
+ *
+ * functions called:
+ * int getnb() lklex.c
+ * VOID * new() lksym.c
+ * int strlen() c_library
+ * char * strcpy() c_library
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * An lbpath structure may be created.
+ */
+
+VOID
+addpath (void)
+{
+ struct lbpath *lbph, *lbp;
+
+ lbph = (struct lbpath *) new (sizeof (struct lbpath));
+ if (lbphead == NULL)
+ {
+ lbphead = lbph;
+ }
+ else
+ {
+ lbp = lbphead;
+ while (lbp->next)
+ {
+ lbp = lbp->next;
+ }
+ lbp->next = lbph;
+ }
+ unget (getnb ());
+ lbph->path = strdup (ip);
+}
+
+/*)Function VOID addlib()
+ *
+ * The function addlib() tests for the existance of a
+ * library path structure to determine the method of
+ * adding this library file to the library search structure.
+ *
+ * This function calls the function addfile() to actually
+ * add the library file to the search list.
+ *
+ * local variables:
+ * lbpath *lbph pointer to path structure
+ *
+ * global variables:
+ * lbpath *lbphead The pointer to the first
+ * path structure
+ * ip a pointer to the library name
+ *
+ * functions called:
+ * VOID addfile() lklibr.c
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * The function addfile() may add the file to
+ * the library search list.
+ */
+
+VOID
+addlib (void)
+{
+ struct lbpath *lbph;
+ int foundcount = 0;
+
+ unget (getnb ());
+
+ if (lbphead == NULL)
+ {
+ foundcount = addfile (NULL, ip);
+ }
+ else
+ {
+ for (lbph = lbphead; lbph; lbph = lbph->next)
+ {
+ foundcount += addfile (lbph->path, ip);
+ }
+ }
+ if (foundcount == 0)
+ {
+ fprintf (stderr, "?ASlink-Warning-Couldn't find library '%s'\n", ip);
+ }
+}
+
+/*)Function int addfile(path,libfil)
+ *
+ * char *path library path specification
+ * char *libfil library file specification
+ *
+ * The function addfile() searches for the library file
+ * by concatenating the path and libfil specifications.
+ * if the library is found, an lbname structure is created
+ * and linked to any previously defined structures. This
+ * linked list is used by the function fndsym() to attempt
+ * to find any undefined symbols.
+ *
+ * The function does not report an error on invalid
+ * path / file specifications or if the file is not found.
+ *
+ * local variables:
+ * lbname *lbnh pointer to new name structure
+ * lbname *lbn temporary pointer
+ * char * str path / file string
+ * char * strend end of path pointer
+ * char * str path / file string
+ * char * strend end of path pointer
+ *
+ * global variables:
+ * lbname *lbnhead The pointer to the first
+ * path structure
+ * int objflg linked file/library object output flag
+ *
+ * functions called:
+ * int getnb() lklex.c
+ * VOID * new() lksym.c
+ * int strlen() c_library
+ * char * strcpy() c_library
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * An lbname structure may be created.
+ *
+ * return:
+ * 1: the library was found
+ * 0: the library was not found
+ */
+
+int
+addfile (char *path, char *libfil)
+{
+ FILE *fp;
+ char *str, *strend;
+ struct lbname *lbnh, *lbn;
+#ifdef OTHERSYSTEM
+ int libfilinc = 0;
+#endif
+
+ if (path != NULL)
+ {
+ str = (char *) new (strlen (path) + strlen (libfil) + 6);
+ strcpy (str, path);
+ strend = str + strlen(str) - 1;
+#ifdef OTHERSYSTEM
+ if (strlen (str) && (*strend != '/') && (*strend != LKDIRSEP))
+ {
+ strcat (str, LKDIRSEPSTR);
+ }
+#endif
+ }
+ else
+ {
+ str = (char *) new (strlen (libfil) + 5);
+ }
+
+#ifdef OTHERSYSTEM
+ if ((libfil[0] == '/') || (libfil[0] == LKDIRSEP))
+ {
+ libfil++;
+ libfilinc = 1;
+ }
+#endif
+
+ strcat (str, libfil);
+ if (strchr (libfil, FSEPX) == NULL)
+ {
+ sprintf (&str[strlen (str)], "%clib", FSEPX);
+ }
+
+ fp = fopen (str, "rb");
+ if (fp == NULL)
+ {
+ /*Ok, that didn't work. Try with the 'libfil' name only */
+#ifdef OTHERSYSTEM
+ if (libfilinc)
+ libfil--;
+#endif
+ fp = fopen (libfil, "rb");
+ if (fp != NULL)
+ {
+ /*Bingo! 'libfil' is the absolute path of the library */
+ strcpy (str, libfil);
+ path = NULL; /*This way 'libfil' and 'path' will be rebuilt from 'str' */
+ }
+ }
+
+ if (path == NULL)
+ {
+ /*'path' can not be null since it is needed to find the object files associated with
+ the library. So, get 'path' from 'str' and then chop it off and recreate 'libfil'.
+ That way putting 'path' and 'libfil' together will result into the original filepath
+ as contained in 'str'. */
+ int j;
+ path = strdup (str);
+ for (j = strlen (path) - 1; j >= 0; j--)
+ {
+ if ((path[j] == '/') || (path[j] == LKDIRSEP))
+ {
+ strcpy (libfil, &path[j + 1]);
+ path[j + 1] = 0;
+ break;
+ }
+ }
+ if (j <= 0)
+ path[0] = 0;
+ }
+
+ if (fp != NULL)
+ {
+ fclose (fp);
+ lbnh = (struct lbname *) new (sizeof (struct lbname));
+ if (lbnhead == NULL)
+ {
+ lbnhead = lbnh;
+ }
+ else
+ {
+ lbn = lbnhead;
+ while (lbn->next)
+ {
+ lbn = lbn->next;
+ }
+ lbn->next = lbnh;
+ }
+
+ lbnh->path = path;
+ lbnh->libfil = strdup (libfil);
+ lbnh->libspc = str;
+ lbnh->f_obj = objflg;
+ return 1;
+ }
+ else
+ {
+ free (str);
+ return 0;
+ }
+}
+
+/*)Function VOID search()
+ *
+ * The function search() looks through all the symbol tables
+ * at the end of pass 1. If any undefined symbols are found
+ * then the function fndsym() is called. Function fndsym()
+ * searches any specified library files to automagically
+ * import the object modules containing the needed symbol.
+ *
+ * After a symbol is found and imported by the function
+ * fndsym() the symbol tables are again searched. The
+ * symbol tables are searched until no more symbols can be
+ * resolved within the library files. This ensures that
+ * back references from one library module to another are
+ * also resolved.
+ *
+ * local variables:
+ * int i temporary counter
+ * sym *sp pointer to a symbol structure
+ * int symfnd found a symbol flag
+ *
+ * global variables:
+ * sym *symhash[] array of pointers to symbol tables
+ *
+ * functions called:
+ * int fndsym() lklibr.c
+ *
+ * side effects:
+ * If a symbol is found then the library object module
+ * containing the symbol will be imported and linked.
+ */
+
+VOID
+search (void)
+{
+ struct sym *sp;
+ int i, symfnd;
+
+ /*
+ * Look for undefined symbols. Keep
+ * searching until no more symbols are resolved.
+ */
+ symfnd = 1;
+ while (symfnd)
+ {
+ symfnd = 0;
+ /*
+ * Look through all the symbols
+ */
+ for (i = 0; i < NHASH; ++i)
+ {
+ sp = symhash[i];
+ while (sp)
+ {
+ /* If we find an undefined symbol
+ * (one where S_DEF is not set), then
+ * try looking for it. If we find it
+ * in any of the libraries then
+ * increment symfnd. This will force
+ * another pass of symbol searching and
+ * make sure that back references work.
+ */
+ if ((sp->s_type & S_DEF) == 0)
+ {
+ if (fndsym (sp->s_id))
+ {
+ symfnd++;
+ }
+ }
+ sp = sp->s_sp;
+ }
+ }
+ }
+}
+
+/*)Function VOID fndsym(name)
+ *
+ * char *name symbol name to find
+ *
+ * The function fndsym() searches through all combinations of the
+ * library path specifications (input by the -k option) and the
+ * library file specifications (input by the -l option) that
+ * lead to an existing file.
+ *
+ * The file specification may be formed in one of two ways:
+ *
+ * (1) If the library file contained an absolute
+ * path/file specification then this becomes filspc.
+ * (i.e. C:\...)
+ *
+ * (2) If the library file contains a relative path/file
+ * specification then the concatenation of the path
+ * and this file specification becomes filspc.
+ * (i.e. \...)
+ *
+ * The structure lbfile is created for the first library
+ * object file which contains the definition for the
+ * specified undefined symbol.
+ *
+ * If the library file [.LIB] contains file specifications for
+ * non existant files, no errors are returned.
+ *
+ * local variables:
+ * char buf[] [.REL] file input line
+ * char c [.REL] file input character
+ * FILE *fp file handle for object file
+ * lbfile *lbf temporary pointer
+ * lbfile *lbfh pointer to lbfile structure
+ * FILE *libfp file handle for library file
+ * lbname *lbnh pointer to lbname structure
+ * char *path file specification path
+ * char relfil[] [.REL] file specification
+ * char *str combined path and file specification
+ * char symname[] [.REL] file symbol string
+ *
+ * global variables:
+ * lbname *lbnhead The pointer to the first
+ * name structure
+ * lbfile *lbfhead The pointer to the first
+ * file structure
+ * int obj_flag linked file/library object output flag
+ *
+ * functions called:
+ * int fclose() c_library
+ * FILE *fopen() c_library
+ * VOID free() c_library
+ * int getnb() lklex.c
+ * VOID lkexit() lkmain.c
+ * VOID loadfile() lklibr.c
+ * VOID * new() lksym.c
+ * char * sprintf() c_library
+ * int sscanf() c_library
+ * char * strcat() c_library
+ * char * strchr() c_library
+ * char * strcpy() c_library
+ * int strlen() c_library
+ * int strncmp() c_library
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * If the symbol is found then a new lbfile structure
+ * is created and added to the linked list of lbfile
+ * structures. The file containing the found symbol
+ * is linked.
+ */
+
+#ifdef INDEXLIB
+int
+fndsym (char *name)
+{
+ struct lbfile *lbfh, *lbf;
+ pmlibraryfile ThisLibr;
+ pmlibrarysymbol ThisSym = NULL;
+
+ pmlibraryfile FirstFound;
+ int numfound = 0;
+
+ D ("Searching symbol: %s\n", name);
+
+ /* Build the index if this is the first call to fndsym */
+ if (libr == NULL)
+ buildlibraryindex ();
+
+ /* Iterate through all library object files */
+ FirstFound = libr; /* So gcc stops whining */
+ for (ThisLibr = libr; ThisLibr != NULL; ThisLibr = ThisLibr->next)
+ {
+ /* Iterate through all symbols in an object file */
+ for (ThisSym = ThisLibr->symbols; ThisSym != NULL; ThisSym = ThisSym->next)
+ {
+ if (!strcmp (ThisSym->name, name))
+ {
+ if ((!ThisLibr->loaded) && (numfound == 0))
+ {
+ /* Object file is not loaded - add it to the list */
+ lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+ if (lbfhead == NULL)
+ {
+ lbfhead = lbfh;
+ }
+ else
+ {
+ for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+ ;
+
+ lbf->next = lbfh;
+ }
+ lbfh->libspc = ThisLibr->libspc;
+ lbfh->filspc = ThisLibr->filspc;
+ lbfh->relfil = strdup (ThisLibr->relfil);
+ lbfh->offset = ThisLibr->offset;
+ lbfh->type = ThisLibr->type;
+
+ (*aslib_targets[lbfh->type]->loadfile) (lbfh);
+
+ ThisLibr->loaded = 1;
+ }
+
+ if (numfound == 0)
+ {
+ numfound++;
+ FirstFound = ThisLibr;
+ }
+ else
+ {
+ char absPath1[PATH_MAX];
+ char absPath2[PATH_MAX];
+#if defined(_WIN32)
+ int j;
+
+ _fullpath (absPath1, FirstFound->libspc, PATH_MAX);
+ _fullpath (absPath2, ThisLibr->libspc, PATH_MAX);
+ for (j = 0; absPath1[j] != 0; j++)
+ absPath1[j] = tolower ((unsigned char) absPath1[j]);
+ for (j = 0; absPath2[j] != 0; j++)
+ absPath2[j] = tolower ((unsigned char) absPath2[j]);
+#else
+ if (NULL == realpath (FirstFound->libspc, absPath1))
+ *absPath1 = '\0';
+ if (NULL == realpath (ThisLibr->libspc, absPath2))
+ *absPath2 = '\0';
+#endif
+ if (!(EQ (absPath1, absPath2) && EQ (FirstFound->relfil, ThisLibr->relfil)))
+ {
+ if (numfound == 1)
+ {
+ fprintf (stderr, "?ASlink-Warning-Definition of public symbol '%s'" " found more than once:\n", name);
+ fprintf (stderr, " Library: '%s', Module: '%s'\n", FirstFound->libspc, FirstFound->relfil);
+ }
+ fprintf (stderr, " Library: '%s', Module: '%s'\n", ThisLibr->libspc, ThisLibr->relfil);
+ numfound++;
+ }
+ }
+ }
+ }
+ }
+ return numfound;
+}
+
+struct add_sym_s
+{
+ pmlibraryfile plf;
+ pmlibrarysymbol pls;
+};
+
+static int
+add_sybmol (const char *sym, void *param)
+{
+ struct add_sym_s *as = (struct add_sym_s *) param;
+ pmlibrarysymbol ps = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+
+ D (" Indexing symbol: %s\n", sym);
+
+ as->plf->loaded = 0;
+ ps->next = NULL;
+ ps->name = strdup (sym);
+
+ if (as->pls == NULL)
+ {
+ as->pls = as->plf->symbols = ps;
+ }
+ else
+ {
+ as->pls->next = ps;
+ as->pls = as->pls->next;
+ }
+
+ return 0;
+}
+
+pmlibrarysymbol
+add_rel_index (FILE * fp, long size, pmlibraryfile This)
+{
+ struct add_sym_s as;
+ as.plf = This;
+ as.pls = This->symbols;
+
+ assert (This->symbols == NULL);
+
+ enum_symbols (fp, size, &add_sybmol, &as);
+
+ return as.pls;
+}
+
+/* buildlibraryindex - build an in-memory cache of the symbols contained in
+ * the libraries
+ */
+int
+buildlibraryindex (void)
+{
+ pmlibraryfile This = NULL;
+ struct lbname *lbnh;
+
+ /*
+ * Search through every library in the linked list "lbnhead".
+ */
+ for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
+ {
+ FILE *libfp;
+ int i;
+
+ D ("Indexing library: %s\n", lbnh->libspc);
+
+ if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
+ {
+ fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
+ lkexit (1);
+ }
+
+ for (i = 0; i < NELEM (aslib_targets); ++i)
+ {
+ if ((*aslib_targets[i]->is_lib) (libfp))
+ {
+ This = (*aslib_targets[i]->buildlibraryindex) (lbnh, libfp, This, i);
+ break;
+ }
+ }
+
+ if (i >= NELEM (aslib_targets))
+ fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
+
+ fclose (libfp);
+ }
+
+ return 0;
+}
+
+/* Release all memory allocated for the in-memory library index */
+void
+freelibraryindex (void)
+{
+ pmlibraryfile ThisLibr, ThisLibr2Free;
+ pmlibrarysymbol ThisSym, ThisSym2Free;
+
+ ThisLibr = libr;
+
+ while (ThisLibr)
+ {
+ ThisSym = ThisLibr->symbols;
+
+ while (ThisSym)
+ {
+ free (ThisSym->name);
+ ThisSym2Free = ThisSym;
+ ThisSym = ThisSym->next;
+ free (ThisSym2Free);
+ }
+ free (ThisLibr->filspc);
+ free (ThisLibr->relfil);
+ ThisLibr2Free = ThisLibr;
+ ThisLibr = ThisLibr->next;
+ free (ThisLibr2Free);
+ }
+
+ libr = NULL;
+}
+
+#else /* INDEXLIB */
+
+struct load_sym_s
+{
+ const char *name;
+ struct lbname *lbnh;
+ const char *relfil;
+ const char *filspc;
+ int offset;
+ int type;
+};
+
+static int
+load_sybmol (const char *sym, void *params)
+{
+ struct load_sym_s *ls = (struct load_sym_s *) params;
+
+ D (" Symbol: %s\n", sym);
+
+ if (strcmp (ls->name, sym) == 0)
+ {
+ struct lbfile *lbfh, *lbf;
+
+ D (" Symbol %s found in module %s!\n", sym, ls->relfil);
+
+ lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+ lbfh->libspc = ls->lbnh->libspc;
+ lbfh->relfil = strdup (ls->relfil);
+ lbfh->filspc = strdup (ls->filspc);
+ lbfh->offset = ls->offset;
+ lbfh->type = ls->type;
+
+ if (lbfhead == NULL)
+ lbfhead = lbfh;
+ else
+ {
+ for (lbf = lbfhead; lbf->next != NULL; lbf = lbf->next)
+ ;
+ lbf->next = lbfh;
+ }
+ (*aslib_targets[ls->type]->loadfile) (lbfh);
+
+ return 1;
+ }
+ else
+ return 0;
+}
+
+/*)Function int is_module_loaded(filspc)
+ *
+ * If this module has been already loaded
+ */
+
+int
+is_module_loaded (const char *filspc)
+{
+ struct lbfile *lbf;
+
+ for (lbf = lbfhead; lbf != NULL; lbf = lbf->next)
+ {
+ if (EQ (filspc, lbf->filspc))
+ {
+ D (" Module %s already loaded!\n", filspc);
+ return 1; /* Module already loaded */
+ }
+ }
+ return 0;
+}
+
+int
+add_rel_file (const char *name, struct lbname *lbnh, const char *relfil,
+ const char *filspc, int offset, FILE * fp, long size, int type)
+{
+ struct load_sym_s ls;
+
+ /* If this module has been loaded already don't load it again. */
+ if (is_module_loaded (filspc))
+ return 0;
+ else
+ {
+ ls.name = name;
+ ls.lbnh = lbnh;
+ ls.relfil = relfil;
+ ls.filspc = filspc;
+ ls.offset = offset;
+ ls.type = type;
+
+ return enum_symbols (fp, size, &load_sybmol, &ls);
+ }
+}
+
+int
+fndsym (const char *name)
+{
+ FILE *libfp;
+ struct lbname *lbnh;
+ int i;
+
+ /*
+ * Search through every library in the linked list "lbnhead".
+ */
+
+ D ("Searching symbol: %s\n", name);
+
+ for (lbnh = lbnhead; lbnh; lbnh = lbnh->next)
+ {
+ int ret = 0;
+
+ D ("Library: %s\n", lbnh->libspc);
+
+ if ((libfp = fopen (lbnh->libspc, "rb")) == NULL)
+ {
+ fprintf (stderr, "?ASlink-Error-Cannot open library file %s\n", lbnh->libspc);
+ lkexit (1);
+ }
+
+ for (i = 0; i < NELEM (aslib_targets); ++i)
+ {
+ if ((*aslib_targets[i]->is_lib) (libfp))
+ {
+ ret = (*aslib_targets[i]->fndsym) (name, lbnh, libfp, i);
+ break;
+ }
+ }
+
+ if (i >= NELEM (aslib_targets))
+ fprintf (stderr, "?ASlink-Error-Unknown library file format %s\n", lbnh->libspc);
+
+ fclose (libfp);
+
+ if (ret)
+ return 1;
+
+ } /* Ends good open of libr file */
+ return 0;
+}
+#endif /* INDEXLIB */
+
+/*)Function VOID library()
+ *
+ * The function library() links all the library object files
+ * contained in the lbfile structures.
+ *
+ * local variables:
+ * lbfile *lbfh pointer to lbfile structure
+ *
+ * global variables:
+ * lbfile *lbfhead pointer to first lbfile structure
+ * int obj_flag linked file/library object output flag
+ *
+ * functions called:
+ * VOID loadfile lklibr.c
+ *
+ * side effects:
+ * Links all files contained in the lbfile structures.
+ */
+
+VOID
+library (void)
+{
+ struct lbfile *lbfh;
+
+ for (lbfh = lbfhead; lbfh; lbfh = lbfh->next) {
+ obj_flag = lbfh->f_obj;
+ (*aslib_targets[lbfh->type]->loadfile) (lbfh);
+ }
+
+#ifdef INDEXLIB
+ freelibraryindex ();
+#endif
+}
--- /dev/null
+/* lklibr.h
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+ Copyright (C) 2008 Borut Razem, borut dot razem at siol dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#ifndef __LKLIBR_H
+#define __LKLIBR_H
+
+#include <stdio.h>
+
+#ifdef INDEXLIB
+typedef struct slibrarysymbol mlibrarysymbol;
+typedef struct slibrarysymbol *pmlibrarysymbol;
+
+struct slibrarysymbol
+{
+ char *name; /* Warning: allocate memory before using */
+ pmlibrarysymbol next;
+};
+
+typedef struct slibraryfile mlibraryfile;
+typedef struct slibraryfile *pmlibraryfile;
+
+struct slibraryfile
+{
+ int loaded;
+ char *libspc;
+ char *relfil; /* Warning: allocate memory before using */
+ char *filspc; /* Warning: allocate memory before using */
+ long offset; /* The embedded file offset in the library file libspc */
+ unsigned int type;
+ pmlibrarysymbol symbols;
+ pmlibraryfile next;
+};
+
+extern pmlibraryfile libr;
+
+pmlibrarysymbol add_rel_index (FILE * fp, long size, pmlibraryfile This);
+#else
+int is_module_loaded (const char *filspc);
+int add_rel_file (const char *name, struct lbname *lbnh, const char *relfil,
+ const char *filspc, int offset, FILE * fp, long size, int type);
+#endif
+
+struct aslib_target
+{
+ int (*is_lib) (FILE * libfp);
+#ifdef INDEXLIB
+ pmlibraryfile (*buildlibraryindex) (struct lbname * lbnh, FILE * libfp, pmlibraryfile This, int type);
+#else
+ int (*fndsym) (const char *name, struct lbname * lbnh, FILE * libfp, int type);
+#endif
+ void (*loadfile) (struct lbfile * lbfh);
+};
+
+extern struct aslib_target aslib_target_sdcclib;
+extern struct aslib_target aslib_target_ar;
+extern struct aslib_target aslib_target_lib;
+
+////
+//#define DEBUG_PRINT
+
+#ifdef DEBUG_PRINT
+# define D printf
+#else
+# define D 1 ? (void)0 : (*(void (*)(const char *, ...))0)
+#endif
+
+#endif /* __LKLIBR_H */
--- /dev/null
+/* lklist.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ */
+
+/*
+ * 28-Oct-97 JLH:
+ * - lstarea: show s_id as string rather than array [NCPS]
+ * - lstarea: show a_id as string rather than array [NCPS]
+ * 31-Oct-97 JLH: add NoICE output file genration in lstarea
+ * 02-Apr-98 JLH: add XDATA, DATA, BIT flags to area output
+ */
+
+#include "aslink.h"
+
+/*)Module lklist.c
+ *
+ * The module lklist.c contains the functions which
+ * output the linker .map file and produce a relocated
+ * listing .rst file.
+ *
+ * lklist.c contains the following functions:
+ * int dgt()
+ * VOID newpag()
+ * VOID slew()
+ * VOID lstarea()
+ * VOID lkulist()
+ * VOID lkalist()
+ * VOID lkglist()
+ *
+ * lklist.c contains no local variables.
+ */
+
+/*)Function VOID newpag()
+ *
+ * The function newpag() outputs a page skip, writes the
+ * first page header line, sets the line count to 1, and
+ * increments the page counter.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * int lop current line number on page
+ * int page current page number
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * The page and line counters are updated.
+ */
+
+VOID
+newpag(FILE *fp)
+{
+ fprintf(fp, "\fASxxxx Linker %s, page %u.\n", VERSION, ++page);
+ lop = 1;
+}
+
+/*)Function int dgt(rdx,str,n)
+ *
+ * int rdx radix bit code
+ * char *str pointer to the test string
+ * int n number of characters to check
+ *
+ * The function dgt() verifies that the string under test
+ * is of the specified radix.
+ *
+ * local variables:
+ * int i loop counter
+ *
+ * global variables:
+ * ctype[] array of character types
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+int
+dgt(int rdx, char *str, int n)
+{
+ int i;
+
+ for (i=0; i<n; i++) {
+ if ((ctype[*str++ & 0x007F] & rdx) == 0)
+ return(0);
+ }
+ return(1);
+}
+
+/*)Function VOID slew(xp, yp)
+ *
+ * area * xp pointer to an area structure
+ * bank * yp pointer to a bank structure
+ *
+ * The function slew() increments the page line counter.
+ * If the number of lines exceeds the maximum number of
+ * lines per page then a page skip and a page header are
+ * output.
+ *
+ * local variables:
+ * a_uint ai temporary
+ * a_uint aj temporary
+ * int i loop counter
+ * int n repeat counter
+ * char * frmta temporary format specifier
+ * char * frmtb temporary format specifier
+ * char * ptr pointer to an id string
+ *
+ * global variables:
+ * int a_bytes T line address bytes
+ * int a_mask addressing mask
+ * int lop current line number on page
+ * FILE *mfp Map output file handle
+ * int wflag Wide format listing
+ * int xflag Map file radix type flag
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID newpag() lklist.c
+ * char putc() c_library
+ *
+ * side effects:
+ * The page line and the page count may be updated.
+ */
+
+VOID
+slew(struct area *xp, struct bank *yp)
+{
+ int i, n;
+ char *frmta, *frmtb, *ptr;
+ a_uint ai, aj;
+
+ if (lop++ >= NLPP) {
+ newpag(mfp);
+ switch(xflag) {
+ default:
+ case 0: frmta = "Hexadecimal"; break;
+ case 1: frmta = "Octal"; break;
+ case 2: frmta = "Decimal"; break;
+ }
+ fprintf(mfp, "%s [%d-Bits]\n", frmta, a_bytes*8);
+ if (*yp->b_id) {
+ fprintf(mfp, "[ Bank == %s ]\n", yp->b_id);
+ lop += 1;
+ }
+ fprintf(mfp, "\n");
+ if (wflag) {
+ fprintf(mfp,
+ "Area Addr");
+ fprintf(mfp,
+ " Size Decimal Bytes (Attributes)\n");
+ fprintf(mfp,
+ "-------------------------------- ----");
+ fprintf(mfp,
+ " ---- ------- ----- ------------\n");
+ } else {
+ fprintf(mfp,
+ "Area Addr ");
+ fprintf(mfp,
+ " Size Decimal Bytes (Attributes)\n");
+ fprintf(mfp,
+ "-------------------- ---- ");
+ fprintf(mfp,
+ " ---- ------- ----- ------------\n");
+ }
+
+ ai = xp->a_addr & a_mask;
+ aj = xp->a_size & a_mask;
+
+ /*
+ * Output Area Header
+ */
+ ptr = &xp->a_id[0];
+ if (wflag) {
+ fprintf(mfp, "%-32.32s", ptr);
+ } else {
+ fprintf(mfp, "%-19.19s", ptr);
+ }
+#ifdef LONGINT
+ switch(a_bytes) {
+ default:
+ case 2:
+ switch(xflag) {
+ default:
+ case 0: frmta = " %04lX %04lX"; break;
+ case 1: frmta = " %06lo %06lo"; break;
+ case 2: frmta = " %05lu %05lu"; break;
+ }
+ frmtb = " = %6lu. bytes "; break;
+ case 3:
+ switch(xflag) {
+ default:
+ case 0: frmta = " %06lX %06lX"; break;
+ case 1: frmta = " %08lo %08lo"; break;
+ case 2: frmta = " %08lu %08lu"; break;
+ }
+ frmtb = " = %8lu. bytes "; break;
+ case 4:
+ switch(xflag) {
+ default:
+ case 0: frmta = " %08lX %08lX"; break;
+ case 1: frmta = " %011lo %011lo"; break;
+ case 2: frmta = " %010lu %010lu"; break;
+ }
+ frmtb = " = %10lu. bytes "; break;
+ }
+#else
+ switch(a_bytes) {
+ default:
+ case 2:
+ switch(xflag) {
+ default:
+ case 0: frmta = " %04X %04X"; break;
+ case 1: frmta = " %06o %06o"; break;
+ case 2: frmta = " %05u %05u"; break;
+ }
+ frmtb = " = %6u. bytes "; break;
+ case 3:
+ switch(xflag) {
+ default:
+ case 0: frmta = " %06X %06X"; break;
+ case 1: frmta = " %08o %08o"; break;
+ case 2: frmta = " %08u %08u"; break;
+ }
+ frmtb = " = %8u. bytes "; break;
+ case 4:
+ switch(xflag) {
+ default:
+ case 0: frmta = " %08X %08X"; break;
+ case 1: frmta = " %011o %011o"; break;
+ case 2: frmta = " %010u %010u"; break;
+ }
+ frmtb = " = %10u. bytes "; break;
+ }
+#endif
+ fprintf(mfp, frmta, ai, aj);
+ fprintf(mfp, frmtb, aj);
+
+ if (xp->a_flag & A3_ABS) {
+ fprintf(mfp, "(ABS");
+ } else {
+ fprintf(mfp, "(REL");
+ }
+ if (xp->a_flag & A3_OVR) {
+ fprintf(mfp, ",OVR");
+ } else {
+ fprintf(mfp, ",CON");
+ }
+ if (xp->a_flag & A3_PAG) {
+ fprintf(mfp, ",PAG");
+ }
+
+ /* sdld specific */
+ if (xp->a_flag & A_CODE) {
+ fprintf(mfp, ",CODE");
+ }
+ if (xp->a_flag & A_XDATA) {
+ fprintf(mfp, ",XDATA");
+ }
+ if (xp->a_flag & A_BIT) {
+ fprintf(mfp, ",BIT");
+ }
+ /* end sdld specific */
+
+ fprintf(mfp, ")\n");
+ if (wflag) {
+ putc('\n', mfp);
+ fprintf(mfp,
+ " Value Global ");
+ fprintf(mfp,
+ " Global Defined In Module\n");
+ fprintf(mfp,
+ " ----- --------------------------------");
+ fprintf(mfp,
+ " ------------------------\n");
+ } else {
+ switch(a_bytes) {
+ default:
+ case 2: frmta = " Value Global ";
+ frmtb = " ----- ------ ";
+ n = 4; break;
+ case 3:
+ case 4: frmta = " Value Global ";
+ frmtb = " ----- ------ ";
+ n = 3; break;
+ }
+ putc('\n', mfp);
+ for(i=0;i<n;++i)
+ fprintf(mfp, "%s", frmta);
+ putc('\n', mfp);
+ for(i=0;i<n;++i)
+ fprintf(mfp, "%s", frmtb);
+ putc('\n', mfp);
+ }
+
+ lop += 9;
+ }
+}
+
+/* sdld specific */
+/* Used for qsort call in lstsym */
+static int _cmpSymByAddr(const void *p1, const void *p2)
+{
+ struct sym **s1 = (struct sym **)(p1);
+ struct sym **s2 = (struct sym **)(p2);
+ int delta = ((*s1)->s_addr + (*s1)->s_axp->a_addr) -
+ ((*s2)->s_addr + (*s2)->s_axp->a_addr);
+
+ /* Sort first by address, then by name. */
+ if (delta)
+ {
+ return delta;
+ }
+ return strcmp((*s1)->s_id,(*s2)->s_id);
+}
+/* end sdld specific */
+
+/*)Function VOID lstarea(xp, yp)
+ *
+ * area * xp pointer to an area structure
+ * bank * yp pointer to a bank structure
+ *
+ * The function lstarea() creates the linker map output for
+ * the area specified by pointer xp. The generated output
+ * area header includes the area name, starting address,
+ * size of area, number of words (in decimal), and the
+ * area attributes. The symbols defined in this area are
+ * sorted by ascending address and output four per line
+ * in the selected radix (one per line in wide format).
+ *
+ * local variables:
+ * areax * oxp pointer to an area extension structure
+ * int i loop counter
+ * int j bubble sort update status
+ * int n repeat counter
+ * char * frmt temporary format specifier
+ * char * ptr pointer to an id string
+ * int nmsym number of symbols in area
+ * a_uint a0 temporary
+ * a_uint ai temporary
+ * a_uint aj temporary
+ * sym * sp pointer to a symbol structure
+ * sym ** p pointer to an array of
+ * pointers to symbol structures
+ *
+ * global variables:
+ * int a_bytes T line address bytes
+ * FILE *mfp Map output file handle
+ * sym *symhash[NHASH] array of pointers to NHASH
+ * linked symbol lists
+ * int wflag Wide format listing
+ * int xflag Map file radix type flag
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID free() c_library
+ * char * malloc() c_library
+ * char putc() c_library
+ * VOID slew() lklist.c
+ *
+ * side effects:
+ * Map output generated.
+ */
+
+VOID
+lstarea(struct area *xp, struct bank *yp)
+{
+ struct areax *oxp;
+ int i, j, n;
+ char *frmt, *ptr;
+ int nmsym;
+ a_uint a0, ai, aj;
+ struct sym *sp;
+ struct sym **p;
+ /* sdld specific */
+ int memPage;
+ /* end sdld specific */
+
+ /*
+ * Find number of symbols in area
+ */
+ nmsym = 0;
+ oxp = xp->a_axp;
+ while (oxp) {
+ for (i=0; i<NHASH; i++) {
+ sp = symhash[i];
+ while (sp != NULL) {
+ if (oxp == sp->s_axp)
+ ++nmsym;
+ sp = sp->s_sp;
+ }
+ }
+ oxp = oxp->a_axp;
+ }
+
+ if ((nmsym == 0) && (xp->a_size == 0)) {
+ return;
+ }
+
+ lop = NLPP;
+ slew(xp, yp);
+
+ if (nmsym == 0) {
+ return;
+ }
+
+ /*
+ * Allocate space for an array of pointers to symbols
+ * and load array.
+ */
+ if ( (p = (struct sym **) malloc (nmsym*sizeof(struct sym *))) == NULL) {
+ fprintf(mfp, "Insufficient space to build Map Segment.\n");
+ return;
+ }
+ nmsym = 0;
+ oxp = xp->a_axp;
+ while (oxp) {
+ for (i=0; i<NHASH; i++) {
+ sp = symhash[i];
+ while (sp != NULL) {
+ if (oxp == sp->s_axp) {
+ p[nmsym++] = sp;
+ }
+ sp = sp->s_sp;
+ }
+ }
+ oxp = oxp->a_axp;
+ }
+
+ if (is_sdld()) {
+ /*
+ * Quick Sort of Addresses in Symbol Table Array
+ */
+ qsort(p, nmsym, sizeof(struct sym *), _cmpSymByAddr);
+ } else {
+ /*
+ * Bubble Sort of Addresses in Symbol Table Array
+ */
+ j = 1;
+ while (j) {
+ j = 0;
+ sp = p[0];
+ a0 = sp->s_addr + sp->s_axp->a_addr;
+ for (i=1; i<nmsym; ++i) {
+ sp = p[i];
+ ai = sp->s_addr + sp->s_axp->a_addr;
+ if (a0 > ai) {
+ j = 1;
+ p[i] = p[i-1];
+ p[i-1] = sp;
+ }
+ a0 = ai;
+ }
+ }
+ }
+
+ /*
+ * Repeat Counter
+ */
+ switch(a_bytes) {
+ default:
+ case 2: n = 4; break;
+ case 3:
+ case 4: n = 3; break;
+ }
+
+ /*
+ * Symbol Table Output
+ */
+ /* sdld specific */
+ memPage = (xp->a_flag & A_CODE) ? 0x0C : ((xp->a_flag & A_XDATA) ? 0x0D : ((xp->a_flag & A_BIT) ? 0x0B : 0x00));
+ /* end sdld specific */
+ i = 0;
+ while (i < nmsym) {
+ if (wflag) {
+ slew(xp, yp);
+ if (is_sdld()) {
+ switch(a_bytes) {
+ default:
+ case 2: frmt = " "; break;
+ case 3:
+ case 4: frmt = ""; break;
+ }
+ if (memPage != 0)
+ fprintf(mfp, "%s%X:", frmt, memPage);
+ else
+ fprintf(mfp, "%s ", frmt);
+ } else {
+ switch(a_bytes) {
+ default:
+ case 2: frmt = " "; break;
+ case 3:
+ case 4: frmt = " "; break;
+ }
+ fprintf(mfp, "%s", frmt);
+ }
+ } else
+ if ((i % n) == 0) {
+ slew(xp, yp);
+ switch(a_bytes) {
+ default:
+ case 2: frmt = " "; break;
+ case 3:
+ case 4: frmt = " "; break;
+ }
+ fprintf(mfp, "%s", frmt);
+ }
+
+ sp = p[i];
+ aj = (sp->s_addr + sp->s_axp->a_addr) & a_mask;
+#ifdef LONGINT
+ switch(a_bytes) {
+ default:
+ case 2:
+ switch(xflag) {
+ default:
+ case 0: frmt = " %04lX "; break;
+ case 1: frmt = "%06lo "; break;
+ case 2: frmt = " %05lu "; break;
+ }
+ break;
+ case 3:
+ switch(xflag) {
+ default:
+ case 0: frmt = " %06lX "; break;
+ case 1: frmt = " %08lo "; break;
+ case 2: frmt = " %08lu "; break;
+ }
+ break;
+ case 4:
+ switch(xflag) {
+ default:
+ case 0: frmt = " %08lX "; break;
+ case 1: frmt = "%011lo "; break;
+ case 2: frmt = " %010lu "; break;
+ }
+ break;
+ }
+#else
+ switch(a_bytes) {
+ default:
+ case 2:
+ switch(xflag) {
+ default:
+ case 0: frmt = " %04X "; break;
+ case 1: frmt = "%06o "; break;
+ case 2: frmt = " %05u "; break;
+ }
+ break;
+ case 3:
+ switch(xflag) {
+ default:
+ case 0: frmt = " %06X "; break;
+ case 1: frmt = " %08o "; break;
+ case 2: frmt = " %08u "; break;
+ }
+ break;
+ case 4:
+ switch(xflag) {
+ default:
+ case 0: frmt = " %08X "; break;
+ case 1: frmt = "%011o "; break;
+ case 2: frmt = " %010u "; break;
+ }
+ break;
+ }
+#endif
+ fprintf(mfp, frmt, aj);
+
+ ptr = &sp->s_id[0];
+
+#if NOICE
+ /*
+ * NoICE output of symbol
+ */
+ if (jflag) DefineNoICE(ptr, aj, yp);
+#endif
+
+#if SDCDB
+ /*
+ * SDCDB output of symbol
+ */
+ if (yflag) DefineSDCDB(ptr, aj);
+#endif
+
+ if (wflag) {
+ fprintf(mfp, "%-32.32s", ptr);
+ i++;
+ ptr = &sp->m_id[0];
+ if(ptr) {
+ fprintf(mfp, " %-.28s", ptr);
+ }
+ } else {
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "%-8.8s"; break;
+ case 3:
+ case 4: frmt = "%-9.9s"; break;
+ }
+ fprintf(mfp, frmt, ptr);
+ if (++i < nmsym)
+ if (i % n != 0)
+ fprintf(mfp, " | ");
+ }
+ if (wflag || (i % n == 0)) {
+ putc('\n', mfp);
+ }
+ }
+ if (i % n != 0) {
+ putc('\n', mfp);
+ }
+ free(p);
+}
+
+/*)Function VOID lkulist(i)
+ *
+ * int i i # 0 process LST to RST file
+ * i = 0 copy remainder of LST file
+ * to RST file and close files
+ *
+ * The function lkulist() creates a relocated listing (.rst)
+ * output file from the ASxxxx assembler listing (.lst)
+ * files. The .lst file's program address and code bytes
+ * are changed to reflect the changes made by ASlink as
+ * the .rel files are combined into a single relocated
+ * output file.
+ *
+ * local variables:
+ * a_uint cpc current program counter address in PC increments
+ * int cbytes bytes so far in T line
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * int hilo byte order
+ * int gline get a line from the LST file
+ * to translate for the RST file
+ * a_uint pc current program counter address in bytes
+ * int pcb bytes per instruction word
+ * char rb[] read listing file text line
+ * FILE *rfp The file handle to the current
+ * output RST file
+ * int rtcnt count of data words
+ * int rtflg[] output the data flag
+ * a_uint rtval[] relocated data
+ * int rterr[] error flag ???
+ * FILE *tfp The file handle to the current
+ * LST file being scanned
+ *
+ * functions called:
+ * int fclose() c_library
+ * int fgets() c_library
+ * int fprintf() c_library
+ * VOID lkalist() lklist.c
+ * VOID lkglist() lklist.c
+ *
+ * side effects:
+ * A .rst file is created for each available .lst
+ * file associated with a .rel file.
+ */
+
+VOID
+lkulist(int i)
+{
+ a_uint cpc;
+ int cbytes;
+
+ /*
+ * Exit if listing file is not open
+ */
+ if (tfp == NULL)
+ return;
+
+ /*
+ * Normal processing of LST to RST
+ */
+ if (i) {
+ /*
+ * Line with only address
+ */
+ if (rtcnt == a_bytes) {
+ lkalist(pc);
+
+ /*
+ * Line with address and code
+ */
+ } else {
+ cpc = pc;
+ cbytes = 0;
+ for (i=a_bytes; i < rtcnt; i++) {
+ if (rtflg[i]) {
+ lkglist(cpc, (int) (rtval[i] & 0xFF), rterr[i]);
+ cbytes += 1;
+ cpc += (cbytes % pcb) ? 0 : 1;
+ }
+ }
+ }
+ /*
+ * Copy remainder of LST to RST
+ */
+ } else {
+ if (gline == 0)
+ fprintf(rfp, "%s", rb);
+
+ while (fgets(rb, sizeof(rb)-2, tfp) != 0) {
+ fprintf(rfp, "%s", rb);
+ }
+ fclose(tfp);
+ tfp = NULL;
+ fclose(rfp);
+ rfp = NULL;
+ }
+}
+
+/*)Function VOID lkalist(cpc)
+ *
+ * int cpc current program counter value
+ *
+ * The function lkalist() performs the following functions:
+ *
+ * (1) if the value of gline = 0 then the current listing
+ * file line is copied to the relocated listing file output.
+ *
+ * (2) the listing file is read line by line and copied to
+ * the relocated listing file until a valid source
+ * line number and a program counter value of the correct
+ * radix is found. The new relocated pc value is substituted
+ * and the line is written to the RST file.
+ *
+ * local variables:
+ * int i loop counter
+ * int m character count
+ * int n character index
+ * int r character radix
+ * char * frmt temporary format specifier
+ * char str[] temporary string
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * a_uint a_mask address masking parameter
+ * int gcntr data byte counter
+ * int gline get a line from the LST file
+ * to translate for the RST file
+ * char rb[] read listing file text line
+ * FILE *rfp The file handle to the current
+ * output RST file
+ * FILE *tfp The file handle to the current
+ * LST file being scanned
+ *
+ * functions called:
+ * int dgt() lklist.c
+ * int fclose() c_library
+ * int fgets() c_library
+ * int fprintf() c_library
+ * int sprintf() c_library
+ * char * strncpy() c_library
+ *
+ * side effects:
+ * Lines of the LST file are copied to the RST file,
+ * the last line copied has the code address
+ * updated to reflect the program relocation.
+ */
+
+/* The Output Formats, No Cycle Count
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXX xx xx xx xx xx xx LLLLL ************* HEX(16)
+ee 000000 ooo ooo ooo ooo LLLLL ************* OCTAL(16)
+ee DDDDD ddd ddd ddd ddd LLLLL ************* DECIMAL(16)
+ XXXX
+ OOOOOO
+ DDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXX xx xx xx xx xx xx xx LLLLL ********* HEX(24)
+ee OO000000 ooo ooo ooo ooo ooo LLLLL ********* OCTAL(24)
+ee DDDDDDDD ddd ddd ddd ddd ddd LLLLL ********* DECIMAL(24)
+ XXXXXX
+ OOOOOOOO
+ DDDDDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXXXX xx xx xx xx xx xx xx LLLLL ********* HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo ooo LLLLL ********* OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd ddd LLLLL ********* DECIMAL(32)
+ XXXXXXXX
+ OOOOOOOOOOO
+ DDDDDDDDDD
+*/
+
+/* The Output Formats, With Cycle Count [nn]
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXX xx xx xx xx xx[nn]LLLLL ************* HEX(16)
+ee 000000 ooo ooo ooo [nn]LLLLL ************* OCTAL(16)
+ee DDDDD ddd ddd ddd [nn]LLLLL ************* DECIMAL(16)
+ XXXX
+ OOOOOO
+ DDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXX xx xx xx xx xx xx[nn]LLLLL ********* HEX(24)
+ee OO000000 ooo ooo ooo ooo [nn]LLLLL ********* OCTAL(24)
+ee DDDDDDDD ddd ddd ddd ddd [nn]LLLLL ********* DECIMAL(24)
+ XXXXXX
+ OOOOOOOO
+ DDDDDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXXXX xx xx xx xx xx xx[nn]LLLLL ********* HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo [nn]LLLLL ********* OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd [nn]LLLLL ********* DECIMAL(32)
+ XXXXXXXX
+ OOOOOOOOOOO
+ DDDDDDDDDD
+*/
+
+VOID
+lkalist(a_uint cpc)
+{
+ char str[16];
+ char *frmt;
+ int m, n, r;
+
+ /*
+ * Truncate (int) to N-Bytes
+ */
+ cpc &= a_mask;
+
+ /*
+ * Exit if listing file is not open
+ */
+loop: if (tfp == NULL)
+ return;
+
+ /*
+ * Copy current LST to RST
+ */
+ if (gline == 0) {
+ fprintf(rfp, "%s", rb);
+ gline = 1;
+ }
+
+ /*
+ * Clear text line buffer
+ */
+ memset(rb, 0, sizeof(rb));
+
+ /*
+ * Get next LST text line
+ */
+ if (fgets(rb, sizeof(rb)-2, tfp) == NULL) {
+ fclose(tfp);
+ tfp = NULL;
+ fclose(rfp);
+ rfp = NULL;
+ return;
+ }
+
+ /*
+ * Must have an ASxxxx Listing line number
+ */
+ switch(a_bytes) {
+ default:
+ case 2: n = 30; break;
+ case 3:
+ case 4: n = 38; break;
+ }
+ if (!dgt(RAD10, &rb[n], 1)) {
+ fprintf(rfp, "%s", rb);
+ goto loop;
+ }
+
+ /*
+ * Must have an address in the expected radix
+ */
+#ifdef LONGINT
+ switch(radix) {
+ default:
+ case 16:
+ r = RAD16;
+ switch(a_bytes) {
+ default:
+ case 2: n = 3; m = 4; frmt = "%04lX"; break;
+ case 3: n = 6; m = 6; frmt = "%06lX"; break;
+ case 4: n = 4; m = 8; frmt = "%08lX"; break;
+ }
+ break;
+ case 10:
+ r = RAD10;
+ switch(a_bytes) {
+ default:
+ case 2: n = 4; m = 5; frmt = "%05lu"; break;
+ case 3: n = 5; m = 8; frmt = "%08lu"; break;
+ case 4: n = 3; m = 10; frmt = "%010lu"; break;
+ }
+ break;
+ case 8:
+ r = RAD8;
+ switch(a_bytes) {
+ default:
+ case 2: n = 3; m = 6; frmt = "%06lo"; break;
+ case 3: n = 5; m = 8; frmt = "%08lo"; break;
+ case 4: n = 2; m = 11; frmt = "%011lo"; break;
+ }
+ break;
+ }
+#else
+ switch(radix) {
+ default:
+ case 16:
+ r = RAD16;
+ switch(a_bytes) {
+ default:
+ case 2: n = 3; m = 4; frmt = "%04X"; break;
+ case 3: n = 6; m = 6; frmt = "%06X"; break;
+ case 4: n = 4; m = 8; frmt = "%08X"; break;
+ }
+ break;
+ case 10:
+ r = RAD10;
+ switch(a_bytes) {
+ default:
+ case 2: n = 4; m = 5; frmt = "%05u"; break;
+ case 3: n = 5; m = 8; frmt = "%08u"; break;
+ case 4: n = 3; m = 10; frmt = "%010u"; break;
+ }
+ break;
+ case 8:
+ r = RAD8;
+ switch(a_bytes) {
+ default:
+ case 2: n = 3; m = 6; frmt = "%06o"; break;
+ case 3: n = 5; m = 8; frmt = "%08o"; break;
+ case 4: n = 2; m = 11; frmt = "%011o"; break;
+ }
+ break;
+ }
+#endif
+ if (!dgt(r, &rb[n], m)) {
+ fprintf(rfp, "%s", rb);
+ goto loop;
+ }
+ sprintf(str, frmt, cpc);
+ strncpy(&rb[n], str, m);
+
+ /*
+ * Copy updated LST text line to RST
+ */
+ fprintf(rfp, "%s", rb);
+ gcntr = 0;
+}
+
+/*)Function VOID lkglist(cpc,v,err)
+ *
+ * int cpc current program counter value
+ * int v value of byte at this address
+ * int err error flag for this value
+ *
+ * The function lkglist() performs the following functions:
+ *
+ * (1) if the value of gline = 1 then the listing file
+ * is read line by line and copied to the
+ * relocated listing file until a valid source
+ * line number and a program counter value of the correct
+ * radix is found.
+ *
+ * (2) The new relocated values and code address are
+ * substituted and the line may be written to the RST file.
+ *
+ * local variables:
+ * int a string index for first byte
+ * int i loop counter
+ * int m character count
+ * int n character index
+ * int r character radix
+ * int s spacing
+ * int u repeat counter
+ * char * afrmt temporary format specifier
+ * char * frmt temporary format specifier
+ * char str[] temporary string
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * a_uint a_mask address masking parameter
+ * int gcntr data byte counter
+ * set to -1 for a continuation line
+ * int gline get a line from the LST file
+ * to translate for the RST file
+ * char rb[] read listing file text line
+ * char *rp pointer to listing file text line
+ * FILE *rfp The file handle to the current
+ * output RST file
+ * FILE *tfp The file handle to the current
+ * LST file being scanned
+ * char *errmsg3[] array of pointers to error strings
+ *
+ * functions called:
+ * int dgt() lklist.c
+ * int fclose() c_library
+ * int fgets() c_library
+ * int fprintf() c_library
+ * int sprintf() c_library
+ * char * strncpy() c_library
+ *
+ * side effects:
+ * Lines of the LST file are copied to the RST file
+ * with updated data values and code addresses.
+ */
+
+/* The Output Formats, No Cycle Count
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXX xx xx xx xx xx xx LLLLL ************* HEX(16)
+ee 000000 ooo ooo ooo ooo LLLLL ************* OCTAL(16)
+ee DDDDD ddd ddd ddd ddd LLLLL ************* DECIMAL(16)
+ XXXX
+ OOOOOO
+ DDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXX xx xx xx xx xx xx xx LLLLL ********* HEX(24)
+ee OO000000 ooo ooo ooo ooo ooo LLLLL ********* OCTAL(24)
+ee DDDDDDDD ddd ddd ddd ddd ddd LLLLL ********* DECIMAL(24)
+ XXXXXX
+ OOOOOOOO
+ DDDDDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXXXX xx xx xx xx xx xx xx LLLLL ********* HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo ooo LLLLL ********* OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd ddd LLLLL ********* DECIMAL(32)
+ XXXXXXXX
+ OOOOOOOOOOO
+ DDDDDDDDDD
+*/
+
+/* The Output Formats, With Cycle Count [nn]
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXX xx xx xx xx xx[nn]LLLLL ************* HEX(16)
+ee 000000 ooo ooo ooo [nn]LLLLL ************* OCTAL(16)
+ee DDDDD ddd ddd ddd [nn]LLLLL ************* DECIMAL(16)
+ XXXX
+ OOOOOO
+ DDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXX xx xx xx xx xx xx[nn]LLLLL ********* HEX(24)
+ee OO000000 ooo ooo ooo ooo [nn]LLLLL ********* OCTAL(24)
+ee DDDDDDDD ddd ddd ddd ddd [nn]LLLLL ********* DECIMAL(24)
+ XXXXXX
+ OOOOOOOO
+ DDDDDDDD
+
+| Tabs- | | | | | |
+ 11111111112222222222333333333344444-----
+012345678901234567890123456789012345678901234-----
+ | | | | |
+ee XXXXXXXX xx xx xx xx xx xx[nn]LLLLL ********* HEX(32)
+eeOOOOO000000 ooo ooo ooo ooo [nn]LLLLL ********* OCTAL(32)
+ee DDDDDDDDDD ddd ddd ddd ddd [nn]LLLLL ********* DECIMAL(32)
+ XXXXXXXX
+ OOOOOOOOOOO
+ DDDDDDDDDD
+*/
+
+VOID
+lkglist(a_uint cpc, int v, int err)
+{
+ char str[16];
+ char *afrmt, *frmt;
+ int a, n, m, r, s, u;
+
+ /*
+ * Truncate (int) to N-Bytes
+ */
+ cpc &= a_mask;
+
+ /*
+ * Exit if listing file is not open
+ */
+loop: if (tfp == NULL)
+ return;
+
+ /*
+ * Get next LST text line
+ */
+ if (gline) {
+ /*
+ * Clear text line buffer
+ */
+ memset(rb, 0, sizeof(rb));
+
+ /*
+ * Get next LST text line
+ */
+ if (fgets(rb, sizeof(rb)-2, tfp) == NULL) {
+ fclose(tfp);
+ tfp = NULL;
+ fclose(rfp);
+ rfp = NULL;
+ return;
+ }
+
+ /*
+ * Check for a listing line number if required
+ */
+ if (gcntr != -1) {
+ switch(a_bytes) {
+ default:
+ case 2: n = 30; break;
+ case 3:
+ case 4: n = 38; break;
+ }
+ if (!dgt(RAD10, &rb[n], 1)) {
+ fprintf(rfp, "%s", rb);
+ goto loop;
+ }
+ gcntr = 0;
+ }
+ gline = 0;
+ }
+
+ /*
+ * Hex Listing
+ */
+#ifdef LONGINT
+ switch(radix) {
+ default:
+ case 16:
+ r = RAD16;
+ switch(a_bytes) {
+ default:
+ case 2: a = 8; s = 3; n = 3; m = 4; u = 6; afrmt = "%04lX"; break;
+ case 3: a = 13; s = 3; n = 6; m = 6; u = 7; afrmt = "%06lX"; break;
+ case 4: a = 13; s = 3; n = 4; m = 8; u = 7; afrmt = "%08lX"; break;
+ }
+ frmt = " %02X"; break;
+ case 10:
+ r = RAD10;
+ switch(a_bytes) {
+ default:
+ case 2: a = 10; s = 4; n = 4; m = 5; u = 4; afrmt = "%05lu"; break;
+ case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08lu"; break;
+ case 4: a = 14; s = 4; n = 3; m = 10; u = 5; afrmt = "%010lu"; break;
+ }
+ frmt = " %03u"; break;
+ case 8:
+ r = RAD8;
+ switch(a_bytes) {
+ default:
+ case 2: a = 10; s = 4; n = 3; m = 6; u = 4; afrmt = "%06lo"; break;
+ case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08lo"; break;
+ case 4: a = 14; s = 4; n = 2; m = 11; u = 5; afrmt = "%011lo"; break;
+ }
+ frmt = " %03o"; break;
+ }
+#else
+ switch(radix) {
+ default:
+ case 16:
+ r = RAD16;
+ switch(a_bytes) {
+ default:
+ case 2: a = 8; s = 3; n = 3; m = 4; u = 6; afrmt = "%04X"; break;
+ case 3: a = 13; s = 3; n = 6; m = 6; u = 7; afrmt = "%06X"; break;
+ case 4: a = 13; s = 3; n = 4; m = 8; u = 7; afrmt = "%08X"; break;
+ }
+ frmt = " %02X"; break;
+ case 10:
+ r = RAD10;
+ switch(a_bytes) {
+ default:
+ case 2: a = 10; s = 4; n = 4; m = 5; u = 4; afrmt = "%05u"; break;
+ case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08u"; break;
+ case 4: a = 14; s = 4; n = 3; m = 10; u = 5; afrmt = "%010u"; break;
+ }
+ frmt = " %03u"; break;
+ case 8:
+ r = RAD8;
+ switch(a_bytes) {
+ default:
+ case 2: a = 10; s = 4; n = 3; m = 6; u = 4; afrmt = "%06o"; break;
+ case 3: a = 14; s = 4; n = 5; m = 8; u = 5; afrmt = "%08o"; break;
+ case 4: a = 14; s = 4; n = 2; m = 11; u = 5; afrmt = "%011o"; break;
+ }
+ frmt = " %03o"; break;
+ }
+#endif
+ /*
+ * Data Byte Pointer
+ */
+ if (gcntr == -1) {
+ rp = &rb[a];
+ } else {
+ rp = &rb[a + (s * gcntr)];
+ }
+ /*
+ * Number must be of proper radix
+ */
+ if (!dgt(r, rp, s-1)) {
+ fprintf(rfp, "%s", rb);
+ gline = 1;
+ goto loop;
+ }
+ /*
+ * Output new data value, overwrite relocation codes
+ */
+ sprintf(str, frmt, v);
+ strncpy(rp-1, str, s);
+ if (gcntr == -1) {
+ gcntr = 0;
+ }
+ /*
+ * Output relocated code address
+ */
+ if (gcntr == 0) {
+ if (dgt(r, &rb[n], m)) {
+ sprintf(str, afrmt, cpc);
+ strncpy(&rb[n], str, m);
+ }
+ }
+ /*
+ * Output an error line if required
+ */
+ if (err) {
+ switch(ASxxxx_VERSION) {
+ case 3:
+ fprintf(rfp, "?ASlink-Warning-%s\n", errmsg3[err]);
+ break;
+
+ default:
+ break;
+ }
+ }
+ /*
+ * Fix 'u' if [nn], cycles, is specified
+ */
+ if (rb[a + (s*u) - 1] == CYCNT_END) {
+ u -= 1;
+ }
+ /*
+ * Output text line when updates finished
+ */
+ if (++gcntr == u) {
+ fprintf(rfp, "%s", rb);
+ gline = 1;
+ gcntr = -1;
+ }
+}
--- /dev/null
+/* lkmain.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+#include "aslink.h"
+
+/*)Module lkmain.c
+ *
+ * The module lkmain.c contains the functions which
+ * (1) input the linker options, parameters, and specifications
+ * (2) perform a two pass link
+ * (3) produce the appropriate linked data output and/or
+ * link map file and/or relocated listing files.
+ *
+ * lkmain.c contains the following functions:
+ * FILE * afile()
+ * VOID bassav()
+ * VOID gblsav()
+ * int intsiz()
+ * VOID link_main()
+ * VOID lkexit()
+ * int fndext()
+ * int fndidx()
+ * int main()
+ * VOID map()
+ * int parse()
+ * VOID doparse()
+ * VOID setgbl()
+ * VOID usage()
+ *
+ * lkmain.c contains the following local variables:
+ * char * usetext[] array of pointers to the
+ * command option tect lines
+ *
+ */
+
+/* sdld 8051 specific */
+/*JCF: Creates some of the default areas so they are allocated in the right order.*/
+void Areas51 (void)
+{
+ char * rel[] = {
+ "XH",
+ "H 7 areas 0 global symbols",
+ "A _CODE size 0 flags 0", /*Each .rel has one, so...*/
+ "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/
+ "A REG_BANK_1 size 0 flags 4",
+ "A REG_BANK_2 size 0 flags 4",
+ "A REG_BANK_3 size 0 flags 4",
+ "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/
+ "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/
+ ""
+ };
+
+ char * rel2[] = {
+ "XH",
+ "H C areas 0 global symbols",
+ "A _CODE size 0 flags 0", /*Each .rel has one, so...*/
+ "A REG_BANK_0 size 0 flags 4", /*Register banks are overlayable*/
+ "A REG_BANK_1 size 0 flags 4",
+ "A REG_BANK_2 size 0 flags 4",
+ "A REG_BANK_3 size 0 flags 4",
+ "A BSEG size 0 flags 80", /*BSEG must be just before BITS*/
+ "A BSEG_BYTES size 0 flags 0", /*Size will be obtained from BSEG in lnkarea()*/
+ "A BIT_BANK size 0 flags 4", /*Bit register bank is overlayable*/
+ "A DSEG size 0 flags 0",
+ "A OSEG size 0 flags 4",
+ "A ISEG size 0 flags 0",
+ "A SSEG size 0 flags 4",
+ ""
+ };
+ int j;
+ struct sym * sp;
+
+ if (packflag) {
+ for (j = 0; rel2[j][0] != 0; j++) {
+ ip = rel2[j];
+ link_main();
+ }
+ }
+ else {
+ for (j = 0; rel[j][0] != 0; j++) {
+ ip = rel[j];
+ link_main();
+ }
+ }
+
+ /*Set the start address of the default areas:*/
+ for (ap = areap; ap; ap = ap->a_ap) {
+ /**/ if (!strcmp(ap->a_id, "REG_BANK_0")) { ap->a_addr = 0x00; ap->a_bset = 1; }
+ else if (!strcmp(ap->a_id, "REG_BANK_1")) { ap->a_addr = 0x08; ap->a_bset = 1; }
+ else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr = 0x10; ap->a_bset = 1; }
+ else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr = 0x18; ap->a_bset = 1; }
+ else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr = 0x20; ap->a_bset = 1; }
+ else if (TARGET_IS_8051 && !strcmp(ap->a_id, "SSEG")) {
+ if (stacksize) ap->a_axp->a_size = stacksize;
+ }
+ }
+
+ sp = lkpsym("l_IRAM", 1);
+ sp->s_addr = ((iram_size>0) && (iram_size<=0x100)) ? iram_size : 0x0100;
+ sp->s_axp = NULL;
+ sp->s_type |= S_DEF;
+}
+/* end sdld 8051 specific */
+
+/*)Function int main(argc,argv)
+ *
+ * int argc number of command line arguments + 1
+ * char * argv[] array of pointers to the command line
+ * arguments
+ *
+ * The function main() evaluates the command line arguments to
+ * determine if the linker parameters are to input through 'stdin'
+ * or read from a command file. The functions nxtline() and parse()
+ * are to input and evaluate the linker parameters. The linking process
+ * proceeds by making the first pass through each .rel file in the order
+ * presented to the linker. At the end of the first pass the setarea(),
+ * lnkarea(), setgbl(), and symdef() functions are called to evaluate
+ * the base address terms, link all areas, define global variables,
+ * and look for undefined symbols. Following these routines a linker
+ * map file may be produced and the linker output files may be opened.
+ * The second pass through the .rel files will output the linked data
+ * in one of the supported formats.
+ *
+ * local variables:
+ * int c character from argument string
+ * int i loop counter
+ * int j loop counter
+ * int k loop counter
+ *
+ * global variables:
+ * text line in ib[]
+ * lfile *cfp The pointer *cfp points to the
+ * current lfile structure
+ * char ctype[] array of character types, one per
+ * ASCII character
+ * lfile *filep The pointer *filep points to the
+ * beginning of a linked list of
+ * lfile structures.
+ * head *hp Pointer to the current
+ * head structure
+ * char ib[NINPUT] .rel file text line
+ * char *ip pointer into the .rel file
+ * lfile *linkp pointer to first lfile structure
+ * containing an input .rel file
+ * specification
+ * int lkerr error flag
+ * int oflag Output file type flag
+ * int objflg Linked file/library output object flag
+ * int pass linker pass number
+ * int pflag print linker command file flag
+ * int radix current number conversion radix
+ * FILE *sfp The file handle sfp points to the
+ * currently open file
+ * lfile *startp aslink startup file structure
+ * FILE * stdout c_library
+ *
+ * functions called:
+ * VOID chkbank() lkbank.c
+ * int fclose() c_library
+ * int fprintf() c_library
+ * VOID library() lklibr.c
+ * VOID link_main() lkmain.c
+ * VOID lkexit() lkmain.c
+ * VOID lkfopen() lkbank.c
+ * VOID lnkarea() lkarea.c
+ * VOID map() lkmain.c
+ * VOID new() lksym.c
+ * int nxtline() lklex.c
+ * int parse() lkmain.c
+ * VOID reloc() lkreloc.c
+ * VOID search() lklibr.c
+ * VOID setarea() lkarea.c
+ * VOID setbank() lkbank.c
+ * VOID setgbl() lkmain.c
+ * char * sprintf() c_library
+ * VOID symdef() lksym.c
+ * VOID usage() lkmain.c
+ * int fndidx() lkmain.c
+ *
+ * side effects:
+ * Completion of main() completes the linking process
+ * and may produce a map file (.map) and/or a linked
+ * data files (.ihx or .s19) and/or one or more
+ * relocated listing files (.rst).
+ */
+
+int
+main(int argc, char *argv[])
+{
+ int c, i, j, k;
+
+ if (intsiz() < 4) {
+ fprintf(stderr, "?ASlink-Error-Size of INT32 is not 32 bits or larger.\n\n");
+ exit(ER_FATAL);
+ }
+
+ /* sdas specific */
+ /* sdas initialization */
+ sdld_init(argv[0]);
+
+ /* use these defaults for parsing the .lnk script */
+ a_bytes = 4;
+ a_mask = 0xFFFFFFFF;
+ s_mask = 0x80000000;
+ v_mask = 0x7FFFFFFF;
+ /* end sdas specific */
+
+ if (!is_sdld())
+ fprintf(stdout, "\n");
+
+ startp = (struct lfile *) new (sizeof (struct lfile));
+ startp->f_idp = "";
+
+ pflag = 1;
+
+ for(i=1; i<argc; i++) {
+ ip = ib;
+ if(argv[i][0] == '-') {
+ j = i;
+ k = 1;
+ while((c = argv[j][k]) != '\0') {
+ ip = ib;
+ sprintf(ip, "-%c", c);
+ switch(c) {
+
+ /*
+ * Options with arguments
+ */
+ case 'b':
+ case 'B':
+
+ case 'g':
+ case 'G':
+
+ case 'k':
+ case 'K':
+
+ case 'l':
+ case 'L':
+
+ case 'f':
+ case 'F':
+
+ case 'I':
+ case 'X':
+ case 'C':
+ case 'S':
+ strcat(ip, " ");
+ if (i < argc - 1)
+ strcat(ip, argv[++i]);
+ else
+ strcpy(ip, "");
+ break;
+ /*
+ * Preprocess these commands
+ */
+ case 'n':
+ case 'N':
+ pflag = 0;
+ break;
+
+ case 'p':
+ case 'P':
+ pflag = 1;
+ break;
+
+ /*
+ * Options without arguments
+ */
+ default:
+ break;
+ }
+ if(pflag)
+ fprintf(stdout, "ASlink >> %s\n", ip);
+ parse();
+ k++;
+ }
+ } else {
+ strcpy(ip, argv[i]);
+ if(pflag)
+ fprintf(stdout, "ASlink >> %s\n", ip);
+ parse();
+ }
+ }
+
+ if (linkp == NULL)
+ usage(ER_FATAL);
+
+ /*
+ * If no input file is specified
+ * then assume a single file with
+ * the same name as the output file.
+ */
+ if (lfp == linkp) {
+ lfp->f_flp = (struct lfile *) new (sizeof (struct lfile));
+ lfp = lfp->f_flp;
+ lfp->f_idp = strsto(linkp->f_idp);
+ lfp->f_idx = fndidx(linkp->f_idp);
+ lfp->f_obj = objflg;
+ lfp->f_type = F_REL;
+ }
+
+ syminit();
+
+#if SDCDB
+ /*
+ * Open SDCC Debug output file
+ */
+ SDCDBfopen();
+#endif
+
+ for (pass=0; pass<2; ++pass) {
+ cfp = NULL;
+ sfp = NULL;
+ filep = linkp->f_flp;
+ hp = NULL;
+ radix = 10;
+
+ /* sdld specific */
+ if (TARGET_IS_8051)
+ Areas51(); /*JCF: Create the default 8051 areas in the right order*/
+ /* end sdld specific */
+
+ while (nxtline()) {
+ ip = ib;
+ link_main();
+ }
+ if (pass == 0) {
+ /*
+ * Search libraries for global symbols
+ */
+ search();
+
+ /* sdas specific */
+ /* use these defaults for parsing the .lk script */
+ a_bytes = 4;
+ a_mask = 0xFFFFFFFF;
+ s_mask = 0x80000000;
+ v_mask = 0x7FFFFFFF;
+ /* end sdas specific */
+
+ /*
+ * Set area base addresses.
+ */
+ setarea();
+ /*
+ * Set bank base addresses.
+ */
+ setbank();
+ /*
+ * Link all area addresses.
+ */
+ if (!packflag)
+ lnkarea();
+ else {
+ /* sdld 8051 specific */
+ lnkarea2();
+ /* end sdld 8051 specific */
+ }
+ /*
+ * Check bank size limits.
+ */
+ chkbank(stderr);
+ /*
+ * Process global definitions.
+ */
+ setgbl();
+ /*
+ * Check for undefined globals.
+ */
+ symdef(stderr);
+#if NOICE
+ /*
+ * Open NoICE output file
+ */
+ NoICEfopen();
+#endif
+ /*
+ * Output Link Map.
+ */
+ map();
+
+ /* sdld specific */
+ if (sflag) { /*JCF: memory usage summary output*/
+ if (!packflag) {
+ if (summary(areap)) lkexit(1);
+ }
+ else {
+ /* sdld 8051 specific */
+ if (summary2(areap)) lkexit(1);
+ /* end sdld 8051 specific */
+ }
+ }
+
+ if ((iram_size) && (!packflag))
+ iramcheck();
+ /* end sdld specific */
+
+ /*
+ * Open output file(s)
+ */
+ lkfopen();
+ } else {
+ /*
+ * Link in library files
+ */
+ library();
+ /*
+ * Complete Processing
+ */
+ reloc('E');
+ }
+ }
+ if (TARGET_IS_8051) {
+ //JCF:
+ CreateAOMF51();
+ }
+
+ lkexit(lkerr ? ER_ERROR : ER_NONE);
+ return(0);
+}
+
+/*)Function int intsiz()
+ *
+ * The function intsiz() returns the size of INT32
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+int
+intsiz()
+{
+ return(sizeof(a_uint));
+}
+
+/*)Function VOID lkexit(i)
+ *
+ * int i exit code
+ *
+ * The function lkexit() explicitly closes all open
+ * files and then terminates the program.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp file handle for .noi
+ * FILE * mfp file handle for .map
+ * FILE * rfp file hanlde for .rst
+ * FILE * sfp file handle for .rel
+ * FILE * tfp file handle for .lst
+ *
+ * functions called:
+ * int fclose() c_library
+ * VOID exit() c_library
+ * VOID lkfclose() lkbank.c
+ *
+ * side effects:
+ * All files closed. Program terminates.
+ */
+
+VOID
+lkexit(i)
+int i;
+{
+ lkfclose();
+#if NOICE
+ if (jfp != NULL) fclose(jfp);
+#endif
+ if (mfp != NULL) fclose(mfp);
+ if (rfp != NULL) fclose(rfp);
+ if (sfp != NULL) { if (sfp != stdin) fclose(sfp); }
+ if (tfp != NULL) fclose(tfp);
+#if SDCDB
+ if (yfp != NULL) fclose(yfp);
+#endif
+ exit(i);
+}
+
+/*)Function link_main()
+ *
+ * The function link_main() evaluates the directives for each line of
+ * text read from the .rel file(s). The valid directives processed
+ * are:
+ * X, D, Q, H, M, A, S, T, R, and P.
+ *
+ * local variables:
+ * int c first non blank character of a line
+ *
+ * global variables:
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * head *hp Pointer to the current
+ * head structure
+ * int a_bytes T Line address bytes
+ * int hilo Byte ordering
+ * int pass linker pass number
+ * int radix current number conversion radix
+ *
+ * functions called:
+ * char endline() lklex.c
+ * VOID module() lkhead.c
+ * VOID newarea() lkarea.c
+ * VOID newhead() lkhead.c
+ * sym * newsym() lksym.c
+ * VOID NoICEmagic() lknoice.c
+ * VOID reloc() lkreloc.c
+ *
+ * side effects:
+ * Head, area, and symbol structures are created and
+ * the radix is set as the .rel file(s) are read.
+ */
+
+VOID
+link_main()
+{
+ char c;
+
+ if ((c=endline()) == 0) { return; }
+ switch (c) {
+
+ /* sdld specific */
+ case 'O': /* For some important sdcc options */
+ if (is_sdld() && pass == 0) {
+ if (NULL == optsdcc) {
+ optsdcc = strsto(&ip[1]);
+ optsdcc_module = hp->m_id;
+ }
+ else {
+ if (strcmp(optsdcc, &ip[1]) != 0) {
+ fprintf(stderr,
+ "?ASlink-Warning-Conflicting sdcc options:\n"
+ " \"%s\" in module \"%s\" and\n"
+ " \"%s\" in module \"%s\".\n",
+ optsdcc, optsdcc_module, &ip[1], hp->m_id);
+ lkerr++;
+ }
+ }
+ }
+ break;
+ /* end sdld specific */
+
+ case 'X':
+ case 'D':
+ case 'Q':
+ ASxxxx_VERSION = 3;
+ a_bytes = 2; /* use default if unspecified */
+ hilo = 0; /* use default if unspecified */
+ if (c == 'X') { radix = 16; } else
+ if (c == 'D') { radix = 10; } else
+ if (c == 'Q') { radix = 8; }
+
+ while ((c = get()) != 0) {
+ switch(c) {
+ case 'H':
+ hilo = 1;
+ break;
+
+ case 'L':
+ hilo = 0;
+ break;
+
+ case '2':
+ a_bytes = 2;
+ break;
+
+ case '3':
+ a_bytes = 3;
+ break;
+
+ case '4':
+ a_bytes = 4;
+ break;
+
+ default:
+ break;
+ }
+ }
+#ifdef LONGINT
+ switch(a_bytes) {
+ default:
+ a_bytes = 2;
+ case 2:
+ a_mask = 0x0000FFFFl;
+ s_mask = 0x00008000l;
+ v_mask = 0x00007FFFl;
+ break;
+
+ case 3:
+ a_mask = 0x00FFFFFFl;
+ s_mask = 0x00800000l;
+ v_mask = 0x007FFFFFl;
+ break;
+
+ case 4:
+ a_mask = 0xFFFFFFFFl;
+ s_mask = 0x80000000l;
+ v_mask = 0x7FFFFFFFl;
+ break;
+ }
+#else
+ switch(a_bytes) {
+ default:
+ a_bytes = 2;
+ case 2:
+ a_mask = 0x0000FFFF;
+ s_mask = 0x00008000;
+ v_mask = 0x00007FFF;
+ break;
+
+ case 3:
+ a_mask = 0x00FFFFFF;
+ s_mask = 0x00800000;
+ v_mask = 0x007FFFFF;
+ break;
+
+ case 4:
+ a_mask = 0xFFFFFFFF;
+ s_mask = 0x80000000;
+ v_mask = 0x7FFFFFFF;
+ break;
+ }
+#endif
+ break;
+
+ case 'H':
+ if (pass == 0) {
+ newhead();
+ } else {
+ if (hp == 0) {
+ hp = headp;
+ } else {
+ hp = hp->h_hp;
+ }
+ }
+ sdp.s_area = NULL;
+ sdp.s_areax = NULL;
+ sdp.s_addr = 0;
+ break;
+
+ case 'M':
+ if (pass == 0)
+ module();
+ break;
+
+ case 'A':
+ if (pass == 0)
+ newarea();
+ if (sdp.s_area == NULL) {
+ sdp.s_area = areap;
+ sdp.s_areax = areap->a_axp;
+ sdp.s_addr = 0;
+ }
+ break;
+
+ case 'S':
+ if (pass == 0)
+ newsym();
+ break;
+
+ case 'T':
+ case 'R':
+ case 'P':
+ if (pass == 0)
+ break;
+ reloc(c);
+ break;
+
+#if NOICE
+ case ';':
+ unget(c);
+ NoICEmagic();
+ break;
+#endif
+
+ default:
+ break;
+ }
+}
+
+/*)Function VOID map()
+ *
+ * The function map() opens the output map file and calls the various
+ * routines to
+ * (1) output the variables in each area,
+ * (2) list the files processed with module names,
+ * (3) list the libraries file processed,
+ * (4) list base address definitions,
+ * (5) list global variable definitions, and
+ * (6) list any undefined variables.
+ *
+ * local variables:
+ * int i counter
+ * head * hdp pointer to head structure
+ * lbfile *lbfh pointer to library file structure
+ *
+ * global variables:
+ * area *ap Pointer to the current
+ * area structure
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * base *basep The pointer to the first
+ * base structure
+ * base *bsp Pointer to the current
+ * base structure
+ * lfile *filep The pointer *filep points to the
+ * beginning of a linked list of
+ * lfile structures.
+ * globl *globlp The pointer to the first
+ * globl structure
+ * globl *gsp Pointer to the current
+ * globl structure
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * lbfile *lbfhead The pointer to the first
+ * lbfile structure of a linked list
+ * lfile *linkp pointer to first lfile structure
+ * containing an input REL file
+ * specification
+ * int lop current line number on page
+ * int mflag Map output flag
+ * FILE *mfp Map output file handle
+ * int page current page number
+ *
+ * functions called:
+ * FILE * afile() lkmain.c
+ * int fprintf() c_library
+ * VOID lkexit() lkmain.c
+ * VOID lstarea() lklist.c
+ * VOID newpag() lklist.c
+ * VOID chkbank() lkbank.c
+ * VOID symdef() lksym.c
+ *
+ * side effects:
+ * The map file is created.
+ */
+
+VOID
+map(void)
+{
+ int i;
+ struct head *hdp;
+ struct lbfile *lbfh;
+
+ if (mflag == 0) return;
+
+ /*
+ * Open Map File
+ */
+ mfp = afile(linkp->f_idp, "map", 1);
+ if (mfp == NULL) {
+ lkexit(ER_FATAL);
+ }
+
+ /*
+ * Output Map Bank/Area Lists
+ */
+ page = 0;
+ lop = NLPP;
+ for (bp = bankp; bp != NULL; bp = bp->b_bp) {
+ for (ap = areap; ap != NULL; ap = ap->a_ap) {
+ if (ap->a_bp == bp)
+ lstarea(ap, bp);
+ }
+ }
+
+ /*
+ * List Linked Files
+ */
+ newpag(mfp);
+ fprintf(mfp, "\nFiles Linked [ module(s) ]\n\n");
+ hdp = headp;
+ filep = linkp->f_flp;
+ while (filep) {
+ if (strlen (filep->f_idp) > 40)
+ fprintf(mfp, "%s\n%40s [ ", filep->f_idp, "");
+ else
+ fprintf(mfp, "%-40.40s [ ", filep->f_idp);
+ i = 0;
+ while ((hdp != NULL) && (hdp->h_lfile == filep)) {
+ if (i)
+ fprintf(mfp, ",\n%44s", "");
+ fprintf(mfp, "%-.32s", hdp->m_id);
+ hdp = hdp->h_hp;
+ i++;
+ }
+ fprintf(mfp, " ]\n");
+ filep = filep->f_flp;
+ }
+ fprintf(mfp, "\n");
+ /*
+ * List Linked Libraries
+ */
+ if (lbfhead != NULL) {
+ fprintf(mfp, "\nLibraries Linked [ object file ]\n\n");
+ for (lbfh=lbfhead; lbfh; lbfh=lbfh->next) {
+ if (strlen (lbfh->libspc) > 40)
+ fprintf(mfp, "%s\n%40s [ %-.32s ]\n",
+ lbfh->libspc, "", lbfh->relfil);
+ else
+ fprintf(mfp, "%-40.40s [ %-.32s ]\n",
+ lbfh->libspc, lbfh->relfil);
+ }
+ fprintf(mfp, "\n");
+ }
+ /*
+ * List Base Address Definitions
+ */
+ if (basep) {
+ newpag(mfp);
+ fprintf(mfp, "\nUser Base Address Definitions\n\n");
+ bsp = basep;
+ while (bsp) {
+ fprintf(mfp, "%s\n", bsp->b_strp);
+ bsp = bsp->b_base;
+ }
+ }
+ /*
+ * List Global Definitions
+ */
+ if (globlp) {
+ newpag(mfp);
+ fprintf(mfp, "\nUser Global Definitions\n\n");
+ gsp = globlp;
+ while (gsp) {
+ fprintf(mfp, "%s\n", gsp->g_strp);
+ gsp = gsp->g_globl;
+ }
+ }
+ fprintf(mfp, "\n\f");
+ chkbank(mfp);
+ symdef(mfp);
+}
+
+/*)Function int parse()
+ *
+ * The function parse() evaluates all command line or file input
+ * linker directives and updates the appropriate variables.
+ *
+ * local variables:
+ * int c character value
+ * int sv_type save type of processing
+ * char fid[] file id string
+ *
+ * global variables:
+ * char ctype[] array of character types, one per
+ * ASCII character
+ * lfile *lfp pointer to current lfile structure
+ * being processed by parse()
+ * lfile *linkp pointer to first lfile structure
+ * containing an input REL file
+ * specification
+ * int mflag Map output flag
+ * int oflag Output file type flag
+ * int objflg Linked file/library output object flag
+ * int pflag print linker command file flag
+ * FILE * stderr c_library
+ * int uflag Relocated listing flag
+ * int xflag Map file radix type flag
+ * int wflag Wide listing format
+ * int zflag Disable symbol case sensitivity
+ *
+ * Functions called:
+ * VOID addlib() lklibr.c
+ * VOID addpath() lklibr.c
+ * VOID bassav() lkmain.c
+ * VOID doparse() lkmain.c
+ * int fprintf() c_library
+ * VOID gblsav() lkmain.c
+ * VOID getfid() lklex.c
+ * int get() lklex.c
+ * int getnb() lklex.c
+ * VOID lkexit() lkmain.c
+ * char * strsto() lksym.c
+ * int strlen() c_library
+ * int fndidx() lkmain.c
+ *
+ * side effects:
+ * Various linker flags are updated and the linked
+ * structure lfile is created.
+ */
+
+int
+parse()
+{
+ int c;
+ int sv_type;
+ char fid[NINPUT];
+
+ while ((c = getnb()) != 0) {
+ /* sdld specific */
+ if ( c == ';')
+ return(0);
+ /* end sdld specific */
+ if ( c == '-') {
+ while (ctype[c=get()] & LETTER) {
+ switch(c) {
+
+ case 'C':
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
+ codesav();
+ return(0);
+ }
+ // else fall through
+ case 'c':
+ if (startp->f_type != 0)
+ break;
+ startp->f_type = F_STD;
+ doparse();
+ return(0);
+
+ case 'f':
+ case 'F':
+ if (startp->f_type == F_LNK)
+ return(0);
+ unget(getnb());
+ if (*ip == 0)
+ usage(ER_FATAL);
+ sv_type = startp->f_type;
+ startp->f_idp = strsto(ip);
+ startp->f_idx = fndidx(ip);
+ startp->f_type = F_LNK;
+ doparse();
+ if (sv_type == F_STD) {
+ cfp = NULL;
+ sfp = NULL;
+ startp->f_type = F_STD;
+ filep = startp;
+ }
+ return(0);
+
+ case 'I':
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
+ iramsav();
+ return(0);
+ }
+ // else fall through
+ case 'i':
+ oflag = 1;
+ break;
+
+ case 'S':
+ if (TARGET_IS_8051) {
+ unget(getnb());
+ if (ip && *ip)
+ {
+ stacksize = expr(0);
+ if (stacksize > 256) stacksize = 256;
+ else if (stacksize < 0) stacksize = 0;
+ }
+ return(0);
+ }
+ // else fall through
+ case 's':
+ oflag = 2;
+ break;
+
+ case 't':
+ case 'T':
+ oflag = 3;
+ break;
+
+ case 'o':
+ case 'O':
+ objflg = 0;
+ break;
+
+ case 'v':
+ case 'V':
+ objflg = 1;
+ break;
+
+ case 'M':
+ /*JCF: memory usage summary output*/
+ if (is_sdld()) {
+ sflag = 1;
+ break;
+ }
+ // else fall through
+ case 'm':
+ mflag = 1;
+ break;
+
+#if NOICE
+ case 'j':
+ case 'J':
+ jflag = 1;
+ break;
+#endif
+
+ case 'r':
+ case 'R':
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB))
+ rflag = 1;
+ else
+ goto err;
+ break;
+
+ case 'u':
+ case 'U':
+ uflag = 1;
+ break;
+
+ case 'X':
+ if (is_sdld() && !(TARGET_IS_Z80 || TARGET_IS_GB)) {
+ xramsav();
+ return(0);
+ }
+ // else fall through
+ case 'x':
+ xflag = 0;
+ break;
+
+ case 'q':
+ case 'Q':
+ xflag = 1;
+ break;
+
+ case 'd':
+ case 'D':
+ xflag = 2;
+ break;
+
+ case 'E':
+ if (TARGET_IS_6808) {
+ oflag = 4;
+ break;
+ }
+ // else fall through
+ case 'e':
+ return(1);
+
+ case 'n':
+ case 'N':
+ pflag = 0;
+ break;
+
+ case 'p':
+ case 'P':
+ pflag = 1;
+ break;
+
+ case 'b':
+ case 'B':
+ bassav();
+ return(0);
+
+ case 'g':
+ case 'G':
+ gblsav();
+ return(0);
+
+ case 'k':
+ case 'K':
+ addpath();
+ return(0);
+
+ case 'l':
+ case 'L':
+ addlib();
+ return(0);
+
+ case 'w':
+ case 'W':
+ wflag = 1;
+ break;
+
+#if SDCDB
+ case 'Y':
+ if (TARGET_IS_8051) {
+ unget(getnb());
+ packflag=1;
+ break;
+ }
+ // else fall through
+ case 'y':
+ yflag = 1;
+ break;
+#endif
+
+ case 'z':
+ case 'Z':
+ zflag = 1;
+ break;
+
+ default:
+ err:
+ fprintf(stderr,
+ "Unknown option -%c ignored\n", c);
+ break;
+ }
+ }
+ /* sdld specific */
+ if ( c == ';')
+ return(0);
+ /* end sdld specific */
+ } else
+ if (!(ctype[c] & ILL)) {
+ if (linkp == NULL) {
+ linkp = (struct lfile *)
+ new (sizeof (struct lfile));
+ lfp = linkp;
+ lfp->f_type = F_OUT;
+ } else {
+ lfp->f_flp = (struct lfile *)
+ new (sizeof (struct lfile));
+ lfp = lfp->f_flp;
+ lfp->f_type = F_REL;
+ }
+ getfid(fid, c);
+ lfp->f_idp = strsto(fid);
+ lfp->f_obj = objflg;
+ } else {
+ fprintf(stderr, "Invalid input\n");
+ lkexit(ER_FATAL);
+ }
+ }
+ return(0);
+}
+
+/*)Function VOID doparse()
+ *
+ * The function doparse() evaluates all interactive
+ * command line or file input linker directives and
+ * updates the appropriate variables.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * stdin standard input
+ * FILE * stdout standard output
+ * lfile *cfp The pointer *cfp points to the
+ * current lfile structure
+ * FILE *sfp The file handle sfp points to the
+ * currently open file
+ * char ib[NINPUT] .rel file text line
+ * char *ip pointer into the .rel file
+ * lfile *filep The pointer *filep points to the
+ * beginning of a linked list of
+ * lfile structures.
+ * lfile *startp asmlnk startup file structure
+ * int pflag print linker command file flag
+ *
+ * Functions called:
+ * int fclose() c_library
+ * int fprintf() c_library
+ * VOID getfid() lklex.c
+ * int nxtline() lklex.c
+ * int parse() lkmain.c
+ *
+ * side effects:
+ * Various linker flags are updated and the linked
+ * structure lfile may be updated.
+ */
+
+VOID
+doparse()
+{
+ cfp = NULL;
+ sfp = NULL;
+ filep = startp;
+ while (1) {
+ ip = ib;
+ if (nxtline() == 0)
+ break;
+ if (pflag && cfp->f_type != F_STD)
+ fprintf(stdout, "ASlink >> %s\n", ip);
+ if (*ip == 0 || parse())
+ break;
+ }
+ if((sfp != NULL) && (sfp != stdin)) {
+ fclose(sfp);
+ }
+ sfp = NULL;
+ startp->f_idp = "";
+ startp->f_idx = 0;
+ startp->f_type = 0;
+}
+
+/*)Function VOID bassav()
+ *
+ * The function bassav() creates a linked structure containing
+ * the base address strings input to the linker.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * base *basep The pointer to the first
+ * base structure
+ * base *bsp Pointer to the current
+ * base structure
+ * char *ip pointer into the REL file
+ * text line in ib[]
+ *
+ * functions called:
+ * int getnb() lklex.c
+ * VOID * new() lksym.c
+ * int strlen() c_library
+ * char * strcpy() c_library
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * The basep structure is created.
+ */
+
+VOID
+bassav()
+{
+ if (basep == NULL) {
+ basep = (struct base *)
+ new (sizeof (struct base));
+ bsp = basep;
+ } else {
+ bsp->b_base = (struct base *)
+ new (sizeof (struct base));
+ bsp = bsp->b_base;
+ }
+ unget(getnb());
+ bsp->b_strp = (char *) new (strlen(ip)+1);
+ strcpy(bsp->b_strp, ip);
+}
+
+
+/*)Function VOID gblsav()
+ *
+ * The function gblsav() creates a linked structure containing
+ * the global variable strings input to the linker.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * globl *globlp The pointer to the first
+ * globl structure
+ * globl *gsp Pointer to the current
+ * globl structure
+ * char *ip pointer into the REL file
+ * text line in ib[]
+ * int lkerr error flag
+ *
+ * functions called:
+ * int getnb() lklex.c
+ * VOID * new() lksym.c
+ * int strlen() c_library
+ * char * strcpy() c_library
+ * VOID unget() lklex.c
+ *
+ * side effects:
+ * The globlp structure is created.
+ */
+
+VOID
+gblsav()
+{
+ if (globlp == NULL) {
+ globlp = (struct globl *)
+ new (sizeof (struct globl));
+ gsp = globlp;
+ } else {
+ gsp->g_globl = (struct globl *)
+ new (sizeof (struct globl));
+ gsp = gsp->g_globl;
+ }
+ unget(getnb());
+ gsp->g_strp = (char *) new (strlen(ip)+1);
+ strcpy(gsp->g_strp, ip);
+}
+
+
+/*)Function VOID setgbl()
+ *
+ * The function setgbl() scans the global variable lines in the
+ * globlp structure, evaluates the arguments, and sets a variable
+ * to this value.
+ *
+ * local variables:
+ * int v expression value
+ * char id[] base id string
+ * sym * sp pointer to a symbol structure
+ *
+ * global variables:
+ * char *ip pointer into the REL file
+ * text line in ib[]
+ * globl *globlp The pointer to the first
+ * globl structure
+ * globl *gsp Pointer to the current
+ * globl structure
+ * FILE * stderr c_library
+ * int lkerr error flag
+ *
+ * functions called:
+ * a_uint expr() lkeval.c
+ * int fprintf() c_library
+ * VOID getid() lklex.c
+ * int getnb() lklex.c
+ * sym * lkpsym() lksym.c
+ *
+ * side effects:
+ * The value of a variable is set.
+ */
+
+VOID
+setgbl()
+{
+ int v;
+ struct sym *sp;
+ char id[NCPS];
+
+ gsp = globlp;
+ while (gsp) {
+ ip = gsp->g_strp;
+ getid(id, -1);
+ if (getnb() == '=') {
+ v = (int) expr(0);
+ sp = lkpsym(id, 0);
+ if (sp == NULL) {
+ fprintf(stderr,
+ "No definition of symbol %s\n", id);
+ lkerr++;
+ } else {
+ if (sp->s_type & S_DEF) {
+ fprintf(stderr,
+ "Redefinition of symbol %s\n", id);
+ lkerr++;
+ sp->s_axp = NULL;
+ }
+ sp->s_addr = v;
+ sp->s_type |= S_DEF;
+ }
+ } else {
+ fprintf(stderr, "No '=' in global expression");
+ lkerr++;
+ }
+ gsp = gsp->g_globl;
+ }
+}
+
+/*)Function FILE * afile(fn, ft, wf)
+ *
+ * char * fn file specification string
+ * char * ft file type string
+ * int wf 0 ==>> read
+ * 1 ==>> write
+ * 2 ==>> binary write
+ *
+ * The function afile() opens a file for reading or writing.
+ * (1) If the file type specification string ft
+ * is not NULL then a file specification is
+ * constructed with the file path\name in fn
+ * and the extension in ft.
+ * (2) If the file type specification string ft
+ * is NULL then the file specification is
+ * constructed from fn. If fn does not have
+ * a file type then the default .rel file
+ * type is appended to the file specification.
+ *
+ * afile() returns a file handle for the opened file or aborts
+ * the assembler on an open error.
+ *
+ * local variables:
+ * int c character value
+ * FILE * fp filehandle for opened file
+ * char * p1 pointer to filespec string fn
+ * char * p2 pointer to filespec string fb
+ * char * p3 pointer to filetype string ft
+ *
+ * global variables:
+ * char afspec[] constructed file specification string
+ * int lkerr error flag
+ *
+ * functions called:
+ * int fndidx() lkmain.c
+ * FILE * fopen() c_library
+ * int fprintf() c_library
+ *
+ * side effects:
+ * File is opened for read or write.
+ */
+
+FILE *
+afile(char *fn, char *ft, int wf)
+{
+ char *p1, *p2;
+ int c;
+ char * frmt;
+ FILE *fp;
+
+ if (strlen(fn) > (FILSPC-7)) {
+ fprintf(stderr, "?ASlink-Error-<filspc too long> : \"%s\"\n", fn);
+ lkerr++;
+ return(NULL);
+ }
+
+ /*
+ * Skip The Path
+ */
+ strcpy(afspec, fn);
+ c = fndidx(afspec);
+
+ /*
+ * Skip to File Extension separator
+ */
+ p1 = strrchr(&afspec[c], FSEPX);
+
+ /*
+ * Copy File Extension
+ */
+ p2 = ft ? ft : "";
+ if (*p2 == 0) {
+ if (p1 == NULL) {
+ p2 = LKOBJEXT;
+ } else {
+ p2 = strrchr(&fn[c], FSEPX) + 1;
+ }
+ }
+ if (p1 == NULL) {
+ p1 = &afspec[strlen(afspec)];
+ }
+ *p1++ = FSEPX;
+ while ((c = *p2++) != 0) {
+ if (p1 < &afspec[FILSPC-1])
+ *p1++ = c;
+ }
+ *p1++ = 0;
+
+ /*
+ * Select Read/Write/Binary Write
+ */
+ switch(wf) {
+ default:
+ case 0: frmt = "r"; break;
+ case 1: frmt = "w"; break;
+#ifdef DECUS
+ case 2: frmt = "wn"; break;
+#else
+ case 2: frmt = "wb"; break;
+#endif
+ }
+ if ((fp = fopen(afspec, frmt)) == NULL && strcmp(ft,"adb") != 0) { /* Do not complain for optional adb files */
+ fprintf(stderr, "?ASlink-Error-<cannot %s> : \"%s\"\n", wf?"create":"open", afspec);
+ lkerr++;
+ }
+ return (fp);
+}
+
+/*)Function int fndidx(str)
+ *
+ * char * str file specification string
+ *
+ * The function fndidx() scans the file specification string
+ * to find the index to the file name. If the file
+ * specification contains a 'path' then the index will
+ * be non zero.
+ *
+ * fndidx() returns the index value.
+ *
+ * local variables:
+ * char * p1 temporary pointer
+ * char * p2 temporary pointer
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * char * strrchr() c_library
+ *
+ * side effects:
+ * none
+ */
+
+int
+fndidx(str)
+char *str;
+{
+ char *p1, *p2;
+
+ /*
+ * Skip Path Delimiters
+ */
+ p1 = str;
+ if ((p2 = strrchr(p1, ':')) != NULL) { p1 = p2 + 1; }
+ if ((p2 = strrchr(p1, '/')) != NULL) { p1 = p2 + 1; }
+ if ((p2 = strrchr(p1, '\\')) != NULL) { p1 = p2 + 1; }
+
+ return((int) (p1 - str));
+}
+
+/*)Function int fndext(str)
+ *
+ * char * str file specification string
+ *
+ * The function fndext() scans the file specification string
+ * to find the file.ext separater.
+ *
+ * fndext() returns the index to FSEPX or the end of the string.
+ *
+ * local variables:
+ * char * p1 temporary pointer
+ * char * p2 temporary pointer
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * char * strrchr() c_library
+ *
+ * side effects:
+ * none
+ */
+
+int
+fndext(str)
+char * str;
+{
+ char *p1, *p2;
+
+ /*
+ * Find the file separator
+ */
+ p1 = str + strlen(str);
+ if ((p2 = strrchr(str, FSEPX)) != NULL) { p1 = p2; }
+
+ return((int) (p1 - str));
+}
+
+/* sdld specific */
+/*)Function VOID iramsav()
+ *
+ * The function iramsav() stores the size of the chip's internal RAM.
+ * This is used after linking to check that variable assignment to this
+ * dataspace didn't overflow into adjoining segments. Variables in the
+ * DSEG, OSEG, and ISEG are assigned to this dataspace.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * char *ip pointer into the REL file
+ * text line in ib[]
+ * unsigned int size of chip's internal
+ * iram_size RAM segment
+ *
+ * functions called:
+ * int getnb() lklex.c
+ * VOID unget() lklex.c
+ * a_uint expr() lkeval.c
+ *
+ * side effects:
+ * The iram_size may be modified.
+ */
+
+VOID
+iramsav()
+{
+ unget(getnb());
+ if (ip && *ip)
+ iram_size = expr(0); /* evaluate size expression */
+ else
+ iram_size = 128; /* Default is 128 (0x80) bytes */
+ if ((iram_size<=0) || (iram_size>256))
+ iram_size = 128; /* Default is 128 (0x80) bytes */
+}
+
+/*Similar to iramsav but for xram memory*/
+VOID
+xramsav()
+{
+ unget(getnb());
+ if (ip && *ip)
+ xram_size = expr(0); /* evaluate size expression */
+ else
+ xram_size = rflag?0x1000000:0x10000;
+}
+
+/*Similar to iramsav but for code memory*/
+VOID
+codesav()
+{
+ unget(getnb());
+ if (ip && *ip)
+ code_size = expr(0); /* evaluate size expression */
+ else
+ code_size = rflag?0x1000000:0x10000;
+}
+
+
+/*)Function VOID iramcheck()
+ *
+ * The function iramcheck() is used at the end of linking to check that
+ * the internal RAM area wasn't overflowed by too many variable
+ * assignments. Variables in the DSEG, ISEG, and OSEG are assigned to
+ * the chip's internal RAM.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * unsigned int size of chip's internal
+ * iram_size RAM segment
+ * struct area linked list of memory
+ * *areap areas
+ *
+ * functions called:
+ *
+ * side effects:
+ */
+
+VOID
+iramcheck()
+{
+ register unsigned int last_addr;
+ register struct area *ap;
+
+ for (ap = areap; ap; ap=ap->a_ap) {
+ if ((ap->a_size != 0) &&
+ (!strcmp(ap->a_id, "DSEG") ||
+ !strcmp(ap->a_id, "OSEG") ||
+ !strcmp(ap->a_id, "ISEG")
+ )
+ )
+ {
+ last_addr = ap->a_addr + ap->a_size - 1;
+ if (last_addr >= iram_size)
+ fprintf(stderr,
+ "\nWARNING! Segment %s extends past the end\n"
+ " of internal RAM. Check map file.\n",
+ ap->a_id);
+ }
+ }
+}
+/* end sdld specific */
+
+char *usetxt[] = {
+ "Usage: [-Options] [-Option with arg] file",
+ "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+ "Startup:",
+ " -p Echo commands to stdout (default)",
+ " -n No echo of commands to stdout",
+ "Alternates to Command Line Input:",
+ " -c ASlink >> prompt input",
+ " -f file[.lk] Command File input",
+ "Libraries:",
+ " -k Library path specification, one per -k",
+ " -l Library file specification, one per -l",
+ "Relocation:",
+ " -b area base address = expression",
+ " -g global symbol = expression",
+ "Map format:",
+ " -m Map output generated as (out)file[.map]",
+ " -w Wide listing format for map file",
+ " -x Hexadecimal (default)",
+ " -d Decimal",
+ " -q Octal",
+ "Output:",
+ " -i Intel Hex as (out)file[.ihx]",
+ " -s Motorola S Record as (out)file[.s19]",
+// " -t Tandy CoCo Disk BASIC binary as (out)file[.bi-]",
+#if NOICE
+ " -j NoICE Debug output as (out)file[.noi]",
+#endif
+#if SDCDB
+ " -y SDCDB Debug output as (out)file[.cdb]",
+#endif
+// " -o Linked file/library object output enable (default)",
+// " -v Linked file/library object output disable",
+ "List:",
+ " -u Update listing file(s) with link data as file(s)[.rst]",
+ "Case Sensitivity:",
+ " -z Disable Case Sensitivity for Symbols",
+ "End:",
+ " -e or null line terminates input",
+ "",
+ 0
+};
+
+char *usetxt_8051[] = {
+ "Usage: [-Options] [-Option with arg] file",
+ "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+ "Startup:",
+ " -p Echo commands to stdout (default)",
+ " -n No echo of commands to stdout",
+ "Alternates to Command Line Input:",
+ " -c ASlink >> prompt input",
+ " -f file[.lk] Command File input",
+ "Libraries:",
+ " -k Library path specification, one per -k",
+ " -l Library file specification, one per -l",
+ "Relocation:",
+ " -b area base address = expression",
+ " -g global symbol = expression",
+ "Map format:",
+ " -m Map output generated as (out)file[.map]",
+ " -w Wide listing format for map file",
+ " -x Hexadecimal (default)",
+ " -d Decimal",
+ " -q Octal",
+ "Output:",
+ " -i Intel Hex as (out)file[.ihx]",
+ " -s Motorola S Record as (out)file[.s19]",
+#if NOICE
+ " -j NoICE Debug output as (out)file[.noi]",
+#endif
+#if SDCDB
+ " -y SDCDB Debug output as (out)file[.cdb]",
+#endif
+ "List:",
+ " -u Update listing file(s) with link data as file(s)[.rst]",
+ "Case Sensitivity:",
+ " -z Disable Case Sensitivity for Symbols",
+ "Miscellaneous:\n"
+ " -I [iram-size] Check for internal RAM overflow",
+ " -X [xram-size] Check for external RAM overflow",
+ " -C [code-size] Check for code overflow",
+ " -M Generate memory usage summary file[.mem]",
+ " -Y Pack internal ram",
+ " -S [stack-size] Allocate space for stack",
+ "End:",
+ " -e or null line terminates input",
+ "",
+ 0
+};
+
+char *usetxt_6808[] = {
+ "Usage: [-Options] [-Option with arg] file",
+ "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+ "Startup:",
+ " -p Echo commands to stdout (default)",
+ " -n No echo of commands to stdout",
+ "Alternates to Command Line Input:",
+ " -c ASlink >> prompt input",
+ " -f file[.lk] Command File input",
+ "Libraries:",
+ " -k Library path specification, one per -k",
+ " -l Library file specification, one per -l",
+ "Relocation:",
+ " -b area base address = expression",
+ " -g global symbol = expression",
+ "Map format:",
+ " -m Map output generated as (out)file[.map]",
+ " -w Wide listing format for map file",
+ " -x Hexadecimal (default)",
+ " -d Decimal",
+ " -q Octal",
+ "Output:",
+ " -i Intel Hex as (out)file[.ihx]",
+ " -s Motorola S Record as (out)file[.s19]",
+ " -E ELF executable as file[.elf]",
+#if NOICE
+ " -j NoICE Debug output as (out)file[.noi]",
+#endif
+#if SDCDB
+ " -y SDCDB Debug output as (out)file[.cdb]",
+#endif
+ "List:",
+ " -u Update listing file(s) with link data as file(s)[.rst]",
+ "Case Sensitivity:",
+ " -z Disable Case Sensitivity for Symbols",
+ "Miscellaneous:\n"
+ " -I [iram-size] Check for internal RAM overflow",
+ " -X [xram-size] Check for external RAM overflow",
+ " -C [code-size] Check for code overflow",
+ " -M Generate memory usage summary file[.mem]",
+ "End:",
+ " -e or null line terminates input",
+ "",
+ 0
+};
+
+char *usetxt_z80_gb[] = {
+ "Usage: [-Options] [-Option with arg] file",
+ "Usage: [-Options] [-Option with arg] outfile file1 [file2 ...]",
+ "Startup:",
+ " -p Echo commands to stdout (default)",
+ " -n No echo of commands to stdout",
+ "Alternates to Command Line Input:",
+ " -c ASlink >> prompt input",
+ " -f file[.lk] Command File input",
+ "Libraries:",
+ " -k Library path specification, one per -k",
+ " -l Library file specification, one per -l",
+ "Relocation:",
+ " -b area base address = expression",
+ " -g global symbol = expression",
+ "Map format:",
+ " -m Map output generated as (out)file[.map]",
+ " -w Wide listing format for map file",
+ " -x Hexadecimal (default)",
+ " -d Decimal",
+ " -q Octal",
+ "Output:",
+ " -i Intel Hex as (out)file[.ihx]",
+ " -s Motorola S Record as (out)file[.s19]",
+#if SDCDB
+ " -y SDCDB Debug output as (out)file[.cdb]",
+#endif
+ "List:",
+ " -u Update listing file(s) with link data as file(s)[.rst]",
+ "Case Sensitivity:",
+ " -z Disable Case Sensitivity for Symbols",
+ "End:",
+ " -e or null line terminates input",
+ "",
+ 0
+};
+
+/*)Function VOID usage(n)
+ *
+ * int n exit code
+ *
+ * The function usage() outputs to the stderr device the
+ * linker name and version and a list of valid linker options.
+ *
+ * local variables:
+ * char ** dp pointer to an array of
+ * text string pointers.
+ *
+ * global variables:
+ * FILE * stderr c_library
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * none
+ */
+
+VOID
+usage(int n)
+{
+ char **dp;
+
+ /* sdld specific */
+ fprintf(stderr, "\n%s Linker %s\n\n", is_sdld() ? "sdld" : "ASxxxx", VERSION);
+ for (dp = TARGET_IS_8051 ? usetxt_8051 : (TARGET_IS_6808 ? usetxt_6808 : ((TARGET_IS_Z80 || TARGET_IS_GB) ? usetxt_z80_gb : usetxt)); *dp; dp++)
+ fprintf(stderr, "%s\n", *dp);
+ /* end sdld specific */
+ lkexit(n);
+}
+
+/*)Function VOID copyfile()
+ *
+ * FILE *dest destination file
+ * FILE *src source file
+ *
+ * function will copy source file to destination file
+ *
+ *
+ * functions called:
+ * int fgetc() c_library
+ * int fputc() c_library
+ *
+ * side effects:
+ * none
+ */
+VOID
+copyfile (FILE *dest, FILE *src)
+{
+ int ch;
+
+ while ((ch = fgetc(src)) != EOF) {
+ fputc(ch,dest);
+ }
+}
--- /dev/null
+/* lkmem.c - Create a memory summary file with extension .mem
+
+ Copyright (C) 2002 Jesus Calvino-Fraga, jesusc at ieee dot org
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "sdld.h"
+#include "aslink.h"
+
+int summary(struct area * areap)
+{
+ if (TARGET_IS_8051 || TARGET_IS_6808) {
+ /* only for 8051 and 6808 targets */
+
+ #define EQ(A,B) !strcasecmp((A),(B))
+ #define MIN_STACK 16
+ #define REPORT_ERROR(A, H) \
+ {\
+ fprintf(of, "%s%s", (H)?"*** ERROR: ":"", (A)); \
+ fprintf(stderr, "%s%s", (H)?"\n?ASlink-Error-":"",(A)); \
+ toreturn=1; \
+ }
+
+ #define REPORT_WARNING(A, H) \
+ { \
+ fprintf(of, "%s%s", (H)?"*** WARNING: ":"", (A)); \
+ fprintf(stderr, "%s%s",(H)?"\n?ASlink-Warning-":"", (A)); \
+ }
+
+ char buff[128];
+ int j, toreturn=0;
+ unsigned int Total_Last=0, k;
+
+ struct area * xp;
+ FILE * of;
+
+ /*Artifacts used for printing*/
+ char start[15], end[15], size[15], max[15];
+ char format[]=" %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
+ char line[]="---------------------";
+
+ typedef struct
+ {
+ unsigned long Start;
+ unsigned long Size;
+ unsigned long Max;
+ char Name[NCPS];
+ unsigned long flag;
+ } _Mem;
+
+ unsigned int dram[0x100];
+ _Mem Ram8051[] = {
+ {0, 8, 8, "REG_BANK_0", 0x0001},
+ {0x8, 8, 8, "REG_BANK_1", 0x0002},
+ {0x10, 8, 8, "REG_BANK_2", 0x0004},
+ {0x18, 8, 8, "REG_BANK_3", 0x0008},
+ {0x20, 0, 16, "BSEG_BYTES", 0x0010},
+ {0, 0, 128, "UNUSED", 0x0000},
+ {0x7f, 0, 128, "DATA", 0x0020},
+ {0, 0, 128, "TOTAL:", 0x0000}
+ };
+
+ _Mem IRam8051 = {0xff, 0, 128, "INDIRECT RAM", 0x0080};
+ _Mem Stack8051 = {0xff, 0, 1, "STACK", 0x0000};
+ _Mem XRam8051 = {0xffff, 0, 65536, "EXTERNAL RAM", 0x0100};
+ _Mem Rom8051 = {0xffff, 0, 65536, "ROM/EPROM/FLASH", 0x0200};
+
+ _Mem Ram6808[] = {
+ {0, 0, 0, "REG_BANK_0", 0x0001},
+ {0x0, 0, 0, "REG_BANK_1", 0x0002},
+ {0x0, 0, 0, "REG_BANK_2", 0x0004},
+ {0x0, 0, 0, "REG_BANK_3", 0x0008},
+ {0x0, 0, 0, "BSEG_BYTES", 0x0010},
+ {0, 0, 256, "UNUSED", 0x0000},
+ {0xff, 0, 256, "DATA", 0x0020},
+ {0, 0, 256, "TOTAL:", 0x0000}
+ };
+
+ _Mem IRam6808 = {0xff, 0, 0, "INDIRECT RAM", 0x0080};
+ _Mem Stack6808 = {0xff, 0, 1, "STACK", 0x0000};
+ _Mem XRam6808 = {0xffff, 0, 65536, "EXTERNAL RAM", 0x0100};
+ _Mem Rom6808 = {0xffff, 0, 65536, "ROM/EPROM/FLASH", 0x0200};
+
+ _Mem *Ram = NULL;
+
+ _Mem IRam = {0, 0, 0, "", 0};
+ _Mem Stack = {0, 0, 0, "", 0};
+ _Mem XRam = {0, 0, 0, "", 0};
+ _Mem Rom = {0, 0, 0, "", 0};
+
+ if (TARGET_IS_8051) {
+ Ram = Ram8051;
+ memcpy(&IRam, &IRam8051, sizeof (_Mem));
+ memcpy(&Stack, &Stack8051, sizeof (_Mem));
+ memcpy(&XRam, &XRam8051, sizeof (_Mem));
+ memcpy(&Rom, &Rom8051, sizeof (_Mem));
+ }
+ else {
+ Ram = Ram6808;
+ memcpy(&IRam, &IRam6808, sizeof (_Mem));
+ memcpy(&Stack, &Stack6808, sizeof (_Mem));
+ memcpy(&XRam, &XRam6808, sizeof (_Mem));
+ memcpy(&Rom, &Rom6808, sizeof (_Mem));
+ }
+
+ if (stacksize == 0) stacksize = MIN_STACK;
+
+ if (TARGET_IS_8051) {
+ if(rflag) /*For the DS390*/
+ {
+ XRam.Max=0x1000000; /*24 bits*/
+ XRam.Start=0xffffff;
+ Rom.Max=0x1000000;
+ Rom.Start=0xffffff;
+ }
+
+ if((iram_size<=0)||(iram_size>0x100)) /*Default: 8052 like memory*/
+ {
+ Ram[5].Max=0x80;
+ Ram[6].Max=0x80;
+ Ram[7].Max=0x80;
+ IRam.Max=0x80;
+ iram_size=0x100;
+ }
+ else if(iram_size<0x80)
+ {
+ Ram[5].Max=iram_size;
+ Ram[6].Max=iram_size;
+ Ram[7].Max=iram_size;
+ IRam.Max=0;
+ }
+ else
+ {
+ Ram[5].Max=0x80;
+ Ram[6].Max=0x80;
+ Ram[7].Max=0x80;
+ IRam.Max=iram_size-0x80;
+ }
+ }
+
+ for(j=0; j<(int)iram_size; j++) dram[j]=0;
+ for(; j<0x100; j++) dram[j]=0x8000; /*Memory not available*/
+
+ /* Open Memory Summary File*/
+ of = afile(linkp->f_idp, "mem", 1);
+ if (of == NULL)
+ {
+ lkexit(1);
+ }
+
+ xp=areap;
+ while (xp)
+ {
+ /**/ if (EQ(xp->a_id, "REG_BANK_0"))
+ {
+ Ram[0].Size=xp->a_size;
+ }
+ else if (EQ(xp->a_id, "REG_BANK_1"))
+ {
+ Ram[1].Size=xp->a_size;
+ }
+ else if (EQ(xp->a_id, "REG_BANK_2"))
+ {
+ Ram[2].Size=xp->a_size;
+ }
+ else if (EQ(xp->a_id, "REG_BANK_3"))
+ {
+ Ram[3].Size=xp->a_size;
+ }
+ else if (EQ(xp->a_id, "BSEG_BYTES"))
+ {
+ if (TARGET_IS_8051)
+ Ram[4].Size+=xp->a_size;
+ else
+ Ram[4].Size=xp->a_size;
+ }
+
+ else if (EQ(xp->a_id, "SSEG"))
+ {
+ Stack.Size+=xp->a_size;
+ if(xp->a_addr<Stack.Start) Stack.Start=xp->a_addr;
+ }
+
+ else if (EQ(xp->a_id, "ISEG"))
+ {
+ IRam.Size+=xp->a_size;
+ if(xp->a_addr<IRam.Start) IRam.Start=xp->a_addr;
+ }
+
+ else if (TARGET_IS_8051)
+ {
+ if(xp->a_flag & A_XDATA)
+ {
+ if(xp->a_size>0)
+ {
+ XRam.Size+=xp->a_size;
+ if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
+ }
+ }
+
+ else if (EQ(xp->a_id, "BIT_BANK"))
+ {
+ Ram[4].Size+=xp->a_size;
+ }
+
+ else if(xp->a_flag & A_CODE)
+ {
+ if(xp->a_size>0)
+ {
+ Rom.Size+=xp->a_size;
+ if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
+ }
+ }
+ }
+
+ else if(TARGET_IS_6808)
+ {
+ if ( EQ(xp->a_id, "DSEG") || EQ(xp->a_id, "OSEG") )
+ {
+ Ram[6].Size+=xp->a_size;
+ if(xp->a_addr<Ram[6].Start) Ram[6].Start=xp->a_addr;
+ }
+
+ else if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") ||
+ EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") )
+ {
+ Rom.Size+=xp->a_size;
+ if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
+ }
+
+ else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG"))
+ {
+ XRam.Size+=xp->a_size;
+ if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
+ }
+ }
+
+ /*If is not a register bank, bit, stack, or idata, then it should be data*/
+ else if((TARGET_IS_8051 && xp->a_flag & (A_CODE|A_BIT|A_XDATA))==0)
+ {
+ if(xp->a_size)
+ {
+ Ram[6].Size+=xp->a_size;
+ if(xp->a_addr<Ram[6].Start) Ram[6].Start=xp->a_addr;
+ }
+ }
+
+ xp=xp->a_ap;
+ }
+
+ for(j=0; j<7; j++)
+ for(k=Ram[j].Start; (k<(Ram[j].Start+Ram[j].Size))&&(k<0x100); k++)
+ dram[k]|=Ram[j].flag; /*Mark as used*/
+
+ if (TARGET_IS_8051) {
+ for(k=IRam.Start; (k<(IRam.Start+IRam.Size))&&(k<0x100); k++)
+ dram[k]|=IRam.flag; /*Mark as used*/
+ }
+
+ /*Compute the amount of unused memory in direct data Ram. This is the
+ gap between the last register bank or bit segment and the data segment.*/
+ for(k=Ram[6].Start-1; (dram[k]==0) && (k>0); k--);
+ Ram[5].Start=k+1;
+ Ram[5].Size=Ram[6].Start-Ram[5].Start; /*It may be zero (which is good!)*/
+
+ /*Compute the data Ram totals*/
+ for(j=0; j<7; j++)
+ {
+ if(Ram[7].Start>Ram[j].Start) Ram[7].Start=Ram[j].Start;
+ Ram[7].Size+=Ram[j].Size;
+ }
+ Total_Last=Ram[6].Size+Ram[6].Start-1;
+
+ /*Report the Ram totals*/
+ fprintf(of, "Direct Internal RAM:\n");
+ fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+
+ for(j=0; j<8; j++)
+ {
+ if((j==0) || (j==7)) fprintf(of, format, line, line, line, line, line);
+ if((j!=5) || (Ram[j].Size>0))
+ {
+ sprintf(start, "0x%02lx", Ram[j].Start);
+ if(Ram[j].Size==0)
+ end[0]=0;/*Empty string*/
+ else
+ sprintf(end, "0x%02lx", j==7?Total_Last:Ram[j].Size+Ram[j].Start-1);
+ sprintf(size, "%5lu", Ram[j].Size);
+ sprintf(max, "%5lu", Ram[j].Max);
+ fprintf(of, format, Ram[j].Name, start, end, size, max);
+ }
+ }
+
+ if (TARGET_IS_8051) {
+ for(k=Ram[6].Start; (k<(Ram[6].Start+Ram[6].Size))&&(k<0x100); k++)
+ {
+ if(dram[k]!=Ram[6].flag)
+ {
+ sprintf(buff, "Internal memory overlap starting at 0x%02x.\n", k);
+ REPORT_ERROR(buff, 1);
+ break;
+ }
+ }
+
+ if(Ram[4].Size>Ram[4].Max)
+ {
+ k=Ram[4].Size-Ram[4].Max;
+ sprintf(buff, "Insufficient bit addressable memory. "
+ "%d byte%s short.\n", k, (k==1)?"":"s");
+ REPORT_ERROR(buff, 1);
+ }
+
+ if(Ram[5].Size!=0)
+ {
+ sprintf(buff, "%ld bytes in data memory wasted. "
+ "SDCC link could use: --data-loc 0x%02lx\n",
+ Ram[5].Size, Ram[6].Start-Ram[5].Size);
+ REPORT_WARNING(buff, 1);
+ }
+
+ if((Ram[6].Start+Ram[6].Size)>Ram[6].Max)
+ {
+ k=(Ram[6].Start+Ram[6].Size)-Ram[6].Max;
+ sprintf(buff, "Insufficient space in data memory. "
+ "%d byte%s short.\n", k, (k==1)?"":"s");
+ REPORT_ERROR(buff, 1);
+ }
+ }
+
+ /*Report the position of the beginning of the stack*/
+ fprintf(of, "\n%stack starts at: 0x%02lx (sp set to 0x%02lx)",
+ rflag ? "16 bit mode initial s" : "S", Stack.Start, Stack.Start-1);
+
+ if (TARGET_IS_8051) {
+ /*Check that the stack pointer is landing in a safe place:*/
+ if( (dram[Stack.Start] & 0x8000) == 0x8000 )
+ {
+ fprintf(of, ".\n");
+ sprintf(buff, "Stack set to unavailable memory.\n");
+ REPORT_ERROR(buff, 1);
+ }
+ else if(dram[Stack.Start])
+ {
+ fprintf(of, ".\n");
+ sprintf(buff, "Stack overlaps area ");
+ REPORT_ERROR(buff, 1);
+ for(j=0; j<7; j++)
+ {
+ if(dram[Stack.Start]&Ram[j].flag)
+ {
+ sprintf(buff, "'%s'\n", Ram[j].Name);
+ break;
+ }
+ }
+ if(dram[Stack.Start]&IRam.flag)
+ {
+ sprintf(buff, "'%s'\n", IRam.Name);
+ }
+ REPORT_ERROR(buff, 0);
+ }
+ else
+ {
+ for(j=Stack.Start, k=0; (j<(int)iram_size)&&(dram[j]==0); j++, k++);
+ fprintf(of, " with %d bytes available\n", k);
+ if ((int)k<stacksize)
+ {
+ sprintf(buff, "Only %d byte%s available for stack.\n",
+ k, (k==1)?"":"s");
+ REPORT_WARNING(buff, 1);
+ }
+ }
+ }
+
+ fprintf(of, "\nOther memory:\n");
+ fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+ fprintf(of, format, line, line, line, line, line);
+
+ /*Report IRam totals:*/
+ if(IRam.Size==0)
+ {
+ start[0]=0;/*Empty string*/
+ end[0]=0;/*Empty string*/
+ }
+ else
+ {
+ sprintf(start, "0x%02lx", IRam.Start);
+ sprintf(end, "0x%02lx", IRam.Size+IRam.Start-1);
+ }
+ sprintf(size, "%5lu", IRam.Size);
+ sprintf(max, "%5lu", IRam.Max);
+ fprintf(of, format, IRam.Name, start, end, size, max);
+
+ /*Report XRam totals:*/
+ if(XRam.Size==0)
+ {
+ start[0]=0;/*Empty string*/
+ end[0]=0;/*Empty string*/
+ }
+ else
+ {
+ sprintf(start, "0x%04lx", XRam.Start);
+ sprintf(end, "0x%04lx", XRam.Size+XRam.Start-1);
+ }
+ sprintf(size, "%5lu", XRam.Size);
+ sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
+ fprintf(of, format, XRam.Name, start, end, size, max);
+
+ /*Report Rom/Flash totals:*/
+ if(Rom.Size==0)
+ {
+ start[0]=0;/*Empty string*/
+ end[0]=0;/*Empty string*/
+ }
+ else
+ {
+ sprintf(start, "0x%04lx", Rom.Start);
+ sprintf(end, "0x%04lx", Rom.Size+Rom.Start-1);
+ }
+ sprintf(size, "%5lu", Rom.Size);
+ sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
+ fprintf(of, format, Rom.Name, start, end, size, max);
+
+ /*Report any excess:*/
+ if (TARGET_IS_8051) {
+ if((IRam.Start+IRam.Size)>(IRam.Max+0x80))
+ {
+ sprintf(buff, "Insufficient INDIRECT RAM memory.\n");
+ REPORT_ERROR(buff, 1);
+ }
+ }
+ if( ((XRam.Start+XRam.Size)>XRam.Max) ||
+ (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
+ {
+ sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
+ REPORT_ERROR(buff, 1);
+ }
+ if( ((Rom.Start+Rom.Size)>Rom.Max) ||
+ (((int)Rom.Size>code_size)&&(code_size>=0)) )
+ {
+ sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
+ REPORT_ERROR(buff, 1);
+ }
+
+ fclose(of);
+ return toreturn;
+ }
+ else {
+ assert (0);
+ return 0;
+ }
+}
+
+int summary2(struct area * areap)
+{
+ if (TARGET_IS_8051) {
+ /* only for 8051 target */
+
+ #define EQ(A,B) !strcasecmp((A),(B))
+
+ char buff[128];
+ int toreturn = 0;
+ unsigned int j;
+ unsigned long int Stack_Start=0, Stack_Size;
+
+ struct area * xp;
+ struct area * xstack_xp = NULL;
+ FILE * of;
+
+ /*Artifacts used for printing*/
+ char start[15], end[15], size[15], max[15];
+ char format[]=" %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
+ char line[]="---------------------";
+
+ typedef struct
+ {
+ unsigned long Start;
+ unsigned long End;
+ unsigned long Size;
+ unsigned long Max;
+ char Name[NCPS];
+ unsigned long flag;
+ } _Mem;
+
+ _Mem Stack={0xff, 0, 0, 1, "STACK", 0x0000};
+ _Mem Paged={0xffff, 0, 0, 256, "PAGED EXT. RAM", A3_PAG};
+ _Mem XRam= {0xffff, 0, 0, 65536, "EXTERNAL RAM", 0x0100};
+ _Mem Rom= {0xffff, 0, 0, 65536, "ROM/EPROM/FLASH", 0x0200};
+
+ if(rflag) /*For the DS390*/
+ {
+ XRam.Max=0x1000000; /*24 bits*/
+ XRam.Start=0xffffff;
+ Rom.Max=0x1000000;
+ Rom.Start=0xffffff;
+ }
+
+ /* Open Memory Summary File*/
+ of = afile(linkp->f_idp, "mem", 1);
+ if (of == NULL)
+ {
+ lkexit(1);
+ }
+
+ xp=areap;
+ while (xp)
+ {
+ if (xp->a_flag & A_CODE)
+ {
+ if(xp->a_size)
+ {
+ Rom.Size += xp->a_size;
+ if(xp->a_addr < Rom.Start)
+ Rom.Start = xp->a_addr;
+ if(xp->a_addr + xp->a_size > Rom.End)
+ Rom.End = xp->a_addr + xp->a_size;
+ }
+ }
+
+ else if (EQ(xp->a_id, "SSEG"))
+ {
+ Stack.Size += xp->a_size;
+ if(xp->a_addr < Stack.Start)
+ Stack.Start = xp->a_addr;
+ if(xp->a_addr + xp->a_size > Stack.End)
+ Stack.End = xp->a_addr + xp->a_size;
+ }
+
+ else if (EQ(xp->a_id, "PSEG"))
+ {
+ Paged.Size += xp->a_size;
+ if(xp->a_addr < Paged.Start)
+ Paged.Start = xp->a_addr;
+ if(xp->a_addr + xp->a_size > Paged.End)
+ Paged.End = xp->a_addr + xp->a_size;
+ }
+
+ else if (EQ(xp->a_id, "XSTK"))
+ {
+ xstack_xp = xp;
+ Paged.Size += xp->a_size;
+ if(xp->a_addr < Paged.Start)
+ Paged.Start = xp->a_addr;
+ if(xp->a_addr + xp->a_size > Paged.End)
+ Paged.End = xp->a_addr + xp->a_size;
+ }
+
+ else if (xp->a_flag & A_XDATA)
+ {
+ if(xp->a_size)
+ {
+ XRam.Size += xp->a_size;
+ if(xp->a_addr < XRam.Start)
+ XRam.Start = xp->a_addr;
+ if(xp->a_addr + xp->a_size > XRam.End)
+ XRam.End = xp->a_addr + xp->a_size;
+ }
+ }
+
+ xp = xp->a_ap;
+ }
+
+ /*Report the Ram totals*/
+ fprintf(of, "Internal RAM layout:\n");
+ fprintf(of, " 0 1 2 3 4 5 6 7 8 9 A B C D E F");
+ for(j=0; j<256; j++)
+ {
+ if(j%16==0) fprintf(of, "\n0x%02x:|", j);
+ fprintf(of, "%c|", idatamap[j]);
+ }
+ fprintf(of, "\n0-3:Reg Banks, T:Bit regs, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack, A:Absolute\n");
+
+ for(j=0; j<256; j++)
+ {
+ if(idatamap[j]=='S')
+ {
+ Stack_Start=j;
+ break;
+ }
+ }
+
+ for(j=Stack_Start, Stack_Size=0; j<((iram_size)?iram_size:256); j++)
+ {
+ if((idatamap[j]=='S')||(idatamap[j]==' ')) Stack_Size++;
+ else break;
+ }
+
+ xp=areap;
+ while (xp)
+ {
+ if(xp->a_unaloc>0)
+ {
+ fprintf(of, "\nERROR: Couldn't get %d byte%s allocated"
+ " in internal RAM for area %s.",
+ xp->a_unaloc, xp->a_unaloc>1?"s":"", xp->a_id);
+ toreturn=1;
+ }
+ xp=xp->a_ap;
+ }
+
+ /*Report the position of the begining of the stack*/
+ if(Stack_Start!=256)
+ fprintf(of, "\n%s starts at: 0x%02lx (sp set to 0x%02lx) with %ld bytes available.",
+ rflag ? "16 bit mode initial stack" : "Stack", Stack_Start, Stack_Start-1, Stack_Size);
+ else
+ fprintf(of, "\nI don't have a clue where the stack ended up! Sorry...");
+
+ /*Report about xstack*/
+ if (xstack_xp)
+ {
+ Stack_Start = xstack_xp->a_addr;
+ Stack_Size = xstack_xp->a_size;
+ fprintf(of, "\nXstack starts at: 0x%04lx with %ld bytes available.",
+ Stack_Start, Stack_Size);
+ }
+
+ fprintf(of, "\n\nOther memory:\n");
+ fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+ fprintf(of, format, line, line, line, line, line);
+
+ /*Report Paged XRam totals:*/
+ if(Paged.Size==0)
+ {
+ start[0]=0;/*Empty string*/
+ end[0]=0;/*Empty string*/
+ }
+ else
+ {
+ sprintf(start, "0x%04lx", Paged.Start);
+ sprintf(end, "0x%04lx", Paged.End-1);
+ }
+ sprintf(size, "%5lu", Paged.Size);
+ sprintf(max, "%5lu", xram_size<0 ? Paged.Max : xram_size<256 ? xram_size : 256);
+ fprintf(of, format, Paged.Name, start, end, size, max);
+
+ /*Report XRam totals:*/
+ if(XRam.Size==0)
+ {
+ start[0]=0;/*Empty string*/
+ end[0]=0;/*Empty string*/
+ }
+ else
+ {
+ sprintf(start, "0x%04lx", XRam.Start);
+ sprintf(end, "0x%04lx", XRam.End-1);
+ }
+ sprintf(size, "%5lu", XRam.Size);
+ sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
+ fprintf(of, format, XRam.Name, start, end, size, max);
+
+ /*Report Rom/Flash totals:*/
+ if(Rom.Size==0)
+ {
+ start[0]=0;/*Empty string*/
+ end[0]=0;/*Empty string*/
+ }
+ else
+ {
+ sprintf(start, "0x%04lx", Rom.Start);
+ sprintf(end, "0x%04lx", Rom.End-1);
+ }
+ sprintf(size, "%5lu", Rom.Size);
+ sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
+ fprintf(of, format, Rom.Name, start, end, size, max);
+
+ /*Report any excess:*/
+ if( ((XRam.End) > XRam.Max) ||
+ (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
+ {
+ sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
+ REPORT_ERROR(buff, 1);
+ }
+ if( ((Rom.End) > Rom.Max) ||
+ (((int)Rom.Size>code_size)&&(code_size>=0)) )
+ {
+ sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
+ REPORT_ERROR(buff, 1);
+ }
+
+ fclose(of);
+ return toreturn;
+ }
+ else {
+ assert (0);
+ return 0;
+ }
+}
+
--- /dev/null
+/* lknoice.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ *
+ * Extensions to produce NoICE debug files
+ *
+ * 31-Oct-1997 by John Hartman
+ * 30-Jan-98 JLH add page to DefineNoICE for 8051
+ * 2-Feb-98 JLH Allow optional .nest on local vars - C scoping rules...
+ * 27-May-01 ARB Updated for ASxxxx V4
+ */
+
+#include "aslink.h"
+
+
+#if NOICE
+
+/*Module lknoice.c
+ *
+ * The module lknoice.c contains the functions
+ * required to create a NoICE debug file.
+ *
+ * lknoice.c contains the following functions:
+ * VOID NoICEfopen()
+ * VOID NoICEmagic()
+ * VOID DefineNoICE()
+ * VOID DefineGlobal()
+ * VOID DefineScoped()
+ * VOID DefineFile()
+ * VOID DefineFunction()
+ * VOID DefineStaticFunction()
+ * VOID DefineEndFunction()
+ * VOID DefineLine()
+ * VOID PagedAddress()
+ *
+ * lknoice.c contains these local variables:
+ * struct noicebn *noicebnp pointer to linked structure of
+ * ';!FILE' specifications
+ * char currentFile[] file being processed
+ * char currentFunction[] function being processed
+ */
+
+struct noicefn {
+ struct noicefn *n_np; /* noicefn link */
+ char * n_id; /* file name */
+};
+
+static struct noicefn *noicefnp = NULL;
+
+static char currentFile[NCPS];
+static char currentFunction[NCPS];
+
+
+/*)Function VOID NoICEfopen()
+ *
+ * The function NoICEfopen() opens the NoICE output file
+ * and sets the map flag, mflag, to create a map file.
+ * NoICE processing is performed during map generation.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * int jflag NoICE Debug flag
+ * FILE * jfp NoICE Debug File handle
+ * struct lfile *linkp Pointer to the Linker output file name
+ * int mflag Map output flag
+ *
+ * functions called:
+ * FILE * afile() lkmain.c
+ * VOID lkexit() lkmain.c
+ *
+ * side effects:
+ * The NoICE output file is opened.
+ * Failure to open the file will
+ * terminate the linker.
+ */
+
+VOID NoICEfopen(void)
+{
+ if (jflag) {
+ jfp = afile(linkp->f_idp, "noi", 1);
+ if (jfp == NULL) {
+ lkexit(1);
+ }
+ mflag = 1;
+ }
+}
+
+
+/*)Function VOID NoICEmagic()
+ *
+ * The function NoICEmagic() passes any "magic Comments"
+ * to the NoICE output file. Magic comments are those
+ * beginning with ";!". Also a linked list of file names
+ * specified in ";!FILE" magic comments is created. These
+ * file names are used to verify that symbols in the
+ * ASxxxx .rel files of the form str1.str2 are NoICE symbols.
+ *
+ * local variables:
+ * char id[] id string
+ * struct noicefn * np pointer to new structure
+ * char * p1 temporary string pointer
+ * char * p2 temporary string pointer
+ * struct noicefn * tnp temporary pointer to noicefn structure
+ *
+ * global variables:
+ * char * ip position into the current
+ * input text line
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * VOID getid() lklex.c
+ * VOID * new() lksym.c
+ * int fprintf() c_library
+ * char * strrchr() c_library
+ * char * strsto() lksym.c
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * The NoICE "magic comments" are passed
+ * to the output file. A list of assembler
+ * file names is created.
+ */
+
+VOID NoICEmagic(void)
+{
+ char id[NCPS];
+ char *p1, *p2;
+ struct noicefn *np, *tnp;
+
+ /*
+ * Pass any "magic comments" to NoICE output
+ */
+ if ((ip[0] == ';') && (ip[1] == '!')) {
+ if (jfp) {
+ fprintf(jfp, "%s\n", &ip[2]);
+ }
+ if (pass == 0) {
+ getid(id, -1);
+ if (symeq(id, ";!FILE", 1)) {
+ getid(id, -1);
+ /*
+ * The name starts after the last
+ * '/' (Unices) or
+ * ':' or '\' (DOS)
+ *
+ * and ends at the last
+ * separator 'FSEPX'
+ */
+ p1 = id;
+ if ((p2 = strrchr(p1, '\\')) != NULL) p1 = ++p2;
+ if ((p2 = strrchr(p1, '/')) != NULL) p1 = ++p2;
+ if ((p2 = strrchr(p1, ':')) != NULL) p1 = ++p2;
+ if ((p2 = strrchr(p1, FSEPX)) != NULL) *p2 = 0;
+
+ np = (struct noicefn *) new (sizeof(struct noicefn));
+ if (noicefnp == NULL) {
+ noicefnp = np;
+ } else {
+ tnp = noicefnp;
+ while (tnp->n_np)
+ tnp = tnp->n_np;
+ tnp->n_np = np;
+ }
+ np->n_id = strsto(p1);
+ }
+ }
+ }
+}
+
+
+/*)Function VOID DefineNoICE()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineNoICE() processes the symbols into
+ * NoICE commands for inclusion in the NoICE output file.
+ *
+ * The function is called from lstarea in lklist.c
+ * for each symbol.
+ *
+ * local variables:
+ * int j parsed argument count
+ * int k parsed argument count
+ * int level function level
+ * char token1[] parsed string
+ * char token2[] parsed string
+ * char token2[] parsed string
+ * char sep1 parsed character
+ * char sep2 parsed character
+ * struct noicefn * tnp temporary pointer to noicefn structure
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * VOID DefineFile() lknoice.c
+ * VOID DefineFunction() lknoice.c
+ * VOID DefineStaticFunction() lknoice.c
+ * VOID DefineEndFunction() lknoice.c
+ * VOID DefineScoped() lknoice.c
+ * VOID DefineLine() lknoice.c
+ * VOID DefineGlobal() lknoice.c
+ * VOID PagedAddress() lknoice.c
+ * int sprintf() c_library
+ * int sscanf() c_library
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * NoICE debug commands are placed
+ * into the output file.
+ */
+
+void DefineNoICE( char *name, a_uint value, struct bank *yp )
+{
+ char token1[NCPS]; /* parse for file.function.symbol */
+ char token2[NCPS];
+ char token3[NCPS];
+ char sep1, sep2;
+ int j, k, level;
+ struct noicefn *np;
+
+ /* no output if file is not open */
+ if (jfp == NULL) return;
+
+ j = sscanf( name, "%[^.]%c%[^.]%c%s", token1, &sep1, token2, &sep2, token3 );
+ if (j > 1) {
+ /* verify that first token is a file name */
+ k = 1;
+ np = noicefnp;
+ while (np != NULL) {
+ if (symeq(token1, np->n_id, 1)) {
+ k = j;
+ break;
+ }
+ np = np->n_np;
+ }
+ j = k;
+ }
+
+ switch (j)
+ {
+ /* file.function.symbol, or file.function..SPECIAL */
+ case 5:
+ DefineFile( token1, 0, NULL );
+ if (token3[0] == '.')
+ {
+ if (symeq( token3, ".FN", 1 ) != 0)
+ {
+ /* Global function */
+ DefineFunction( token2, value, yp );
+ }
+ else if (symeq( token3, ".SFN", 1 ) != 0)
+ {
+ /* Static (file-scope) function */
+ DefineStaticFunction( token2, value, yp );
+ }
+ else if (symeq( token3, ".EFN", 1 ) != 0)
+ {
+ /* End of function */
+ DefineEndFunction( value, yp );
+ }
+ }
+ else
+ {
+ /* Function-scope var. */
+ DefineFunction( token2, 0, NULL );
+
+ /* Look for optional level integer */
+ j = sscanf( token3, "%[^.]%c%u", token1, &sep1, &level );
+ if ((j == 3) && (level != 0))
+ {
+ sprintf( &token1[ strlen(token1) ], "_%u", level );
+ }
+ DefineScoped( token1, value, yp );
+ }
+ break;
+
+ /* either file.symbol or file.line# */
+ case 3:
+ DefineFile( token1, 0, NULL );
+ if ((token2[0] >= '0') && (token2[0] <= '9'))
+ {
+ /* Line number */
+ DefineLine( token2, value, yp );
+ }
+ else
+ {
+ /* File-scope symbol. (Kill any function) */
+ DefineEndFunction( 0, NULL );
+ DefineScoped( token2, value, yp );
+ }
+ break;
+
+ /* NoICE file.func. is illegal */
+ case 4:
+
+ /* NoICE symbol. is illegal */
+ case 2:
+
+ /* just a symbol */
+ case 1:
+
+ /* NoICE .symbol is illegal */
+ case 0:
+ default:
+ DefineGlobal( name, value, yp );
+ break;
+ }
+}
+
+
+/*)Function VOID DefineGlobal()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineGlobal() places a DEF statement
+ * in the .noi debug file for the global symbol.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ *
+ * side effects:
+ * A global symbol definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineGlobal( char *name, a_uint value, struct bank *yp )
+{
+ fprintf( jfp, "DEF %s ", name );
+ PagedAddress( value, yp );
+}
+
+
+/*)Function VOID DefineScoped()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineScoped() places a DEFS statement
+ * in the .noi debug file for the scoped symbol.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ *
+ * side effects:
+ * A scoped symbol definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineScoped( char *name, a_uint value, struct bank *yp )
+{
+ fprintf( jfp, "DEFS %s ", name );
+ PagedAddress( value, yp );
+}
+
+
+/*)Function VOID DefineFile()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineFile() places a FILE statement
+ * in the .noi debug file for the processed file.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ * char * strcpy() c_library
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * A file name definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineFile( char *name, a_uint value, struct bank *yp )
+{
+ if (symeq( name, currentFile, 1 ) == 0)
+ {
+ strcpy( currentFile, name );
+ if (value != 0)
+ {
+ fprintf( jfp, "FILE %s ", name );
+ PagedAddress( value, yp );
+ }
+ else
+ {
+ fprintf( jfp, "FILE %s\n", name );
+ }
+ }
+}
+
+
+/*)Function VOID DefineFunction()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineFunction() places a FUNC statement
+ * in the .noi debug file for the processed symbol. If
+ * a vaulue is present then a preceeding DEF statement is
+ * also placed in the .noi debug file.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ * char * strcpy() c_library
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * A function definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineFunction( char *name, a_uint value, struct bank *yp )
+{
+ if (symeq( name, currentFunction, 1 ) == 0)
+ {
+ strcpy( currentFunction, name );
+ if (value != 0)
+ {
+ fprintf( jfp, "DEF %s ", name );
+ PagedAddress( value, yp );
+ fprintf( jfp, "FUNC %s ", name );
+ PagedAddress( value, yp );
+ }
+ else
+ {
+ fprintf( jfp, "FUNC %s\n", name );
+ }
+ }
+}
+
+
+/*)Function VOID DefineStaticFunction()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineStaticFunction() places a SFUNC statement
+ * in the .noi debug file for the processed file. If
+ * a value is present then a preceeding DEFS statement is
+ * also placed in the .noi debug file.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ * char * strcpy() c_library
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * A static function definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineStaticFunction( char *name, a_uint value, struct bank *yp )
+{
+ if (symeq( name, currentFunction, 1 ) == 0)
+ {
+ strcpy( currentFunction, name );
+ if (value != 0)
+ {
+ fprintf( jfp, "DEFS %s ", name );
+ PagedAddress( value, yp );
+ fprintf( jfp, "SFUNC %s ", name );
+ PagedAddress( value, yp );
+ }
+ else
+ {
+ fprintf( jfp, "SFUNC %s\n", name );
+ }
+ }
+}
+
+
+/*)Function VOID DefineEndFunction()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineEndFunction() places an ENDF statement
+ * in the .noi debug file for the processed file.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ * char * strcpy() c_library
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * An end function definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineEndFunction( a_uint value, struct bank *yp )
+{
+ if (currentFunction[0] != 0)
+ {
+ if (value != 0)
+ {
+ fprintf( jfp, "ENDF " );
+ PagedAddress( value, yp );
+ }
+ else
+ {
+ fprintf( jfp, "ENDF\n" );
+ }
+
+ currentFunction[0] = 0;
+ }
+}
+
+
+/*)Function VOID DefineLine()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function DefineLine() places a LINE statement
+ * in the .noi debug file for the processed file.
+ *
+ * local variables:
+ * int indigit converted digit
+ * int lineNumber converted line number
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID PagedAddress() lknoice.c
+ * int digit() lkeval.c
+ *
+ * side effects:
+ * A Line definition is
+ * placed in the .noi debug file.
+ */
+
+void DefineLine( char *lineString, a_uint value, struct bank *yp )
+{
+ int indigit, lineNumber;
+
+ lineNumber = 0;
+ while( (indigit=digit( *lineString++, 10 )) >= 0)
+ {
+ lineNumber = 10*lineNumber + indigit;
+ }
+ fprintf( jfp, "LINE %u ", lineNumber );
+ PagedAddress( value, yp );
+}
+
+
+/*)Function VOID PagedAddress()
+ *
+ * a_uint value value of symbol
+ * struct bank * yp pointer to associated bank
+ *
+ * The function PagedAddress() places the value
+ * in the .noi debug file for the processed value.
+ * If the current bank is "mapped" then the page
+ * number preceeds the value as xx:.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * FILE * jfp NoICE Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * A value is appended to the current
+ * line placed in the .noi debug file.
+ */
+
+void PagedAddress( a_uint value, struct bank *yp )
+{
+ if (yp->b_flag & B_MAP) {
+ fprintf( jfp, "%X:0x%X\n", yp->b_map, value );
+ } else {
+ fprintf( jfp, "0x%X\n", value );
+ }
+}
+
+#endif
--- /dev/null
+/* lkout.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With enhancements by
+ *
+ * G. Osborn
+ * gary@s-4.com.
+ */
+
+#include "aslink.h"
+
+/*)Module lkout.c
+ *
+ * The module lkout.c contains the dispatch
+ * function to create the relocated object
+ * code output in the required format.
+ *
+ * lkout.c contains the following functions:
+ * VOID lkout()
+ * VOID lkflush()
+ * VOID ixx()
+ * VOID iflush()
+ * VOID dbx()
+ * VOID dflush()
+ *
+ * lkout.c contains no local variables.
+ */
+
+/*)Function lkout(i)
+ *
+ * int i 1 - process data
+ * 0 - end of data
+ *
+ * The function lkout() dispatches to the
+ * required output format routine.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * int oflag output type flag
+ * int obj_flag Output enabled flag
+ * FILE * ofp output file handle
+ * a_uint pc Current relocation address
+ * int pcb Current pc bytes per address
+ *
+ * functions called:
+ * VOID ixx() lkout.c
+ * VOID s19() lks19.c
+ * VOID dbx() lkout.c
+ * VOID elf() lkelf.c
+ *
+ * side effects:
+ * The REL data is output in the required format.
+ */
+
+VOID
+lkout(int i, int b)
+{
+ int j;
+
+ if (i && obj_flag) { return; }
+ if (ofp == NULL) { return; }
+
+ /*
+ * Create the Byte Output Address
+ */
+ for (j=1; j<pcb; j++) {
+ adb_xb(pc, 0);
+ }
+
+ /*
+ * Intel Formats
+ */
+ if (oflag == 1) {
+ ixx(i, b);
+ } else
+ /*
+ * Motorola Formats
+ */
+ if (oflag == 2) {
+ s19(i);
+ } else
+ /*
+ * Disk Basic Formats
+ */
+ if (oflag == 3) {
+ dbx(i);
+ } else
+ /*
+ * Elf Formats
+ */
+ if (oflag == 4) {
+ elf(i);
+ }
+}
+
+
+/*)Function lkflush()
+ *
+ * The function lkflush() dispatches
+ * to the required data flushing routine.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * int oflag output type flag
+ * FILE * ofp output file handle
+ *
+ * functions called:
+ * VOID iflush() lkout.c
+ * VOID sflush() lks19.c
+ * VOID dflush() lkout.c
+ *
+ * side effects:
+ * Any remaining REL data is flushed
+ * to the output file.
+ */
+
+VOID
+lkflush()
+{
+ if (ofp == NULL) { return; }
+
+ /*
+ * Intel Formats
+ */
+ if (oflag == 1) {
+ iflush();
+ } else
+ /*
+ * Motorola Formats
+ */
+ if (oflag == 2) {
+ sflush();
+ } else
+ /*
+ * Disk Basic Formats
+ */
+ if (oflag == 3) {
+ dflush();
+ }
+}
+
+
+/*Intel Format
+ * Record Mark Field - This field signifies the start of a
+ * record, and consists of an ascii colon
+ * (:).
+ *
+ * Record Length Field - This field consists of two ascii
+ * characters which indicate the number of
+ * data bytes in this record. The
+ * characters are the result of converting
+ * the number of bytes in binary to two
+ * ascii characters, high digit first. An
+ * End of File record contains two ascii
+ * zeros in this field.
+ *
+ * Load Address Field - This field consists of the four ascii
+ * characters which result from converting
+ * the the binary value of the address in
+ * which to begin loading this record. The
+ * order is as follows:
+ *
+ * High digit of high byte of address.
+ * Low digit of high byte of address.
+ * High digit of low byte of address.
+ * Low digit of low byte of address.
+ *
+ * In an End of File record this field con-
+ * sists of four ascii zeros, in a start
+ * address record this is the program entry
+ * address (low), or in a segment record
+ * this is the high order address.
+ *
+ * Record Type Field - This field identifies the record type,
+ * which is either 0 for data records, 1
+ * for an End of File record, 3 for a
+ * start address, or 4 for a
+ * segment record. It consists
+ * of two ascii characters, with the high
+ * digit of the record type first, followed
+ * by the low digit of the record type.
+ *
+ * Data Field - This field consists of the actual data,
+ * converted to two ascii characters, high
+ * digit first. There are no data bytes in
+ * the End of File record.
+ *
+ * Checksum Field - The checksum field is the 8 bit binary
+ * sum of the record length field, the load
+ * address field, the record type field,
+ * and the data field. This sum is then
+ * negated (2's complement) and converted
+ * to two ascii characters, high digit
+ * first.
+ */
+
+/*)Function ixx(i, b)
+ *
+ * int i 1 - process data
+ * 0 - end of data
+ * int b - bank tag
+ *
+ * The function ixx() loads the output buffer with
+ * the relocated data.
+ *
+ * local variables:
+ * a_uint chksum byte checksum
+ * a_uint lo_addr address within segment
+ * a_uint hi_addr segment number
+ * int i loop counter
+ * a_uint j temporary
+ * int k loop counter
+ * struct sym *sp symbol pointer
+ * a_uint symadr symbol address
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * int hilo byte order
+ * FILE * ofp output file handle
+ * int rtaflg first output flag
+ * int rtcnt count of data words
+ * int rtflg[] output the data flag
+ * a_uint rtval[] relocated data
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ * a_uint rtadr2 address temporary
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID iflush() lkout.c
+ *
+ * side effects:
+ * The data is placed into the output buffer.
+ */
+
+/*
+ * The number of Data Field bytes is:
+ *
+ * 1 Record Mark Field
+ * 2 Record Length Field
+ * 4 Load Address Field
+ * 2 Record Type Field
+ * 2 Checksum Field
+ *
+ * Plus 32 data bytes (64 characters)
+ */
+
+static int i_lb = -1;
+
+VOID
+ixx(int i, int b)
+{
+ int k;
+ struct sym *sp;
+ a_uint j, symadr, chksum;
+
+ if (i) {
+ if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
+ return;
+
+ if (hilo == 0) {
+ switch(a_bytes){
+ default:
+ case 2:
+ j = rtval[0];
+ rtval[0] = rtval[1];
+ rtval[1] = j;
+ break;
+ case 3:
+ j = rtval[0];
+ rtval[0] = rtval[2];
+ rtval[2] = j;
+ break;
+ case 4:
+ j = rtval[0];
+ rtval[0] = rtval[3];
+ rtval[3] = j;
+ j = rtval[2];
+ rtval[2] = rtval[1];
+ rtval[1] = j;
+ break;
+ }
+ }
+ for (i=0,rtadr2=0; i<a_bytes; i++) {
+ rtadr2 = (rtadr2 << 8) | rtval[i];
+ }
+ if ((rtadr2 != rtadr1) || rtaflg || b != i_lb) {
+ /*
+ * data bytes not contiguous between records
+ */
+ iflush();
+ i_lb = b;
+ rtadr0 = rtadr1 = rtadr2;
+ rtaflg = 0;
+ }
+ for (k=a_bytes; k<rtcnt; k++) {
+ if (rtflg[k]) {
+ rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
+ if ((rtadr1 & 0xffff) == 0) {
+ iflush();
+ }
+ if (rtadr1 - rtadr0 == IXXMAXBYTES) {
+ iflush();
+ }
+ }
+ }
+ } else {
+ sp = lkpsym(".__.END.", 0);
+ if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
+ symadr = symval(sp);
+ chksum = 0x04;
+ chksum += 0x05;
+ chksum += symadr;
+ chksum += symadr >> 8;
+ chksum += symadr >> 16;
+ chksum += symadr >> 24;
+#ifdef LONGINT
+ fprintf(ofp, ":04000005%08lX%02lX\n", symadr, (~chksum + 1) & 0x00ff);
+#else
+ fprintf(ofp, ":04000005%08X%02X\n", symadr, (~chksum + 1) & 0x00ff);
+#endif
+ }
+
+ fprintf(ofp, ":00000001FF\n");
+ }
+}
+
+
+/*)Function iflush()
+ *
+ * The function iflush() outputs the relocated data
+ * in the standard Intel format.
+ *
+ * local variables:
+ * a_uint chksum byte checksum
+ * a_uint lo_addr address within segment
+ * a_uint hi_addr segment number
+ * int i loop counter
+ * int max number of data bytes
+ * int reclen record length
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * FILE * ofp output file handle
+ * int rtaflg first output flag
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * The data is output to the file defined by ofp.
+ */
+
+/*
+ * This function derived from the work
+ * of G. Osborn, gary@s-4.com.
+ * The new version concatenates the assembler
+ * output records when they represent contiguous
+ * memory segments to produce IXXMAXBYTES data byte
+ * Intel Hex output lines whenever possible, resulting
+ * in a substantial reduction in file size.
+ * More importantly, the download time
+ * to the target system is much improved.
+ */
+
+VOID
+iflush(void)
+{
+ int i, max, reclen;
+ a_uint chksum, lo_addr, hi_addr;
+
+ max = (int) (rtadr1 - rtadr0);
+ if (max) {
+ if (a_bytes > 2) {
+ static a_uint prev_hi_addr = 0;
+
+ hi_addr = (rtadr0 >> 16) & 0xffff;
+ if ((hi_addr != prev_hi_addr) || rtaflg) {
+ chksum = 0x02;
+ chksum += 0x04;
+ chksum += hi_addr;
+ chksum += hi_addr >> 8;
+#ifdef LONGINT
+ fprintf(ofp, "%02X:02000004%04lX%02lX\n", i_lb, hi_addr, (~chksum + 1) & 0x00ff);
+#else
+ fprintf(ofp, "%02X:02000004%04X%02X\n", i_lb, hi_addr, (~chksum + 1) & 0x00ff);
+#endif
+ prev_hi_addr = hi_addr;
+ }
+ }
+
+ /*
+ * Only the ":" and the checksum itself are excluded
+ * from the checksum. The record length includes
+ * only the data bytes.
+ */
+ lo_addr = rtadr0 & 0xffff;
+ reclen = max;
+ chksum = reclen;
+ chksum += lo_addr;
+ chksum += lo_addr >> 8;
+#ifdef LONGINT
+ fprintf(ofp, "%02X:%02X%04lX00", i_lb, reclen, lo_addr);
+#else
+ fprintf(ofp, "%02X:%02X%04X00", i_lb, reclen, lo_addr);
+#endif
+ for (i=0; i<max; i++) {
+ chksum += rtbuf[i];
+ fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
+ }
+ /*
+ * 2's complement
+ */
+#ifdef LONGINT
+ fprintf(ofp, "%02lX\n", (~chksum + 1) & 0x00ff);
+#else
+ fprintf(ofp, "%02X\n", (~chksum + 1) & 0x00ff);
+#endif
+ rtadr0 = rtadr1;
+ }
+
+}
+
+#if 0
+/*)S19/S28/S37 Formats
+ * Record Type Field - This field signifies the start of a
+ * record and identifies the the record
+ * type as follows:
+ *
+ * 2-Byte Address: Ascii S1 - Data Record
+ * Ascii S9 - End of File Record
+ * 3-Byte Address: Ascii S2 - Data Record
+ * Ascii S8 - End of File Record
+ * 4-Byte Address: Ascii S3 - Data Record
+ * Ascii S7 - End of File Record
+ *
+ * Record Length Field - This field specifies the record length
+ * which includes the address, data, and
+ * checksum fields. The 8 bit record
+ * length value is converted to two ascii
+ * characters, high digit first.
+ *
+ * Load Address Field - This field consists of the 4/6/8 ascii
+ * characters which result from converting
+ * the the binary value of the address in
+ * which to begin loading this record. The
+ * order is as follows:
+ *
+ * S37: High digit of fourth byte of address.
+ * Low digit of fourth byte of address.
+ * S28/S37: High digit of third byte of address.
+ * Low digit of third byte of address.
+ * S19/S28/S37: High digit of high byte of address.
+ * Low digit of high byte of address.
+ * High digit of low byte of address.
+ * Low digit of low byte of address.
+ *
+ * In an End of File record this field con-
+ * sists of either 4/6/8 ascii zeros or the
+ * program entry address.
+ *
+ * Data Field - This field consists of the actual data,
+ * converted to two ascii characters, high
+ * digit first. There are no data bytes in
+ * the End of File record.
+ *
+ * Checksum Field - The checksum field is the 8 bit binary
+ * sum of the record length field, the load
+ * address field, and the data field. This
+ * sum is then complemented (1's comple-
+ * ment) and converted to two ascii
+ * characters, high digit first.
+ */
+
+/*)Function sxx(i)
+ *
+ * int i 1 - process data
+ * 0 - end of data
+ *
+ * The function s19() loads the output buffer with
+ * the relocated data.
+ *
+ * local variables:
+ * a_uint addr address temporary
+ * a_uint chksum byte checksum
+ * char * frmt format string pointer
+ * int i loop counter
+ * a_uint j temporary
+ * int k loop counter
+ * int max number of data bytes
+ * int reclen record length
+ * struct sym *sp symbol pointer
+ * a_uint symadr symbol address
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * int hilo byte order
+ * FILE * ofp output file handle
+ * int rtcnt count of data words
+ * int rtflg[] output the data flag
+ * a_uint rtval[] relocated data
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ * a_uint rtadr2 address temporary
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID sflush() lkout.c
+ *
+ * side effects:
+ * The data is placed into the output buffer.
+ */
+
+/*
+ * Number of Data Field bytes is:
+ *
+ * 2 Record Type Field
+ * 2 Record Length Field
+ * 4/6/8 Load Address Field
+ * 2 Checksum Field
+ *
+ * Plus 32 data bytes (64 characters)
+ */
+
+VOID
+sxx(i)
+int i;
+{
+ struct sym *sp;
+ char *frmt;
+ int k, reclen;
+ a_uint j, addr, symadr, chksum;
+
+ if (i) {
+ if (hilo == 0) {
+ switch(a_bytes){
+ default:
+ case 2:
+ j = rtval[0];
+ rtval[0] = rtval[1];
+ rtval[1] = j;
+ break;
+ case 3:
+ j = rtval[0];
+ rtval[0] = rtval[2];
+ rtval[2] = j;
+ break;
+ case 4:
+ j = rtval[0];
+ rtval[0] = rtval[3];
+ rtval[3] = j;
+ j = rtval[2];
+ rtval[2] = rtval[1];
+ rtval[1] = j;
+ break;
+ }
+ }
+ for (i=0,rtadr2=0; i<a_bytes; i++) {
+ rtadr2 = (rtadr2 << 8) | rtval[i];
+ }
+
+ if (rtadr2 != rtadr1) {
+ /*
+ * data bytes not contiguous between records
+ */
+ sflush();
+ rtadr0 = rtadr1 = rtadr2;
+ }
+ for (k=a_bytes; k<rtcnt; k++) {
+ if (rtflg[k]) {
+ rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
+ if (rtadr1 - rtadr0 == SXXMAXBYTES) {
+ sflush();
+ }
+ }
+ }
+ } else {
+ /*
+ * Only the "S_" and the checksum itself are excluded
+ * from the checksum. The record length does not
+ * include "S_" and the pair count. It does
+ * include the address bytes, the data bytes,
+ * and the checksum.
+ */
+ reclen = 1 + a_bytes;
+ chksum = reclen;
+ sp = lkpsym(".__.END.", 0);
+ if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
+ symadr = symval(sp);
+ for (i=0,addr=symadr; i<a_bytes; i++,addr>>=8) {
+ chksum += addr;
+ }
+ } else {
+ symadr = 0;
+ }
+#ifdef LONGINT
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "S9%02X%04lX"; addr = symadr & 0x0000ffffl; break;
+ case 3: frmt = "S8%02X%06lX"; addr = symadr & 0x00ffffffl; break;
+ case 4: frmt = "S7%02X%08lX"; addr = symadr & 0xffffffffl; break;
+ }
+#else
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "S9%02X%04X"; addr = symadr & 0x0000ffff; break;
+ case 3: frmt = "S8%02X%06X"; addr = symadr & 0x00ffffff; break;
+ case 4: frmt = "S7%02X%08X"; addr = symadr & 0xffffffff; break;
+ }
+#endif
+ fprintf(ofp, frmt, reclen, addr);
+ /*
+ * 1's complement
+ */
+#ifdef LONGINT
+ fprintf(ofp, "%02lX\n", (~chksum) & 0x00ff);
+#else
+ fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
+#endif
+ }
+}
+
+
+/*)Function sflush()
+ *
+ * The function sflush() outputs the relocated data
+ * in the standard Motorola format.
+ *
+ * local variables:
+ * a_uint addr address temporary
+ * a_uint chksum byte checksum
+ * char * frmt format string pointer
+ * int i loop counter
+ * int max number of data bytes
+ * int reclen record length
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * FILE * ofp output file handle
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * The data is output to the file defined by ofp.
+ */
+
+/*
+ * Written by G. Osborn, gary@s-4.com, 6-17-98.
+ * The new version concatenates the assembler
+ * output records when they represent contiguous
+ * memory segments to produce SXXMAXBYTES data byte
+ * S_ output lines whenever possible, resulting
+ * in a substantial reduction in file size.
+ * More importantly, the download time
+ * to the target system is much improved.
+ */
+
+VOID
+sflush()
+{
+ char *frmt;
+ int i, max, reclen;
+ a_uint addr, chksum;
+
+ max = (int) (rtadr1 - rtadr0);
+ if (max == 0) {
+ return;
+ }
+
+ /*
+ * Only the "S_" and the checksum itself are excluded
+ * from the checksum. The record length does not
+ * include "S_" and the pair count. It does
+ * include the address bytes, the data bytes,
+ * and the checksum.
+ */
+ reclen = max + 1 + a_bytes;
+ chksum = reclen;
+ for (i=0,addr=rtadr0; i<a_bytes; i++,addr>>=8) {
+ chksum += addr;
+ }
+#ifdef LONGINT
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "S1%02X%04lX"; addr = rtadr0 & 0x0000ffffl; break;
+ case 3: frmt = "S2%02X%06lX"; addr = rtadr0 & 0x00ffffffl; break;
+ case 4: frmt = "S3%02X%08lX"; addr = rtadr0 & 0xffffffffl; break;
+ }
+#else
+ switch(a_bytes) {
+ default:
+ case 2: frmt = "S1%02X%04X"; addr = rtadr0 & 0x0000ffff; break;
+ case 3: frmt = "S2%02X%06X"; addr = rtadr0 & 0x00ffffff; break;
+ case 4: frmt = "S3%02X%08X"; addr = rtadr0 & 0xffffffff; break;
+ }
+#endif
+ fprintf(ofp, frmt, reclen, addr);
+ for (i=0; i<max; i++) {
+ chksum += rtbuf[i];
+ fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
+ }
+ /*
+ * 1's complement
+ */
+#ifdef LONGINT
+ fprintf(ofp, "%02lX\n", (~chksum) & 0x00ff);
+#else
+ fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
+#endif
+ rtadr0 = rtadr1;
+}
+#endif
+
+/*)Disk BASIC Format
+ *
+ * Each code segment starts with the following record:
+ *
+ * Record Preamble - This field is either $00 (for start of new
+ * record) or $FF (for last record in file).
+ *
+ * Record Length Field - This field specifies the record length
+ * that follows the Load Address Field.
+ *
+ * 16-Bit Length - 2-bytes
+ * 24-Bit Length - 3-bytes
+ * 32-Bit Length - 4-bytes
+ *
+ * Load Address Field - This field consists of the address where
+ * the record will be loaded into memory.
+ *
+ * 16-Bit Address - 2-bytes
+ * 24-Bit Address - 3-bytes
+ * 32-Bit Address - 4-bytes
+ *
+ * Binary Data Bytes - Record Length data bytes.
+ *
+ * After the last code segment, a final record like the one above is
+ * placed. In this final segment, the Record Preamble is $FF, the
+ * Record Length Field is $0000 and the Load Adress Field is the
+ * execution address.
+ */
+
+/*)Function dbx(i)
+ *
+ * int i 1 - process data
+ * 0 - end of data
+ *
+ * The function decb() loads the output buffer with
+ * the relocated data.
+ *
+ * local variables:
+ * int k loop counter
+ * struct sym *sp symbol pointer
+ * a_uint symadr start address
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ * FILE * ofp output file handle
+ * int rtcnt count of data words
+ * int rtflg[] output the data flag
+ * a_uint rtval[] relocated data
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ * a_uint rtadr2 address temporary
+ *
+ * functions called:
+ * int putc() c_library
+ * VOID dflush() lkout.c
+ *
+ * side effects:
+ * The data is placed into the output buffer.
+ */
+
+VOID
+dbx(i)
+int i;
+{
+ struct sym *sp;
+ int k;
+ a_uint j, symadr;
+
+ if (i) {
+ if (hilo == 0) {
+ switch(a_bytes){
+ default:
+ case 2:
+ j = rtval[0];
+ rtval[0] = rtval[1];
+ rtval[1] = j;
+ break;
+ case 3:
+ j = rtval[0];
+ rtval[0] = rtval[2];
+ rtval[2] = j;
+ break;
+ case 4:
+ j = rtval[0];
+ rtval[0] = rtval[3];
+ rtval[3] = j;
+ j = rtval[2];
+ rtval[2] = rtval[1];
+ rtval[1] = j;
+ break;
+ }
+ }
+ for (i=0,rtadr2=0; i<a_bytes; i++) {
+ rtadr2 = (rtadr2 << 8) | rtval[i];
+ }
+
+ if (rtadr2 != rtadr1) {
+ /*
+ * data bytes not contiguous between records
+ */
+ dflush();
+ rtadr0 = rtadr1 = rtadr2;
+ }
+ for (k=a_bytes; k<rtcnt; k++) {
+ if (rtflg[k]) {
+ rtbuf[(int) (rtadr1++ - rtadr0)] = rtval[k];
+ if (rtadr1 - rtadr0 == (unsigned) (DBXMAXBYTES - (2 * a_bytes) - 1)) {
+ dflush();
+ }
+ }
+ }
+ } else {
+ /* Disk BASIC BIN Trailer */
+ sp = lkpsym(".__.END.", 0);
+ if (sp && (sp->s_axp->a_bap->a_ofp == ofp)) {
+ symadr = symval(sp);
+ } else {
+ symadr = 0;
+ }
+ /* Terminator */
+ putc(0xFF, ofp);
+
+ /* Size (0) */
+ switch(a_bytes) {
+ case 4: putc((int) (0 >> 24) & 0xFF, ofp);
+ case 3: putc((int) (0 >> 16) & 0xFF, ofp);
+ default:
+ case 2: putc((int) (0 >> 8) & 0xFF, ofp);
+ putc((int) (0 >> 0) & 0xFF, ofp);
+ break;
+ }
+
+ /* Starting Address */
+ switch(a_bytes) {
+ case 4: putc((int) (symadr >> 24) & 0xFF, ofp);
+ case 3: putc((int) (symadr >> 16) & 0xFF, ofp);
+ default:
+ case 2: putc((int) (symadr >> 8) & 0xFF, ofp);
+ putc((int) (symadr >> 0) & 0xFF, ofp);
+ break;
+ }
+ }
+}
+
+
+/*)Function dflush()
+ *
+ * The function dflush() outputs the relocated data
+ * in the Disk BASIC loadable format
+ *
+ * local variables:
+ * int i loop counter
+ * int max number of data bytes
+ *
+ * global variables:
+ * FILE * ofp output file handle
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ *
+ * functions called:
+ * int putc() c_library
+ *
+ * side effects:
+ * The data is output to the file defined by ofp.
+ */
+
+/*
+ * Written by Boisy G. Pitre, boisy@boisypitre.com, 6-7-04
+ */
+
+VOID
+dflush()
+{
+ int i, max;
+
+ max = (int) (rtadr1 - rtadr0);
+ if (max == 0) {
+ return;
+ }
+
+ /* Preamble Byte */
+ putc(0, ofp);
+
+ /* Record Size */
+ switch(a_bytes){
+ case 4: putc((int) (max >> 24) & 0xFF, ofp);
+ case 3: putc((int) (max >> 16) & 0xFF, ofp);
+ default:
+ case 2: putc((int) (max >> 8) & 0xFF, ofp);
+ putc((int) (max >> 0) & 0xFF, ofp);
+ break;
+ }
+
+ /* Load Address */
+ switch(a_bytes){
+ case 4: putc((int) (rtadr0 >> 24) & 0xFF, ofp);
+ case 3: putc((int) (rtadr0 >> 16) & 0xFF, ofp);
+ default:
+ case 2: putc((int) (rtadr0 >> 8) & 0xFF, ofp);
+ putc((int) (rtadr0 >> 0) & 0xFF, ofp);
+ break;
+ }
+
+ for (i = 0; i < max; i++) {
+ putc(rtbuf[i], ofp);
+ }
+
+ rtadr0 = rtadr1;
+}
--- /dev/null
+/* lkrel.c - .rel object file handling
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+ Copyright (C) 2008-2010 Borut Razem, borut dot razem at siol dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <assert.h>
+
+#include "lk_readnl.h"
+#include "aslink.h"
+#include "lkrel.h"
+
+int
+is_rel (FILE * libfp)
+{
+ int c;
+ long pos = ftell (libfp);
+ int ret = 0;
+
+ /* [XDQ][HL][234] */
+ if (((c = getc (libfp)) == 'X' || c == 'D' || c == 'Q') && ((c = getc (libfp)) == 'H' || c == 'L'))
+ {
+ switch (getc (libfp))
+ {
+ case '2':
+ case '3':
+ case '4':
+ switch (getc (libfp))
+ {
+ case '\r':
+ if (getc (libfp) == '\n')
+ ret = 1;
+ break;
+
+ case '\n':
+ ret = 1;
+ }
+ break;
+
+ case '\r':
+ if (getc (libfp) == '\n')
+ ret = 1;
+ break;
+
+ case '\n':
+ ret = 1;
+ }
+ }
+ else if (c == ';')
+ {
+ char buf[6];
+
+ if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, "!FILE ", 6) == 0)
+ ret = 1;
+ }
+ fseek (libfp, pos, SEEK_SET);
+ return ret;
+}
+
+/* Load a standalone or embedded .rel */
+int
+load_rel (FILE * libfp, long size)
+{
+ if (is_rel (libfp))
+ {
+ char str[NINPUT];
+ long end;
+
+ end = (size >= 0) ? ftell (libfp) + size : -1;
+
+ while ((end < 0 || ftell (libfp) < end) && lk_readnl (str, sizeof (str), libfp) != NULL)
+ {
+ if (0 == strcmp (str, "</REL>"))
+ return 1;
+
+ ip = str;
+ link_main ();
+ }
+
+ return 1;
+ }
+ else
+ return 0;
+}
+
+int
+enum_symbols (FILE * fp, long size, int (*func) (const char *symvoid, void *param), void *param)
+{
+ char buf[NINPUT];
+ long end = (size >= 0) ? ftell (fp) + size : -1;
+
+ assert (func != NULL);
+
+ /*
+ * Read in the object file. Look for lines that
+ * begin with "S" and end with "D". These are
+ * symbol table definitions. If we find one, see
+ * if it is our symbol. Make sure we only read in
+ * our object file and don't go into the next one.
+ */
+
+ while ((end < 0 || ftell (fp) < end) && lk_readnl (buf, sizeof (buf), fp) != NULL)
+ {
+ char symname[NINPUT];
+ char c;
+
+ /*
+ * When a 'T line' is found terminate file scan.
+ * All 'S line's preceed 'T line's in .REL files.
+ */
+ if (buf[0] == 'T')
+ break;
+
+ /*
+ * Skip everything that's not a symbol record.
+ */
+ if (buf[0] != 'S')
+ continue;
+
+ sscanf (buf, "S %s %c", symname, &c);
+
+ /* If it's an actual symbol, record it */
+ if (c == 'D')
+ {
+ if ((*func) (symname, param))
+ return 1;
+ }
+ }
+
+ return 0;
+}
--- /dev/null
+/* lkrel.h - .rel object file handling
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+ Copyright (C) 2008-2009 Borut Razem, borut dot razem at siol dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#ifndef __LKREL_H
+#define __LKREL_H
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+ int is_rel (FILE * libfp);
+ int load_rel (FILE * libfp, long size);
+ int enum_symbols (FILE * fp, long size, int (*func) (const char *symvoid, void *param), void *param);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __LKREL_H */
--- /dev/null
+/* lkrloc.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With enhancements from:
+ *
+ * John L. Hartman (JLH)
+ * jhartman@compuserve.com
+ *
+ * Bill McKinnon (BM)
+ * w_mckinnon@conknet.com
+ */
+
+#include <ctype.h>
+#include "aslink.h"
+
+/*)Module lkrloc.c
+ *
+ * The module lkrloc.c contains the functions which
+ * perform the relocation calculations.
+ *
+ * lkrloc.c contains the following functions:
+ * a_uint adb_1b()
+ * a_uint adb_2b()
+ * a_uint adb_3b()
+ * a_uint adb_4b()
+ * a_uint adb_xb()
+ * a_uint evword()
+ * VOID prntval()
+ * VOID reloc()
+ *
+ *
+ */
+
+/*)Function VOID reloc(c)
+ *
+ * int c process code
+ *
+ * The function reloc() calls the proper version
+ * of the linker code.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * ASxxxx_VERSION ASxxxx REL file version
+ *
+ * called functions:
+ * VOID reloc3() lkrloc3.c
+ * VOID reloc4() lkrloc4.c
+ *
+ * side effects:
+ * Refer to the called relocation functions.
+ *
+ */
+
+VOID
+reloc(int c)
+{
+ switch(ASxxxx_VERSION) {
+ case 3:
+ reloc3(c);
+ break;
+
+// case 4:
+// reloc4(c);
+// break;
+
+ default:
+ fprintf(stderr, "Internal Version Error");
+ lkexit(ER_FATAL);
+ break;
+ }
+}
+
+
+/*)Function a_uint evword()
+ *
+ * The function evword() combines two byte values
+ * into a single word value.
+ *
+ * local variable:
+ * a_uint v temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * int eval() lkeval.c
+ *
+ * side effects:
+ * Relocation text line is scanned to combine
+ * two byte values into a single word value.
+ *
+ */
+
+a_uint
+evword(void)
+{
+ a_uint v;
+
+ if (hilo) {
+ v = (eval() << 8);
+ v += eval();
+ } else {
+ v = eval();
+ v += (eval() << 8);
+ }
+ return(v);
+}
+
+/*)Function a_uint adb_1b(v, i)
+ *
+ * a_uint v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_1b() adds the value of v to
+ * the single byte value contained in rtval[i].
+ * The new value of rtval[i] is returned.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_1b(a_uint v, int i)
+{
+ a_uint j;
+
+ j = v + rtval[i];
+ rtval[i] = j & ((a_uint) 0x000000FF);
+
+ return(j);
+}
+
+/*)Function a_uint adb_2b(v, i)
+ *
+ * a_uint v value to add to word
+ * int i rtval[] index
+ *
+ * The function adb_2b() adds the value of v to the
+ * 2 byte value contained in rtval[i] and rtval[i+1].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The 2 byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_2b(a_uint v, int i)
+{
+ a_uint j;
+
+ if (hilo) {
+ j = v + (rtval[i+0] << 8) +
+ (rtval[i+1] << 0);
+ rtval[i+0] = (j >> 8) & ((a_uint) 0x000000FF);
+ rtval[i+1] = (j >> 0) & ((a_uint) 0x000000FF);
+ } else {
+ j = v + (rtval[i+0] << 0) +
+ (rtval[i+1] << 8);
+ rtval[i+0] = (j >> 0) & ((a_uint) 0x000000FF);
+ rtval[i+1] = (j >> 8) & ((a_uint) 0x000000FF);
+ }
+ return(j);
+}
+
+/*)Function a_uint adb_3b(v, i)
+ *
+ * a_uint v value to add to word
+ * int i rtval[] index
+ *
+ * The function adb_3b() adds the value of v to the
+ * three byte value contained in rtval[i], rtval[i+1], and rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] / rtval[i+2] is returned.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The 3 byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_3b(a_uint v, int i)
+{
+ a_uint j;
+
+ if (hilo) {
+ j = v + (rtval[i+0] << 16) +
+ (rtval[i+1] << 8) +
+ (rtval[i+2] << 0);
+ rtval[i+0] = (j >> 16) & ((a_uint) 0x000000FF);
+ rtval[i+1] = (j >> 8) & ((a_uint) 0x000000FF);
+ rtval[i+2] = (j >> 0) & ((a_uint) 0x000000FF);
+ } else {
+ j = v + (rtval[i+0] << 0) +
+ (rtval[i+1] << 8) +
+ (rtval[i+2] << 16);
+ rtval[i+0] = (j >> 0) & ((a_uint) 0x000000FF);
+ rtval[i+1] = (j >> 8) & ((a_uint) 0x000000FF);
+ rtval[i+2] = (j >> 16) & ((a_uint) 0x000000FF);
+ }
+ return(j);
+}
+
+/*)Function a_uint adb_4b(v, i)
+ *
+ * a_uint v value to add to word
+ * int i rtval[] index
+ *
+ * The function adb_4b() adds the value of v to the
+ * four byte value contained in rtval[i], ..., rtval[i+3].
+ * The new value of rtval[i], ..., rtval[i+3] is returned.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The 4 byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_4b(a_uint v, int i)
+{
+ a_uint j;
+
+ if (hilo) {
+ j = v + (rtval[i+0] << 24) +
+ (rtval[i+1] << 16) +
+ (rtval[i+2] << 8) +
+ (rtval[i+3] << 0);
+ rtval[i+0] = (j >> 24) & ((a_uint) 0x000000FF);
+ rtval[i+1] = (j >> 16) & ((a_uint) 0x000000FF);
+ rtval[i+2] = (j >> 8) & ((a_uint) 0x000000FF);
+ rtval[i+3] = (j >> 0) & ((a_uint) 0x000000FF);
+ } else {
+ j = v + (rtval[i+0] << 0) +
+ (rtval[i+1] << 8) +
+ (rtval[i+2] << 16) +
+ (rtval[i+3] << 24);
+ rtval[i+0] = (j >> 0) & ((a_uint) 0x000000FF);
+ rtval[i+1] = (j >> 8) & ((a_uint) 0x000000FF);
+ rtval[i+2] = (j >> 16) & ((a_uint) 0x000000FF);
+ rtval[i+3] = (j >> 24) & ((a_uint) 0x000000FF);
+ }
+ return(j);
+}
+
+/*)Function a_uint adb_xb(v, i)
+ *
+ * a_uint v value to add to x-bytes
+ * int i rtval[] index
+ *
+ * The function adb_xb() adds the value of v to
+ * the value contained in rtval[i] for x-bytes.
+ * The new value of rtval[i] for x-bytes is returned.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * int a_bytes T Line Address Bytes
+ *
+ * called functions:
+ * a_uint adb_1b() lkrloc.c
+ * a_uint adb_2b() lkrloc.c
+ * a_uint adb_3b() lkrloc.c
+ * a_uint adb_4b() lkrloc.c
+ *
+ * side effects:
+ * The x-byte value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_xb(a_uint v, int i)
+{
+ a_uint j;
+
+ switch(a_bytes){
+ case 1:
+ j = adb_1b(v, i);
+ j = (j & ((a_uint) 0x00000080) ? j | ~((a_uint) 0x0000007F) : j & ((a_uint) 0x0000007F));
+ break;
+ case 2:
+ j = adb_2b(v, i);
+ j = (j & ((a_uint) 0x00008000) ? j | ~((a_uint) 0x00007FFF) : j & ((a_uint) 0x00007FFF));
+ break;
+ case 3:
+ j = adb_3b(v, i);
+ j = (j & ((a_uint) 0x00800000) ? j | ~((a_uint) 0x007FFFFF) : j & ((a_uint) 0x007FFFFF));
+ break;
+ case 4:
+ j = adb_4b(v, i);
+ j = (j & ((a_uint) 0x80000000) ? j | ~((a_uint) 0x7FFFFFFF) : j & ((a_uint) 0x7FFFFFFF));
+ break;
+ default:
+ j = 0;
+ break;
+ }
+ return(j);
+}
+
+/*)Function VOID prntval(fptr, v)
+ *
+ * FILE *fptr output file handle
+ * a_uint v value to output
+ *
+ * The function prntval() outputs the value v, in the
+ * currently selected radix, to the device specified
+ * by fptr.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * int xflag current radix
+ *
+ * called functions:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * none
+ *
+ */
+
+VOID
+prntval(FILE *fptr, a_uint v)
+{
+ char *frmt;
+
+ switch(xflag) {
+ default:
+ case 0:
+ switch(a_bytes) {
+ default:
+ case 2: frmt = " %04X\n"; break;
+ case 3: frmt = " %06X\n"; break;
+ case 4: frmt = " %08X\n"; break;
+ }
+ break;
+ case 1:
+ switch(a_bytes) {
+ default:
+ case 2: frmt = " %06o\n"; break;
+ case 3: frmt = " %08o\n"; break;
+ case 4: frmt = "%011o\n"; break;
+ }
+ break;
+ case 2:
+ switch(a_bytes) {
+ default:
+ case 2: frmt = " %05u\n"; break;
+ case 3: frmt = " %08u\n"; break;
+ case 4: frmt = " %010u\n"; break;
+ }
+ break;
+ }
+ fprintf(fptr, frmt, v & a_mask);
+}
--- /dev/null
+/* lkrloc3.c */
+
+/*
+ * Copyright (C) 1989-2010 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With enhancements from:
+ *
+ * John L. Hartman (JLH)
+ * jhartman@compuserve.com
+ *
+ * Bill McKinnon (BM)
+ * w_mckinnon@conknet.com
+ */
+
+#include "aslink.h"
+
+/*)Module lkrloc3.c
+ *
+ * The module lkrloc3.c contains the functions which
+ * perform the version 3 relocation calculations.
+ *
+ * lkrloc3.c contains the following functions:
+ * a_uint adb_lo()
+ * a_uint adb_hi()
+ * VOID erpdmp3()
+ * VOID errdmp3()
+ * VOID rele3()
+ * VOID relerr3()
+ * VOID relerp3()
+ * VOID reloc3()
+ * VOID relp3()
+ * VOID relr3()
+ * VOID relt3()
+ *
+ * lkrloc3.c the local variable errmsg3[].
+ *
+ */
+
+/*)Function VOID reloc3(c)
+ *
+ * int c process code
+ *
+ * The function reloc3() calls a particular relocation
+ * function determined by the process code.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * int lkerr error flag
+ *
+ * called functions:
+ * int fprintf() c_library
+ * VOID rele3() lkrloc3.c
+ * VOID relp3() lkrloc3.c
+ * VOID relr3() lkrloc3.c
+ * VOId relt3() lkrloc3.c
+ *
+ * side effects:
+ * Refer to the called relocation functions.
+ *
+ */
+
+VOID
+reloc3(int c)
+{
+ switch(c) {
+
+ case 'T':
+ relt3();
+ break;
+
+ case 'R':
+ relr3();
+ break;
+
+ case 'P':
+ relp3();
+ break;
+
+ case 'E':
+ rele3();
+ break;
+
+ default:
+ fprintf(stderr, "Undefined Relocation Operation\n");
+ lkerr++;
+ break;
+
+ }
+}
+
+
+/*)Function VOID relt3()
+ *
+ * The function relt3() evaluates a T line read by
+ * the linker. Each byte value read is saved in the
+ * rtval[] array, rtflg[] is set, and the number of
+ * evaluations is maintained in rtcnt.
+ *
+ * T Line
+ *
+ * T xx xx nn nn nn nn nn ...
+ *
+ *
+ * In: "T n0 n1 n2 n3 ... nn"
+ *
+ * Out: 0 1 2 .. rtcnt
+ * +----+----+----+----+----+
+ * rtval | n0 | n1 | n2 | .. | nn |
+ * +----+----+----+----+----+
+ * rtflag| 1 | 1 | 1 | 1 | 1 |
+ * +----+----+----+----+----+
+ *
+ * The T line contains the assembled code output by the assem-
+ * bler with xx xx being the offset address from the current area
+ * base address and nn being the assembled instructions and data in
+ * byte format.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * int rtcnt number of values evaluated
+ * int rtflg[] array of evaluation flags
+ * int rtval[] array of evaluation values
+ *
+ * called functions:
+ * int eval() lkeval.c
+ * int more() lklex.c
+ *
+ * side effects:
+ * Linker input T line evaluated.
+ *
+ */
+
+VOID
+relt3(void)
+{
+ rtcnt = 0;
+ while (more()) {
+ if (rtcnt < NTXT) {
+ rtval[rtcnt] = eval();
+ rtflg[rtcnt] = 1;
+ rterr[rtcnt] = 0;
+ rtcnt++;
+ }
+ }
+}
+
+/* Fuzix _CODE1, _CODE2, _CODE3 indicate magic banking values */
+static int bankmagic(struct areax *ax)
+{
+ struct area *a = ax->a_bap;
+ int c;
+
+ /* Hack: fix me up */
+ if (strcmp(a->a_id, "_FONT") == 0)
+ return 3;
+ if (strcmp(a->a_id, "_VIDEO") == 0)
+ return 3;
+ if (strcmp(a->a_id, "_DISCARD") == 0)
+ return 3;
+ if (strncmp(a->a_id, "_CODE", 5))
+ return 0;
+ if (a->a_id[5] == 0) /* We count _CODE and _CODE1 both as first bank */
+ return 1;
+ c = a->a_id[5] - '0';
+ if (c < 1 || c > 9)
+ return 0;
+ return c;
+}
+
+static void bankingstub(struct sym *s, struct areax *bx, int bmagic, int addr)
+{
+ struct areax *ax = s->s_axp;
+ struct area *a = ax->a_bap;
+ int bxm = bankmagic(bx);
+
+ if (bxm == bmagic)
+ return;
+
+ if (ofp) {
+ fprintf(ofp, "; Banking Stub %s:%s(%s)\n",
+ a->a_id, s->s_id, s->m_id);
+ fprintf(ofp, "; From area %s\n", bx->a_bap->a_id);
+ fprintf(ofp, "B %02X %04X %02X %s\n",
+ bxm, addr,
+ bmagic, bx->a_bap->a_id);
+ }
+ return;
+}
+
+/*)Function VOID relr3()
+ *
+ * The function relr3() evaluates a R line read by
+ * the linker. The R line data is combined with the
+ * previous T line data to perform the relocation of
+ * code and data bytes. The S19 / IHX output and
+ * translation of the LST files to RST files may be
+ * performed.
+ *
+ * R Line
+ *
+ * R 0 0 nn nn n1 n2 xx xx ...
+ *
+ * The R line provides the relocation information to the linker.
+ * The nn nn value is the current area index, i.e. which area the
+ * current values were assembled. Relocation information is en-
+ * coded in groups of 4 bytes:
+ *
+ * 1. n1 is the relocation mode and object format
+ * 1. bit 0 word(0x00)/byte(0x01)
+ * 2. bit 1 relocatable area(0x00)/symbol(0x02)
+ * 3. bit 2 normal(0x00)/PC relative(0x04) relocation
+ * 4. bit 3 1-byte(0x00)/2-byte(0x08) byte data
+ * 5. bit 4 signed(0x00)/unsigned(0x10) byte data
+ * 6. bit 5 normal(0x00)/page '0'(0x20) reference
+ * 7. bit 6 normal(0x00)/page 'nnn'(0x40) reference
+ *
+ * 2. n2 is a byte index into the corresponding (i.e. pre-
+ * ceeding) T line data (i.e. a pointer to the data to be
+ * updated by the relocation). The T line data may be
+ * 1-byte or 2-byte byte data format or 2-byte word
+ * format.
+ *
+ * 3. xx xx is the area/symbol index for the area/symbol be-
+ * ing referenced. the corresponding area/symbol is found
+ * in the header area/symbol lists.
+ *
+ * The groups of 4 bytes are repeated for each item requiring relo-
+ * cation in the preceeding T line.
+ *
+ * local variable:
+ * areax **a pointer to array of area pointers
+ * int aindex area index
+ * char *errmsg3[] array of pointers to error strings
+ * int error error code
+ * int mode relocation mode
+ * adrr_t paga paging base area address
+ * a_uint pags paging symbol address
+ * a_uint r PCR relocation value
+ * a_uint reli relocation initial value
+ * a_uint relv relocation final value
+ * int rindex symbol / area index
+ * a_uint rtbase base code address
+ * a_uint rtofst rtval[] index offset
+ * int rtp index into T data
+ * sym **s pointer to array of symbol pointers
+ *
+ * global variables:
+ * head *hp pointer to the head structure
+ * int lkerr error flag
+ * a_uint pc relocated base address
+ * int pcb bytes per instruction word
+ * rerr rerr linker error structure
+ * FILE *stderr standard error device
+ *
+ * called functions:
+ * a_uint adb_1b() lkrloc.c
+ * a_uint adb_2b() lkrloc.c
+ * a_uint adb_lo() lkrloc3.c
+ * a_uint adb_hi() lkrloc3.c
+ * sdld specific
+ * VOID elf() lkelf.c
+ * VOID gb() lkgb.c
+ * end sdld specific
+ * a_uint evword() lkrloc.c
+ * int eval() lkeval.c
+ * int fprintf() c_library
+ * VOID ihx() lkihx.c
+ * VOID s19() lks19.c
+ * VOID lkulist lklist.c
+ * int more() lklex.c
+ * VOID relerr3() lkrloc3.c
+ * int symval() lksym.c
+ *
+ * side effects:
+ * The R and T lines are combined to produce
+ * relocated code and data. Output Sxx / Ixx
+ * and relocated listing files may be produced.
+ *
+ */
+
+VOID
+relr3(void)
+{
+ int mode;
+ a_uint reli, relv;
+ int aindex, rindex, rtp, error, i;
+ a_uint r, rtbase, rtofst, paga = 0, pags = 0;
+ struct areax **a;
+ struct sym **s;
+ int bmagic = 0;
+ int mybank;
+
+ /*
+ * Get area and symbol lists
+ */
+ a = hp->a_list;
+ s = hp->s_list;
+
+ /*
+ * Verify Area Mode
+ */
+ if (eval() != (R3_WORD | R3_AREA) || eval()) {
+ fprintf(stderr, "R input error\n");
+ lkerr++;
+ return;
+ }
+
+ /*
+ * Get area pointer
+ */
+ aindex = (int) evword();
+ if (aindex >= hp->h_narea) {
+ fprintf(stderr, "R area error\n");
+ lkerr++;
+ return;
+ }
+
+ /*
+ * Select Output File
+ */
+ if (oflag != 0) {
+ ap = a[aindex]->a_bap;
+ if (ofp != NULL) {
+ rtabnk->b_rtaflg = rtaflg;
+ if (ofp != ap->a_ofp) {
+ lkflush();
+ }
+ }
+ ofp = ap->a_ofp;
+ rtabnk = ap->a_bp;
+ rtaflg = rtabnk->b_rtaflg;
+ }
+
+ /*
+ * Base values
+ */
+ rtbase = adb_xb(0, 0);
+ rtofst = a_bytes;
+
+ /*
+ * Relocate address
+ */
+ pc = adb_xb(a[aindex]->a_addr, 0);
+
+ /*
+ * Number of 'bytes' per PC address
+ */
+ pcb = 1;
+
+ mybank = bankmagic(a[aindex]);
+
+ #if 0
+ printf("area %d base address: 0x%x size: 0x%x rtbase: 0x%x\n", aindex,
+ a[aindex]->a_addr, a[aindex]->a_size, rtbase);
+ #endif
+ /*
+ * Do remaining relocations
+ */
+ while (more()) {
+ error = 0;
+ bmagic = 0;
+ mode = (int) eval();
+
+ if ((mode & R_ESCAPE_MASK) == R_ESCAPE_MASK)
+ {
+ mode = ((mode & ~R_ESCAPE_MASK) << 8) | eval();
+ /* printf("unescaping rmode\n"); */
+ }
+
+ rtp = (int) eval();
+ rindex = (int) evword();
+
+ /*
+ * R3_SYM or R3_AREA references
+ */
+ if (mode & R3_SYM) {
+ if (rindex >= hp->h_nsym) {
+ fprintf(stderr, "R symbol error\n");
+ lkerr++;
+ return;
+ }
+ reli = symval(s[rindex]);
+ /* Check if this symbol is magic */
+ bmagic = bankmagic(s[rindex]->s_axp);
+ }
+/* sdld specific */
+ else if ((IS_R_J11(mode) || IS_R_J19(mode)) && (rindex == 0xFFFF)) {
+ /* absolute acall/ajmp address */
+ reli = 0;
+ }
+/* end sdld specific */
+ else {
+ if (rindex >= hp->h_narea) {
+ fprintf(stderr, "R area error\n");
+ lkerr++;
+ return;
+ }
+ reli = a[rindex]->a_addr;
+ }
+
+ /*
+ * R3_PCR addressing
+ */
+ if (mode & R3_PCR) {
+ if (mode & R3_BYTE) {
+ reli -= (pc + (rtp-rtofst) + 1);
+ } else {
+ reli -= (pc + (rtp-rtofst) + 2);
+ }
+ }
+
+ /*
+ * R3_PAG0 or R3_PAG addressing
+ */
+ if (mode & (R3_PAG0 | R3_PAG)) {
+ paga = sdp.s_area->a_addr;
+ pags = sdp.s_addr;
+ reli -= paga + pags;
+ }
+
+ /*
+ * R3_BYTE or R3_WORD operation
+ */
+ if (mode & R3_BYTE) {
+ if (mode & R_BYT3)
+ {
+ /* This is a three byte address, of which
+ * we will select one byte.
+ */
+/* sdld specific */
+ if (mode & R_BIT)
+ {
+ relv = adb_24_bit(reli, rtp);
+ }
+/* sdld specific */
+ else if (mode & R_HIB)
+ {
+ /* printf("24 bit address selecting hi byte.\n"); */
+ relv = adb_24_hi(reli, rtp);
+ }
+ else if (mode & R3_MSB)
+ {
+ /* Note that in 24 bit mode, R3_MSB
+ * is really the middle byte, not
+ * the most significant byte.
+ *
+ * This is ugly and I can only apologize
+ * for any confusion.
+ */
+ /* printf("24 bit address selecting middle byte.\n"); */
+ relv = adb_24_mid(reli, rtp);
+ }
+ else
+ {
+ /* printf("24 bit address selecting lo byte.\n"); */
+ relv = adb_24_lo(reli, rtp);
+ }
+ }
+ else if (mode & R3_BYTX) {
+ /* This is a two byte address, of
+ * which we will select one byte.
+ */
+ if (mode & R_BIT) {
+ relv = adb_bit(reli, rtp);
+ } else if (mode & R3_MSB) {
+ relv = adb_hi(reli, rtp);
+ } else {
+ relv = adb_lo(reli, rtp);
+ }
+ } else {
+ relv = adb_1b(reli, rtp);
+ }
+ } else if (IS_R_J11(mode)) {
+ /*
+ * JLH: 11 bit jump destination for 8051.
+ * Forms two byte instruction with
+ * op-code bits in the MIDDLE!
+ * rtp points at 3 byte locus:
+ * first two will get the address,
+ * third one has raw op-code
+ */
+
+ /*
+ * Calculate absolute destination
+ * relv must be on same 2K page as pc
+ */
+ relv = adb_2b(reli, rtp);
+
+ if ((relv & ~((a_uint) 0x000007FF)) !=
+ ((pc + rtp - rtofst) & ~((a_uint) 0x000007FF))) {
+ error = 6;
+ }
+
+ /*
+ * Merge MSB with op-code,
+ * ignoring top 5 bits of address.
+ * Then hide the op-code.
+ */
+ rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+2];
+ rtflg[rtp + 2] = 0;
+ rtofst += 1;
+ }
+ else if (IS_R_J19(mode)) {
+ /*
+ * BK: 19 bit jump destination for DS80C390.
+ * Forms four byte instruction with
+ * op-code bits in the MIDDLE!
+ * rtp points at 4 byte locus:
+ * first three will get the address,
+ * fourth one has raw op-code
+ */
+ relv = adb_3b(reli, rtp);
+
+ /*
+ * Calculate absolute destination
+ * relv must be on same 512K page as pc
+ */
+ if ((relv & ~((a_uint) 0x0007FFFF)) !=
+ ((pc + rtp - rtofst) & ~((a_uint) 0x0007FFFF))) {
+ error = 7;
+ }
+
+ /*
+ * Merge MSB with op-code,
+ * ignoring top 5 bits of address.
+ * Then hide the op-code.
+ */
+ rtval[rtp] = ((rtval[rtp] & 0x07)<<5) | rtval[rtp+3];
+ rtflg[rtp + 3] = 0;
+ rtofst += 1;
+ }
+ else if (IS_C24(mode))
+ {
+ /*
+ * 24 bit destination
+ */
+ relv = adb_3b(reli, rtp);
+ }
+ else
+ {
+ /* 16 bit address. */
+ if (bmagic)
+ bankingstub(s[rindex], a[aindex], bmagic, a[aindex]->a_addr + rtbase + rtp - rtofst);
+ relv = adb_2b(reli, rtp);
+ }
+
+ /*
+ * R3_BYTE with R3_BYTX offset adjust
+ */
+ if (mode & R3_BYTE) {
+ if (mode & R3_BYTX) {
+ rtofst += (a_bytes - 1);
+ }
+ }
+
+ /*
+ * Unsigned Byte Checking
+ */
+ if (mode & R3_USGN && mode & R3_BYTE && relv & ~((a_uint) 0x000000FF))
+ error = 1;
+
+ /*
+ * PCR Relocation Error Checking
+ */
+ if (mode & R3_PCR && mode & R3_BYTE) {
+ r = relv & ~0x7F;
+ if (r != (a_uint) ~0x7F && r != 0)
+ error = 2;
+ }
+
+ /*
+ * Page Relocation Error Checking
+ */
+ if ((TARGET_IS_GB || TARGET_IS_Z80) &&
+ mode & R3_PAG0 && (relv & ~0xFF || paga || pags))
+ error = 4;
+ if (mode & R3_PAG && (relv & ~0xFF))
+ error = 5;
+/* sdld specific */
+ if ((mode & R_BIT) && (relv & ~0x87FF))
+ error = 10;
+/* end sdld specific */
+
+ /*
+ * Error Processing
+ */
+ if (error) {
+ rerr.aindex = aindex;
+ rerr.mode = mode;
+ rerr.rtbase = rtbase + rtp - rtofst - 1;
+ rerr.rindex = rindex;
+ rerr.rval = relv - reli;
+ relerr3(errmsg3[error]);
+
+ for (i=rtp; i<rtp+a_bytes; i++) {
+ if (rtflg[i]) {
+ rterr[i] = error;
+ break;
+ }
+ }
+ }
+ }
+ if (uflag != 0) {
+ lkulist(1);
+ }
+ if (oflag != 0) {
+ lkout(1, mybank);
+ }
+}
+
+char *errmsg3[] = {
+/* 0 */ "LKRLOC3 Error List",
+/* 1 */ "Unsigned Byte error",
+/* 2 */ "Byte PCR relocation error",
+/* 3 */ "",
+/* 4 */ "Page0 relocation error",
+/* 5 */ "Page Mode relocation error",
+/* 6 */ "2K Page relocation error",
+/* 7 */ "512K Page relocation error",
+/* 8 */ "",
+/* 9 */ "",
+/* sdld specific */
+/* 10 */ "Bit-addressable relocation error"
+/* end sdld specific */
+};
+
+
+/*)Function VOID relp3()
+ *
+ * The function relp3() evaluates a P line read by
+ * the linker. The P line data is combined with the
+ * previous T line data to set the base page address
+ * and test the paging boundary and length.
+ *
+ * P Line
+ *
+ * P 0 0 nn nn n1 n2 xx xx
+ *
+ * The P line provides the paging information to the linker as
+ * specified by a .setdp directive. The format of the relocation
+ * information is identical to that of the R line. The correspond-
+ * ing T line has the following information:
+ * T xx xx aa aa bb bb
+ *
+ * Where aa aa is the area reference number which specifies the
+ * selected page area and bb bb is the base address of the page.
+ * bb bb will require relocation processing if the 'n1 n2 xx xx' is
+ * specified in the P line. The linker will verify that the base
+ * address is on a 256 byte boundary and that the page length of an
+ * area defined with the PAG type is not larger than 256 bytes.
+ *
+ * local variable:
+ * areax **a pointer to array of area pointers
+ * int aindex area index
+ * int mode relocation mode
+ * a_uint relv relocation value
+ * int rindex symbol / area index
+ * int rtp index into T data
+ * sym **s pointer to array of symbol pointers
+ *
+ * global variables:
+ * head *hp pointer to the head structure
+ * int lkerr error flag
+ * sdp sdp base page structure
+ * FILE *stderr standard error device
+ *
+ * called functions:
+ * a_uint adb_2b() lkrloc.c
+ * a_uint evword() lkrloc.c
+ * int eval() lkeval.c
+ * int fprintf() c_library
+ * int more() lklex.c
+ * int symval() lksym.c
+ *
+ * side effects:
+ * The P and T lines are combined to set
+ * the base page address and report any
+ * paging errors.
+ *
+ */
+
+VOID
+relp3()
+{
+ int aindex, rindex;
+ int mode, rtp;
+ a_uint relv;
+ struct areax **a;
+ struct sym **s;
+
+ /*
+ * Get area and symbol lists
+ */
+ a = hp->a_list;
+ s = hp->s_list;
+
+ /*
+ * Verify Area Mode
+ */
+ if (eval() != (R3_WORD | R3_AREA) || eval()) {
+ fprintf(stderr, "P input error\n");
+ lkerr++;
+ }
+
+ /*
+ * Get area pointer
+ */
+ aindex = (int) evword();
+ if (aindex >= hp->h_narea) {
+ fprintf(stderr, "P area error\n");
+ lkerr++;
+ return;
+ }
+
+ /*
+ * Do remaining relocations
+ */
+ while (more()) {
+ mode = (int) eval();
+ rtp = (int) eval();
+ rindex = (int) evword();
+
+ /*
+ * R3_SYM or R3_AREA references
+ */
+ if (mode & R3_SYM) {
+ if (rindex >= hp->h_nsym) {
+ fprintf(stderr, "P symbol error\n");
+ lkerr++;
+ return;
+ }
+ relv = symval(s[rindex]);
+ } else {
+ if (rindex >= hp->h_narea) {
+ fprintf(stderr, "P area error\n");
+ lkerr++;
+ return;
+ }
+ relv = a[rindex]->a_addr;
+ }
+ adb_2b(relv, rtp);
+ }
+
+ /*
+ * Paged values
+ */
+ aindex = (int) adb_2b(0, 2);
+ if (aindex >= hp->h_narea) {
+ fprintf(stderr, "P area error\n");
+ lkerr++;
+ return;
+ }
+ sdp.s_areax = a[aindex];
+ sdp.s_area = sdp.s_areax->a_bap;
+ sdp.s_addr = adb_2b(0, 4);
+ if (sdp.s_area->a_addr & 0xFF || sdp.s_addr & 0xFF)
+ relerp3("Page Definition Boundary Error");
+}
+
+/*)Function VOID rele3()
+ *
+ * The function rele3() closes all open output files
+ * at the end of the linking process.
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * int oflag output type flag
+ * int uflag relocation listing flag
+ *
+ * called functions:
+ * VOID lkfclose() lkbank.c
+ * VOID lkflush() lkout.c
+ * VOID lkulist() lklist.c
+ *
+ * side effects:
+ * All open output files are closed.
+ *
+ */
+
+VOID
+rele3()
+{
+ if (uflag != 0) {
+ lkulist(0);
+ }
+ if (oflag != 0) {
+ lkflush();
+ lkfclose();
+ }
+}
+
+/*)Function VOID relerr3(str)
+ *
+ * char *str error string
+ *
+ * The function relerr3() outputs the error string to
+ * stderr and to the map file (if it is open).
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * FILE *mfp handle for the map file
+ *
+ * called functions:
+ * VOID errdmp3() lkrloc3.c
+ *
+ * side effects:
+ * Error message inserted into map file.
+ *
+ */
+
+VOID
+relerr3(char *str)
+{
+ errdmp3(stderr, str);
+ if (mfp)
+ errdmp3(mfp, str);
+}
+
+/*)Function VOID errdmp3(fptr, str)
+ *
+ * FILE *fptr output file handle
+ * char *str error string
+ *
+ * The function errdmp3() outputs the error string str
+ * to the device specified by fptr. Additional information
+ * is output about the definition and referencing of
+ * the symbol / area error.
+ *
+ * local variable:
+ * int mode error mode
+ * int aindex area index
+ * int lkerr error flag
+ * int rindex error index
+ * sym **s pointer to array of symbol pointers
+ * areax **a pointer to array of area pointers
+ * areax *raxp error area extension pointer
+ *
+ * global variables:
+ * sdp sdp base page structure
+ *
+ * called functions:
+ * int fprintf() c_library
+ * VOID prntval() lkrloc.c
+ *
+ * side effects:
+ * Error reported.
+ *
+ */
+
+const char errdmp3_null_srcname[] = "<missing>";
+
+VOID
+errdmp3(FILE *fptr, char *str)
+{
+ int mode, aindex, rindex;
+ struct sym **s;
+ struct areax **a;
+ struct areax *raxp;
+
+ a = hp->a_list;
+ s = hp->s_list;
+
+ mode = rerr.mode;
+ aindex = rerr.aindex;
+ rindex = rerr.rindex;
+
+ /*
+ * Print Error
+ */
+ fprintf(fptr, "\n?ASlink-Warning-%s", str);
+ lkerr++;
+
+ /*
+ * Print symbol if symbol based
+ */
+ if (mode & R3_SYM) {
+ fprintf(fptr, " for symbol %s\n",
+ &s[rindex]->s_id[0]);
+ } else {
+ fprintf(fptr, "\n");
+ }
+
+ /*
+ * Print Ref Info
+ */
+/* 11111111112222222222333333333344444444445555555555666666666677777*/
+/*12345678901234567890123456789012345678901234567890123456789012345678901234*/
+/* | | | | */
+ fprintf(fptr,
+" file module area offset\n");
+ fprintf(fptr,
+" Refby %-14.14s %-14.14s %-14.14s ",
+ (hp->h_lfile && hp->h_lfile->f_idp) ? hp->h_lfile->f_idp : errdmp3_null_srcname,
+ &hp->m_id[0],
+ &a[aindex]->a_bap->a_id[0]);
+ prntval(fptr, rerr.rtbase);
+
+ /*
+ * Print Def Info
+ */
+ if (mode & R3_SYM) {
+ raxp = s[rindex]->s_axp;
+ } else {
+ raxp = a[rindex];
+ }
+/* 11111111112222222222333333333344444444445555555555666666666677777*/
+/*12345678901234567890123456789012345678901234567890123456789012345678901234*/
+/* | | | | */
+ fprintf(fptr,
+" Defin %-14.14s %-14.14s %-14.14s ",
+ (raxp->a_bhp->h_lfile && raxp->a_bhp->h_lfile->f_idp) ? raxp->a_bhp->h_lfile->f_idp : errdmp3_null_srcname,
+ &raxp->a_bhp->m_id[0],
+ &raxp->a_bap->a_id[0]);
+ if (mode & R3_SYM) {
+ prntval(fptr, s[rindex]->s_addr);
+ } else {
+ prntval(fptr, rerr.rval);
+ }
+}
+
+/*)Function VOID relerp3(str)
+ *
+ * char *str error string
+ *
+ * The function relerp3() outputs the paging error string to
+ * stderr and to the map file (if it is open).
+ *
+ * local variable:
+ * none
+ *
+ * global variables:
+ * FILE *mfp handle for the map file
+ *
+ * called functions:
+ * VOID erpdmp3() lkrloc3.c
+ *
+ * side effects:
+ * Error message inserted into map file.
+ *
+ */
+
+VOID
+relerp3(char *str)
+{
+ erpdmp3(stderr, str);
+ if (mfp)
+ erpdmp3(mfp, str);
+}
+
+/*)Function VOID erpdmp3(fptr, str)
+ *
+ * FILE *fptr output file handle
+ * char *str error string
+ *
+ * The function erpdmp3() outputs the error string str
+ * to the device specified by fptr.
+ *
+ * local variable:
+ * head *thp pointer to head structure
+ *
+ * global variables:
+ * int lkerr error flag
+ * sdp sdp base page structure
+ *
+ * called functions:
+ * int fprintf() c_library
+ * VOID prntval() lkrloc.c
+ *
+ * side effects:
+ * Error reported.
+ *
+ */
+
+VOID
+erpdmp3(FILE *fptr, char *str)
+{
+ struct head *thp;
+
+ thp = sdp.s_areax->a_bhp;
+
+ /*
+ * Print Error
+ */
+ fprintf(fptr, "\n?ASlink-Warning-%s\n", str);
+ lkerr++;
+
+ /*
+ * Print PgDef Info
+ */
+/* 111111111122222222223333333333444444444455555555556666666666777*/
+/*123456789012345678901234567890123456789012345678901234567890123456789012*/
+ fprintf(fptr,
+" file module pgarea pgoffset\n");
+ fprintf(fptr,
+" PgDef %-14.14s %-14.14s %-14.14s ",
+ thp->h_lfile->f_idp,
+ &thp->m_id[0],
+ &sdp.s_area->a_id[0]);
+ prntval(fptr, sdp.s_area->a_addr + sdp.s_addr);
+}
+
+/* sdld specific */
+/*)Function a_uint adb_bit(v, i)
+ *
+ * a_uint v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_bit() converts the single
+ * byte address value contained in rtval[i] to bit-
+ * addressable space and adds the value of v to it.
+ * The new value of rtval[i] is returned.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_bit(a_uint v, int i)
+{
+ a_uint j;
+
+ j = adb_lo(v, i) & 0xFF;
+ if ((j >= 0x20) && (j <= 0x2F)) {
+ j = (j - 0x20) * 8;
+ } else if ((j < 0x80) || ((j & 0x07) != 0)) {
+ return(0x100);//error
+ }
+
+ if (hilo) {
+ j = rtval[i+1] = j + (rtval[i] & 0x07);
+ } else {
+ j = rtval[i] = j + (rtval[i+1] & 0x07);
+ }
+ return(j);
+}
+/* end sdld specific */
+
+/*)Function a_uint adb_lo(v, i)
+ *
+ * int v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_lo() adds the value of v to the
+ * value contained in rtval[i] through rtval[i + a_bytes - 1].
+ * The new value of rtval[i] ... is returned.
+ * The rtflg[] flags are cleared for all rtval[i] ... except
+ * the LSB.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] values corresponding to all bytes
+ * except the LSB of the value are cleared to reflect
+ * the fact that the LSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_lo(v, i)
+a_uint v;
+int i;
+{
+ a_uint j;
+ int m, n;
+
+ j = adb_xb(v, i);
+ /*
+ * LSB is lowest order byte of data
+ */
+ m = (hilo ? a_bytes-1 : 0);
+ for (n=0; n<a_bytes; n++) {
+ if(n != m) rtflg[i+n] = 0;
+ }
+ return (j);
+}
+
+/*)Function a_uint adb_hi(v, i)
+ *
+ * int v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_hi() adds the value of v to the
+ * value contained in rtval[i] through rtval[i + a_bytes - 1].
+ * The new value of rtval[i] .... is returned.
+ * The LSB rtflg[] is cleared.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] values corresponding to all bytes
+ * except the 2nd byte (MSB) are cleared to reflect
+ * the fact that the MSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_hi(v, i)
+a_uint v;
+int i;
+{
+ a_uint j;
+ int m, n;
+
+ j = adb_xb(v, i);
+ /*
+ * MSB is next lowest order byte of data
+ */
+ m = (hilo ? a_bytes-2 : 1);
+ for (n=0; n<a_bytes; n++) {
+ if(n != m) rtflg[i+n] = 0;
+ }
+ return (j);
+}
+
+/* sdld specific */
+/*)Function a_uint adb_24_bit(v, i)
+ *
+ * a_uint v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_bit() converts the single
+ * byte address value contained in rtval[i] to bit-
+ * addressable space and adds the value of v to it.
+ * The new value of rtval[i] is returned.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * none
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ *
+ */
+
+a_uint
+adb_24_bit(v, i)
+a_uint v;
+int i;
+{
+ a_uint j;
+
+ j = adb_24_lo(v, i) & 0xFF;
+ if ((j >= 0x20) && (j <= 0x2F)) {
+ j = (j - 0x20) * 8;
+ } else if ((j < 0x80) || ((j & 0x07) != 0)) {
+ return(0x100);//error
+ }
+
+ if (hilo) {
+ j = rtval[i+2] = j + (rtval[i+1] & 0x07);
+ } else {
+ j = rtval[i] = j + (rtval[i+1] & 0x07);
+ }
+ return(j);
+}
+
+/*)Function a_uint adb_24_hi(v, i)
+ *
+ * a_uint v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_hi() adds the value of v to the
+ * 24 bit value contained in rtval[i] - rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ * The LSB & middle byte rtflg[] is cleared.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] value corresponding to the
+ * LSB & middle byte of the word value is cleared to
+ * reflect the fact that the MSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_24_hi(v, i)
+a_uint v;
+int i;
+{
+ a_uint j;
+
+ j = adb_3b(v, i);
+
+ /* Remove the lower two bytes. */
+ if (hilo)
+ {
+ rtflg[i+2] = 0;
+ }
+ else
+ {
+ rtflg[i] = 0;
+ }
+ rtflg[i+1] = 0;
+
+ return (j);
+}
+
+/*)Function a_uint adb_24_mid(v, i)
+ *
+ * a_uint v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_mid() adds the value of v to the
+ * 24 bit value contained in rtval[i] - rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ * The LSB & MSB byte rtflg[] is cleared.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] value corresponding to the
+ * LSB & MSB of the 24 bit value is cleared to reflect
+ * the fact that the middle byte is the selected byte.
+ *
+ */
+
+a_uint
+adb_24_mid(v, i)
+a_uint v;
+int i;
+{
+ a_uint j;
+
+ j = adb_3b(v, i);
+
+ /* remove the MSB & LSB. */
+ rtflg[i+2] = 0;
+ rtflg[i] = 0;
+
+ return (j);
+}
+
+/*)Function a_uint adb_24_lo(v, i)
+ *
+ * a_uint v value to add to byte
+ * int i rtval[] index
+ *
+ * The function adb_24_lo() adds the value of v to the
+ * 24 bit value contained in rtval[i] - rtval[i+2].
+ * The new value of rtval[i] / rtval[i+1] is returned.
+ * The MSB & middle byte rtflg[] is cleared.
+ *
+ * local variable:
+ * a_uint j temporary evaluation variable
+ *
+ * global variables:
+ * hilo byte ordering parameter
+ *
+ * called functions:
+ * none
+ *
+ * side effects:
+ * The value of rtval[] is changed.
+ * The rtflg[] value corresponding to the
+ * MSB & middle byte of the word value is cleared to
+ * reflect the fact that the LSB is the selected byte.
+ *
+ */
+
+a_uint
+adb_24_lo(v, i)
+a_uint v;
+int i;
+{
+ a_uint j;
+
+ j = adb_3b(v, i);
+
+ /* Remove the upper two bytes. */
+ if (hilo)
+ {
+ rtflg[i] = 0;
+ }
+ else
+ {
+ rtflg[i+2] = 0;
+ }
+ rtflg[i+1] = 0;
+
+ return (j);
+}
+
+/* end sdld specific */
--- /dev/null
+/* lks19.c
+
+ Copyright (C) 1989-1998 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#include <stdio.h>
+#include <string.h>
+#include "sdld.h"
+#include "aslink.h"
+
+/*)Module lks19.c
+ *
+ * The module lks19.c contains the functions to
+ * output the relocated object code in the
+ * Motorola S19 format.
+ *
+ * lks19.c contains the following functions:
+ * VOID s19()
+ * VOID sflush()
+ *
+ * lks19.c contains no local variables.
+ */
+
+/*)S19 Format
+ * Record Type Field - This field signifies the start of a
+ * record and identifies the the record
+ * type as follows:
+ *
+ * Ascii S1 - Data Record
+ * Ascii S9 - End of File Record
+ *
+ * Record Length Field - This field specifies the record length
+ * which includes the address, data, and
+ * checksum fields. The 8 bit record
+ * length value is converted to two ascii
+ * characters, high digit first.
+ *
+ * Load Address Field - This field consists of the four ascii
+ * characters which result from converting
+ * the the binary value of the address in
+ * which to begin loading this record. The
+ * order is as follows:
+ *
+ * High digit of high byte of address.
+ * Low digit of high byte of address.
+ * High digit of low byte of address.
+ * Low digit of low byte of address.
+ *
+ * In an End of File record this field con-
+ * sists of either four ascii zeros or the
+ * program entry address. Currently the
+ * entry address option is not supported.
+ *
+ * Data Field - This field consists of the actual data,
+ * converted to two ascii characters, high
+ * digit first. There are no data bytes in
+ * the End of File record.
+ *
+ * Checksum Field - The checksum field is the 8 bit binary
+ * sum of the record length field, the load
+ * address field, and the data field. This
+ * sum is then complemented (1's comple-
+ * ment) and converted to two ascii
+ * characters, high digit first.
+ */
+
+/*)Function s19(i)
+ *
+ * int i 0 - process data
+ * 1 - end of data
+ *
+ * The function s19() loads the output buffer with
+ * the relocated data.
+ *
+ * local variables:
+ * a_uint j temporary
+ *
+ * global variables:
+ * int hilo byte order
+ * FILE * ofp output file handle
+ * int rtcnt count of data words
+ * int rtflg[] output the data flag
+ * a_uint rtval[] relocated data
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ * a_uint rtadr2 address temporary
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID sflush() lks19.c
+ *
+ * side effects:
+ * The data is placed into the output buffer.
+ */
+
+/*
+ * The maximum number of Data Field bytes is NMAX less:
+ * 2 Record Type Field
+ * 2 Record Length Field
+ * 4 Load Address Field
+ * 2 Checksum Field
+ *
+ * Divided by 2 (2 characters per byte)
+ */
+
+#define MAXBYTES ((NMAX - 10)/2)
+
+VOID
+s19(int i)
+{
+ a_uint j;
+ int k;
+
+ if (i) {
+ if (TARGET_IS_6808 && ap->a_flag & A_NOLOAD)
+ return;
+
+ if (hilo == 0) {
+ j = rtval[0];
+ rtval[0] = rtval[1];
+ rtval[1] = j;
+ }
+ rtadr2 = rtval[0] << 8 | rtval[1];
+ if (rtadr2 != rtadr1) {
+ /*
+ * data bytes not contiguous between records
+ */
+ sflush();
+ rtadr0 = rtadr1 = rtadr2;
+ }
+ for (k=2; k<rtcnt; k++) {
+ if (rtflg[k]) {
+ rtbuf[rtadr1++ - rtadr0] = rtval[k];
+ if (rtadr1 - rtadr0 == MAXBYTES) {
+ sflush();
+ }
+ }
+ }
+ } else {
+ sflush();
+ fprintf(ofp, "S9030000FC\n");
+ }
+}
+
+/*)Function sflush()
+ *
+ * The function sflush() outputs the relocated data
+ * in the standard Motorola S19 format.
+ *
+ * local variables:
+ * a_uint chksum byte checksum
+ * int i loop counter
+ * int max number of data bytes
+ * int reclen record length
+ *
+ * global variables:
+ * FILE * ofp output file handle
+ * char rtbuf[] output buffer
+ * a_uint rtadr0 address temporary
+ * a_uint rtadr1 address temporary
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * The data is output to the file defined by ofp.
+ */
+
+/*
+ * Written by G. Osborn, gary@s-4.com, 6-17-98.
+ * The new version concatenates the assembler
+ * output records when they represent contiguous
+ * memory segments to produces NMAX character
+ * S-19 output lines whenever possible, resulting
+ * in a substantial reduction in file size.
+ * More importantly, the download time
+ * to the target system is much improved.
+ */
+
+VOID
+sflush()
+{
+ a_uint chksum;
+ a_uint i, max, reclen;
+
+ max = rtadr1 - rtadr0;
+ if (max == 0) {
+ return;
+ }
+
+ /*
+ * Only the "S1" and the checksum itself are excluded
+ * from the checksum. The record length does not
+ * include "S1" and the pair count. It does
+ * include the two address bytes, the data bytes,
+ * and the checksum.
+ */
+ reclen = max + 3;
+ chksum = reclen;
+ chksum += rtadr0;
+ chksum += rtadr0 >> 8;
+ fprintf(ofp, "S1%02X%04X", reclen, rtadr0);
+ for (i=0; i<max; i++) {
+ chksum += rtbuf[i];
+ fprintf(ofp, "%02X", rtbuf[i] & 0x00ff);
+ }
+ /*
+ * 1's complement
+ */
+ fprintf(ofp, "%02X\n", (~chksum) & 0x00ff);
+ rtadr0 = rtadr1;
+}
--- /dev/null
+/* lksdcclib.c - sdcc library format handling
+
+ Copyright (C) 1989-1995 Alan R. Baldwin
+ 721 Berkeley St., Kent, Ohio 44240
+ Copyright (C) 2008 Borut Razem, borut dot razem at siol dot net
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+/*
+ * With contributions for the
+ * object libraries from
+ * Ken Hornstein
+ * kenh@cmf.nrl.navy.mil
+ *
+ */
+
+/*
+ * Extensions: P. Felber
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "sdld.h"
+#include "lk_readnl.h"
+#include "aslink.h"
+#include "lklibr.h"
+#include "lkrel.h"
+
+#define EQ(A,B) !strcmp((A),(B))
+#define MAXLINE 254 /* when using lk_readnl */
+
+
+static int
+is_sdcclib (FILE * libfp)
+{
+#define SDCCLIB_MAGIC "<SDCCLIB>"
+#define SDCCLIB_MAGIC_LEN (sizeof ("<SDCCLIB>") - 1)
+
+ char buf[SDCCLIB_MAGIC_LEN];
+
+ if (fread (buf, 1, sizeof (buf), libfp) == sizeof (buf) && memcmp (buf, SDCCLIB_MAGIC, SDCCLIB_MAGIC_LEN) == 0)
+ {
+ switch (getc (libfp))
+ {
+ case '\r':
+ if (getc (libfp) == '\n')
+ return 1;
+
+ case '\n':
+ return 1;
+ }
+ }
+ rewind (libfp);
+ return 0;
+}
+
+/* Load a .rel file embedded in a sdcclib file */
+static int
+LoadRel (char *libfname, FILE * libfp, char *ModName)
+{
+ char str[NINPUT];
+ int state = 0;
+
+ while (lk_readnl (str, sizeof (str), libfp) != NULL)
+ {
+ switch (state)
+ {
+ case 0:
+ if (EQ (str, "<FILE>"))
+ {
+ if (NULL != lk_readnl (str, sizeof (str), libfp) && EQ (str, ModName))
+ state = 1;
+ else
+ return 0;
+ }
+ else
+ return 0;
+ break;
+
+ case 1:
+ return EQ (str, "<REL>") ? load_rel (libfp, -1) : 0;
+ }
+ }
+
+ return 0;
+}
+
+#ifdef INDEXLIB
+static pmlibraryfile
+buildlibraryindex_sdcclib (struct lbname *lbnh, FILE * libfp, pmlibraryfile This, int type)
+{
+ char FLine[MAXLINE];
+ int state = 0;
+ long IndexOffset = 0;
+ pmlibrarysymbol ThisSym = NULL;
+
+ while (lk_readnl (FLine, sizeof (FLine), libfp))
+ {
+ switch (state)
+ {
+ case 0:
+ if (EQ (FLine, "<INDEX>"))
+ {
+ /*The next line has the size of the index */
+ lk_readnl (FLine, sizeof (FLine), libfp);
+ IndexOffset = atol (FLine);
+ state = 1;
+ }
+ break;
+
+ case 1:
+ if (EQ (FLine, "<MODULE>"))
+ {
+ char buff[PATH_MAX];
+ char ModName[NCPS] = "";
+ long FileOffset;
+
+ /* The next line has the name of the module and the offset
+ of the corresponding embedded file in the library */
+ lk_readnl (FLine, sizeof (FLine), libfp);
+ sscanf (FLine, "%s %ld", ModName, &FileOffset);
+ state = 2;
+
+ /* Create a new libraryfile object for this module */
+ if (libr == NULL)
+ {
+ libr = This = (pmlibraryfile) new (sizeof (mlibraryfile));
+ }
+ else
+ {
+ This->next = (pmlibraryfile) new (sizeof (mlibraryfile));
+ This = This->next;
+ }
+ This->next = NULL;
+ This->loaded = -1;
+ This->offset = FileOffset + IndexOffset;
+ This->libspc = lbnh->libspc;
+ This->relfil = strdup (ModName);
+ sprintf (buff, "%s%s%c%s", lbnh->path, ModName, FSEPX, LKOBJEXT);
+ This->filspc = strdup (buff);
+ This->type = type;
+
+ This->symbols = ThisSym = NULL; /* Start a new linked list of symbols */
+ }
+ else if (EQ (FLine, "</INDEX>"))
+ {
+ return This; /* Finish, get out of here */
+ }
+ break;
+
+ case 2:
+ if (EQ (FLine, "</MODULE>"))
+ {
+ This->loaded = 0;
+ /* Create the index for the next module */
+ state = 1;
+ }
+ else
+ {
+ /* Add the symbols */
+ if (ThisSym == NULL) /* First symbol of the current module */
+ {
+ ThisSym = This->symbols = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+ }
+ else
+ {
+ ThisSym->next = (pmlibrarysymbol) new (sizeof (mlibrarysymbol));
+ ThisSym = ThisSym->next;
+ }
+ ThisSym->next = NULL;
+ ThisSym->name = strdup (FLine);
+ }
+ break;
+
+ default:
+ return This; /* State machine should never reach this point, but just in case... */
+ break;
+ }
+ }
+
+ return This; /* State machine should never reach this point, but just in case... */
+}
+
+#else
+
+/* Load an .adb file embedded in a sdcclib file. If there is
+something between <ADB> and </ADB> returns 1, otherwise returns 0.
+This way the aomf51 will not have useless empty modules. */
+
+static int
+LoadAdb (FILE * libfp)
+{
+ char str[MAXLINE];
+ int state = 0;
+ int ret = 0;
+
+ while (lk_readnl (str, sizeof (str), libfp) != NULL)
+ {
+ switch (state)
+ {
+ case 0:
+ if (EQ (str, "<ADB>"))
+ state = 1;
+ break;
+
+ case 1:
+ if (EQ (str, "</ADB>"))
+ return ret;
+ fprintf (yfp, "%s\n", str);
+ ret = 1;
+ break;
+ }
+ }
+ return ret;
+}
+
+/* Check for a symbol in a SDCC library. If found, add the embedded .rel and
+ .adb files from the library. The library must be created with the SDCC
+ librarian 'sdcclib' since the linking process depends on the correct file offsets
+ embedded in the library file. */
+
+static int
+findsym_sdcclib (const char *name, struct lbname *lbnh, FILE * libfp, int type)
+{
+ struct lbfile *lbfh;
+ char ModName[NCPS] = "";
+ char FLine[MAXLINE];
+ int state = 0;
+ long IndexOffset = 0, FileOffset;
+
+ while (lk_readnl (FLine, sizeof (FLine), libfp))
+ {
+ char filspc[PATH_MAX];
+
+ if (lbnh->path != NULL)
+ {
+ strcpy (filspc, lbnh->path);
+#ifdef OTHERSYSTEM
+ if (*filspc != '\0' && (filspc[strlen (filspc) - 1] != '/') && (filspc[strlen (filspc) - 1] != LKDIRSEP))
+ {
+ strcat (filspc, LKDIRSEPSTR);
+ }
+#endif
+ }
+
+ switch (state)
+ {
+ case 0:
+ if (EQ (FLine, "<INDEX>"))
+ {
+ /* The next line has the size of the index */
+ lk_readnl (FLine, sizeof (FLine), libfp);
+ IndexOffset = atol (FLine);
+ state = 1;
+ }
+ break;
+
+ case 1:
+ if (EQ (FLine, "<MODULE>"))
+ {
+ /* The next line has the name of the module and the offset
+ of the corresponding embedded file in the library */
+ lk_readnl (FLine, sizeof (FLine), libfp);
+ sscanf (FLine, "%s %ld", ModName, &FileOffset);
+ state = 2;
+ }
+ else if (EQ (FLine, "</INDEX>"))
+ {
+ /* Reached the end of the index. The symbol is not in this library. */
+ return 0;
+ }
+ break;
+
+ case 2:
+ if (EQ (FLine, "</MODULE>"))
+ {
+ /* The symbol is not in this module, try the next one */
+ state = 1;
+ }
+ else
+ {
+ /* Check if this is the symbol we are looking for. */
+ if (strncmp (name, FLine, NCPS) == 0)
+ {
+ /* The symbol is in this module. */
+
+ /* As in the original library format, it is assumed that the .rel
+ files reside in the same directory as the lib files. */
+ sprintf (&filspc[strlen (filspc)], "%s%c%s", ModName, FSEPX, LKOBJEXT);
+
+ /* If this module has been loaded already don't load it again. */
+ if (is_module_loaded (filspc))
+ return 1;
+
+ /* Add the embedded file to the list of files to be loaded in
+ the second pass. That is performed latter by the function
+ library() below. */
+ lbfh = (struct lbfile *) new (sizeof (struct lbfile));
+ if (lbfhead == NULL)
+ {
+ lbfhead = lbfh;
+ }
+ else
+ {
+ struct lbfile *lbf;
+
+ for (lbf = lbfhead; lbf->next; lbf = lbf->next)
+ ;
+
+ lbf->next = lbfh;
+ }
+
+ lbfh->libspc = lbnh->libspc;
+ lbfh->filspc = strdup (filspc);
+ lbfh->relfil = strdup (ModName);
+ lbfh->f_obj = lbnh->f_obj;
+ /* Library embedded file, so lbfh->offset must be >=0 */
+ lbfh->offset = IndexOffset + FileOffset;
+ obj_flag = lbfh->f_obj;
+
+ /* Jump to where the .rel begins and load it. */
+ fseek (libfp, lbfh->offset, SEEK_SET);
+ if (!LoadRel (lbnh->libspc, libfp, ModName))
+ {
+ fclose (libfp);
+ fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, ModName);
+ lkexit (1);
+ }
+ /* if cdb information required & .adb file present */
+ if (yflag && yfp)
+ {
+ if (LoadAdb (libfp))
+ SaveLinkedFilePath (filspc);
+ }
+ return 1; /* Found the symbol, so success! */
+ }
+ }
+ break;
+
+ default:
+ return 0; /* It should never reach this point, but just in case... */
+ break;
+ }
+ }
+
+ return 0; /* The symbol is not in this library */
+}
+
+#endif
+
+static void
+loadfile_sdcclib (struct lbfile *lbfh)
+{
+ FILE *fp;
+ int res;
+
+#ifdef __CYGWIN__
+ char posix_path[PATH_MAX];
+ void cygwin_conv_to_full_posix_path (char *win_path, char *posix_path);
+ cygwin_conv_to_full_posix_path (lbfh->libspc, posix_path);
+ fp = fopen (posix_path, "rb");
+#else
+ fp = fopen (lbfh->libspc, "rb");
+#endif
+
+ if (fp != NULL)
+ {
+ fseek (fp, lbfh->offset, SEEK_SET);
+ res = LoadRel (lbfh->libspc, fp, lbfh->relfil);
+ fclose (fp);
+
+ if (!res)
+ {
+ fprintf (stderr, "?ASlink-Error-Bad offset in library file %s(%s)\n", lbfh->libspc, lbfh->relfil);
+ lkexit (1);
+ }
+ }
+ else
+ {
+ fprintf (stderr, "?ASlink-Error-Opening library '%s'\n", lbfh->libspc);
+ lkexit (1);
+ }
+}
+
+struct aslib_target aslib_target_sdcclib = {
+ &is_sdcclib,
+#ifdef INDEXLIB
+ &buildlibraryindex_sdcclib,
+#else
+ &findsym_sdcclib,
+#endif
+ &loadfile_sdcclib,
+};
--- /dev/null
+/* lksdcdb.c */
+
+/*
+ * Copyright (C) 2001-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ */
+
+#include "aslink.h"
+
+#if SDCDB
+
+/*Module lkcdb.c
+ *
+ * The module lkcdb.c contains the functions
+ * required to create a SDCDB debug file.
+ *
+ * lksdcdb.c contains the following functions:
+ * VOID SDCDBfopen()
+ * VOID SDCDBcopy()
+ * VOID DefineSDCDB()
+ */
+
+/*)Function VOID SDCDBfopen()
+ *
+ * The function SDCDBfopen() opens the SDCDB output file
+ * and sets the map flag, mflag, to create a map file.
+ * SDCDB processing is performed during map generation.
+ *
+ * local variables:
+ * none
+ *
+ * global variables:
+ * int yflag SDCDB Debug flag
+ * FILE * yfp SDCDB Debug File handle
+ * struct lfile *linkp Pointer to the Linker output file name
+ * int mflag Map output flag
+ *
+ * functions called:
+ * FILE * afile() lkmain.c
+ * VOID lkexit() lkmain.c
+ *
+ * side effects:
+ * The SDCDB output file is opened.
+ * Failure to open the file will
+ * terminate the linker.
+ */
+
+VOID SDCDBfopen(void)
+{
+ if (yflag) {
+ SaveLinkedFilePath(linkp->f_idp); //Must be the first one...
+ yfp = afile(linkp->f_idp, "cdb", 1);
+ if (yfp == NULL) {
+ lkexit(1);
+ }
+ mflag = 1;
+ }
+}
+
+
+/*)Function VOID SDCDBcopy()
+ *
+ * char * str pointer to the file spec
+ *
+ * The function SDCDBcopy() copies an existing adb file
+ * into the linker cdb file.
+ *
+ * The function is called from lklex.c and lklibr.c
+ *
+ * local variables:
+ * FILE * xfp file handle
+ * char line[] line from file
+ *
+ * global variables:
+ * int yflag SDCDB Debug flag
+ * FILE * yfp SDCDB Debug File handle
+ *
+ * functions called:
+ * FILE * afile() lkmain.c
+ * int fgets() c_library
+ * int fprintf() c_library
+ * int fclose() c_library
+ *
+ * side effects:
+ * SDCDB cdb file is copied into
+ * the linker cdb output file.
+ */
+
+VOID SDCDBcopy(char * str)
+{
+ FILE * xfp;
+
+ /*
+ * Copy .adb file if present and requested.
+ */
+ if (yflag && yfp) {
+ xfp = afile(str, "adb", 0); //JCF: Nov 30, 2002
+ if (xfp) {
+ copyfile(yfp, xfp);
+ fclose(xfp);
+ }
+ }
+}
+
+
+/*)Function VOID DefineSDCDB()
+ *
+ * char * name pointer to the symbol string
+ * a_uint value value of symbol
+ *
+ * The function DefineSDCDB() processes the symbols into
+ * SDCDB commands for inclusion in the SDCDB output file.
+ *
+ * The function is called from lstarea in lklist.c
+ * for each symbol.
+ *
+ * local variables:
+ * int j argument count
+ * char * p1 temporary string pointer
+ *
+ * global variables:
+ * FILE * yfp SDCDB Debug File handle
+ *
+ * functions called:
+ * int fprintf() c_library
+ * int strchr() c_library
+ *
+ * side effects:
+ * SDCDB debug symbols are placed
+ * into the output file.
+ */
+
+VOID DefineSDCDB(char *name, a_uint value)
+{
+ int j;
+ char *p1;
+
+ /* no output if file is not open */
+ if (yfp == NULL) return;
+
+ /*
+ * SDCC symbols have 3 or more $ characters
+ */
+ j = 0;
+ p1 = name;
+ while ((p1 = strchr(p1, '$')) != NULL) {
+ p1++;
+ j += 1;
+ }
+
+ if (j > 2) {
+#ifdef LONGINT
+ fprintf(yfp, "L:%s:%lX\n", name ,value);
+#else
+ fprintf(yfp, "L:%s:%X\n", name ,value);
+#endif
+ }
+
+}
+
+#endif
+
--- /dev/null
+/* lksym.c */
+
+/*
+ * Copyright (C) 1989-2009 Alan R. Baldwin
+ *
+ * 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, see <http://www.gnu.org/licenses/>.
+ *
+ *
+ * Alan R. Baldwin
+ * 721 Berkeley St.
+ * Kent, Ohio 44240
+ *
+ * With enhancements from
+ * John L. Hartman (JLH)
+ * jhartman@compuserve.com
+ *
+ */
+
+#include "aslink.h"
+
+/*)Module lksym.c
+ *
+ * The module lksym.c contains the functions that operate
+ * on the symbol structures.
+ *
+ * lksym.c contains the following functions:
+ * int hash()
+ * sym * lkpsym()
+ * char * new()
+ * sym * newsym()
+ * char * strsto()
+ * VOID symdef()
+ * int symeq()
+ * VOID syminit()
+ * VOID symmod()
+ * a_uint symval()
+ *
+ * lksym.c contains the static variables:
+ * char * pnext
+ * int bytes
+ * used by the string store function.
+ */
+
+/*)Function VOID syminit()
+ *
+ * The function syminit() is called to clear the hashtable.
+ *
+ * local variables:
+ * sym ** spp pointer to an array of
+ * sym structure pointers
+ *
+ * global variables:
+ * sym * symhash[] array of pointers to NHASH
+ * linked symbol lists
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * (1) The symbol hash tables are cleared
+ */
+
+VOID
+syminit(void)
+{
+ struct sym **spp;
+
+ spp = &symhash[0];
+ while (spp < &symhash[NHASH])
+ *spp++ = NULL;
+}
+
+/*)Function sym * newsym()
+ *
+ * The function newsym() is called to evaluate the symbol
+ * definition/reference directive from the .rel file(s).
+ * If the symbol is not found in the symbol table a new
+ * symbol structure is created. Evaluation of the
+ * directive determines if this is a reference or a definition.
+ * Multiple definitions of the same variable will be flagged
+ * as an error if the values are not identical. A symbol
+ * definition places the symbol value and area extension
+ * into the symbols data structure. And finally, a pointer
+ * to the symbol structure is placed into the head structure
+ * symbol list. Refer to the description of the header, symbol,
+ * area, and areax structures in lkdata.c for structure and
+ * linkage details.
+ *
+ * local variables:
+ * int c character from input text
+ * int i evaluation value
+ * char id[] symbol name
+ * int nglob number of symbols in this header
+ * sym * tsp pointer to symbol structure
+ * sym ** s list of pointers to symbol structures
+ *
+ * global variables:
+ * areax *axp Pointer to the current
+ * areax structure
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * int lkerr error flag
+ *
+ * functions called:
+ * a_uint eval() lkeval.c
+ * VOID exit() c_library
+ * int fprintf() c_library
+ * char getSid() lklex.c
+ * int get() lklex.c
+ * int getnb() lklex.c
+ * sym * lkpsym() lksym.c
+ *
+ * side effects:
+ * A symbol structure is created and/or modified.
+ * If structure space allocation fails linker will abort.
+ * Several severe errors (these are internal errors
+ * indicating a corrupted .rel file or corrupted
+ * assembler or linker) will terminated the linker.
+ */
+
+/*
+ * Find/Create a global symbol entry.
+ *
+ * S xxxxxx Defnnnn
+ * | | |
+ * | | `-- sp->s_addr
+ * | `----- sp->s_type
+ * `------------ sp->s_id
+ *
+ */
+struct sym *
+newsym(void)
+{
+ a_uint ev;
+ int c, i, nsym;
+ struct sym *tsp;
+ struct sym **s;
+ char id[NCPS];
+
+ if (headp == NULL) {
+ fprintf(stderr, "No header defined\n");
+ lkexit(ER_FATAL);
+ }
+ /*
+ * Create symbol entry
+ */
+ getSid(id);
+ tsp = lkpsym(id, 1);
+ c = getnb();get();get();
+ if (c == 'R') {
+ tsp->s_type |= S_REF;
+ if (eval()) {
+ fprintf(stderr, "Non zero S_REF\n");
+ lkerr++;
+ }
+ } else
+ if (c == 'D') {
+ ev = eval();
+ if (tsp->s_type & S_DEF &&
+ !(tsp->s_addr == ev && tsp->s_axp && tsp->s_axp->a_bap && ((tsp->s_axp->a_bap->a_flag & A3_ABS) == A3_ABS))) {
+ fprintf(stderr,
+ "Multiple definition of %s\n", id);
+ lkerr++;
+ }
+ /*
+ * Set value and area extension link.
+ */
+ tsp->s_addr = ev;
+ tsp->s_axp = axp;
+ tsp->s_type |= S_DEF;
+ tsp->m_id = hp->m_id;
+ } else {
+ fprintf(stderr, "Invalid symbol type %c for %s\n", c, id);
+ lkexit(ER_FATAL);
+ }
+ /*
+ * Place pointer in header symbol list
+ */
+ nsym = hp->h_nsym;
+ s = hp->s_list;
+ for (i=0; i < nsym ;++i) {
+ if (s[i] == NULL) {
+ s[i] = tsp;
+ return(tsp);
+ }
+ }
+ fprintf(stderr, "Header symbol list overflow\n");
+ lkexit(ER_FATAL);
+ return(NULL);
+}
+
+/*)Function sym * lkpsym(id,f)
+ *
+ * char * id symbol name string
+ * int f f == 0, lookup only
+ * f != 0, create if not found
+ *
+ * The function lookup() searches the symbol hash tables for
+ * a symbol name match returning a pointer to the sym structure.
+ * If the symbol is not found then a sym structure is created,
+ * initialized, and linked to the appropriate hash table if f != 0.
+ * A pointer to this new sym structure is returned or a NULL
+ * pointer is returned if f == 0.
+ *
+ * local variables:
+ * int h computed hash value
+ * sym * sp pointer to a sym structure
+ *
+ * global varaibles:
+ * sym * symhash[] array of pointers to NHASH
+ * linked symbol lists
+ * int zflag Disable symbol case sensitivity
+ *
+ * functions called:
+ * int hash() lksym.c
+ * char * new() lksym.c
+ * int symeq() lksym.c
+ *
+ * side effects:
+ * If the function new() fails to allocate space
+ * for the new sym structure the linker terminates.
+ */
+
+struct sym *
+lkpsym(char *id, int f)
+{
+ struct sym *sp;
+ int h;
+
+ h = hash(id, zflag);
+ sp = symhash[h];
+ while (sp != NULL) {
+ if (symeq(id, sp->s_id, zflag))
+ return (sp);
+ sp = sp->s_sp;
+ }
+ if (f == 0)
+ return (NULL);
+ sp = (struct sym *) new (sizeof(struct sym));
+ sp->s_sp = symhash[h];
+ symhash[h] = sp;
+ sp->s_id = strsto(id); /* JLH */
+ return (sp);
+}
+
+/*)Function a_uint symval(tsp)
+ *
+ * sym * tsp pointer to a symbol structure
+ *
+ * The function symval() returns the value of the
+ * relocated symbol by adding the variable definition
+ * value to the areax base address.
+ *
+ * local variables:
+ * a_uint val relocated address value
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+a_uint
+symval(struct sym *tsp)
+{
+ a_uint val;
+
+ val = tsp->s_addr;
+ if (tsp->s_axp) {
+ val += tsp->s_axp->a_addr;
+ }
+ return(val);
+}
+
+/*)Function VOID symdef(fp)
+ *
+ * FILE * fp file handle for output
+ *
+ * The function symdef() scans the hashed symbol table
+ * searching for variables referenced but not defined.
+ * Undefined variables are linked to the default
+ * area "_CODE" and reported as referenced by the
+ * appropriate module.
+ *
+ * local variables:
+ * int i hash table index loop variable
+ * sym * sp pointer to linked symbol structure
+ *
+ * global variables:
+ * area *areap The pointer to the first
+ * area structure of a linked list
+ * sym *symhash[NHASH] array of pointers to NHASH
+ * linked symbol lists
+ *
+ * functions called:
+ * symmod() lksym.c
+ *
+ * side effects:
+ * Undefined variables have their areas set to "_CODE".
+ */
+
+VOID
+symdef(FILE *fp)
+{
+ struct sym *sp;
+ int i;
+
+ for (i=0; i<NHASH; ++i) {
+ sp = symhash[i];
+ while (sp) {
+ if (sp->s_axp == NULL)
+ sp->s_axp = areap->a_axp;
+ if ((sp->s_type & S_DEF) == 0)
+ symmod(fp, sp);
+ sp = sp->s_sp;
+ }
+ }
+}
+
+/*)Function VOID symmod(fp,tsp)
+ *
+ * FILE * fp output file handle
+ * sym * tsp pointer to a symbol structure
+ *
+ * The function symmod() scans the header structures
+ * searching for a reference to the symbol structure
+ * pointed to by tsp. The function then generates an error
+ * message whichs names the module having referenced the
+ * undefined variable.
+ *
+ * local variables:
+ * int i loop counter
+ * sym ** p pointer to a list of pointers
+ * to symbol structures
+ *
+ * global variables:
+ * head *headp The pointer to the first
+ * head structure of a linked list
+ * head *hp Pointer to the current
+ * head structure
+ * int lkerr error flag
+ *
+ * functions called:
+ * int fprintf() c_library
+ *
+ * side effects:
+ * Error output generated.
+ */
+
+VOID
+symmod(FILE *fp, struct sym *tsp)
+{
+ int i;
+ struct sym **p;
+
+ if ((hp = headp) != NULL) {
+ while(hp) {
+ p = hp->s_list;
+ for (i=0; i<hp->h_nsym; ++i) {
+ if (p[i] == tsp) {
+ fprintf(fp,
+ "\n?ASlink-Warning-Undefined Global '%s' ",
+ tsp->s_id);
+ fprintf(fp,
+ "referenced by module '%s'\n",
+ hp->m_id);
+ lkerr++;
+ }
+ }
+ hp = hp->h_hp;
+ }
+ }
+}
+
+/*)Function int symeq(p1, p2, cflag)
+ *
+ * int cflag case sensitive flag
+ * char * p1 name string
+ * char * p2 name string
+ *
+ * The function symeq() compares the two name strings for a match.
+ * The return value is 1 for a match and 0 for no match.
+ *
+ * cflag == 0 case sensitive compare
+ * cflag != 0 case insensitive compare
+ *
+ * local variables:
+ * int n loop counter
+ *
+ * global variables:
+ * char ccase[] an array of characters which
+ * perform the case translation function
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ *
+ */
+
+int
+symeq(char *p1, char *p2, int cflag)
+{
+ int n;
+
+ n = strlen(p1) + 1;
+ if(cflag) {
+ /*
+ * Case Insensitive Compare
+ */
+ do {
+ if (ccase[*p1++ & 0x007F] != ccase[*p2++ & 0x007F])
+ return (0);
+ } while (--n);
+ } else {
+ /*
+ * Case Sensitive Compare
+ */
+ do {
+ if (*p1++ != *p2++)
+ return (0);
+ } while (--n);
+ }
+ return (1);
+}
+
+/*)Function int hash(p, cflag)
+ *
+ * char * p pointer to string to hash
+ * int cflag case sensitive flag
+ *
+ * The function hash() computes a hash code using the sum
+ * of all characters mod table size algorithm.
+ *
+ * cflag == 0 case sensitive hash
+ * cflag != 0 case insensitive hash
+ *
+ * local variables:
+ * int h accumulated character sum
+ *
+ * global variables:
+ * char ccase[] an array of characters which
+ * perform the case translation function
+ *
+ * functions called:
+ * none
+ *
+ * side effects:
+ * none
+ */
+
+int
+hash(char *p, int cflag)
+{
+ int h;
+
+ h = 0;
+ while (*p) {
+ if(cflag) {
+ /*
+ * Case Insensitive Hash
+ */
+ h += ccase[*p++ & 0x007F];
+ } else {
+ /*
+ * Case Sensitive Hash
+ */
+ h += *p++;
+ }
+ }
+ return (h&HMASK);
+}
+
+#if decus
+
+/*)Function char * strsto(str)
+ *
+ * char * str pointer to string to save
+ *
+ * Allocate space for "str", copy str into new space.
+ * Return a pointer to the allocated string.
+ *
+ * This function based on code by
+ * John L. Hartman
+ * jhartman@compuserve.com
+ *
+ * local variables:
+ * int l string length + 1
+ * char * p string location
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * char * new() assym.c
+ * char * strncpy() c_library
+ *
+ * side effects:
+ * Space allocated for string, string copied
+ * to space. Out of Space terminates linker.
+ */
+
+char *
+strsto(char *str)
+{
+ int l;
+ char *p;
+
+ /*
+ * What we need, including a null.
+ */
+ l = strlen(str) + 1;
+ p = (char *) new (l);
+
+ /*
+ * Copy the name and terminating null.
+ */
+ strncpy(p, str, l);
+ return(p);
+}
+
+/*
+ * This code is optimized for the PDP-11 (decus)
+ * which has a limited program space of 56K Bytes !
+ * Short strings and small structures are allocated
+ * from a memory hunk in new() to reduce the overhead
+ * from allocations directly by malloc(). Longer
+ * allocations are made directly by malloc.
+ * PDP-11 addressing requires that variables
+ * are allocated on a word boundary, (strings donot
+ * have this restriction,) all allocations will have
+ * at most 1 extra byte to maintain the word boundary
+ * requirement.
+ */
+
+/*)Function char * new(n)
+ *
+ * unsigned int n allocation size in bytes
+ *
+ * The function new() allocates n bytes of space and returns
+ * a pointer to this memory. If no space is available the
+ * linker is terminated.
+ *
+ * Allocate space for "str", copy str into new space.
+ * Return a pointer to the allocated string.
+ *
+ * This function based on code by
+ * John L. Hartman
+ * jhartman@compuserve.com
+ *
+ * local variables:
+ * int bytes bytes remaining in buffer area
+ * int i loop counter
+ * char * p pointer to head of copied string
+ * char * pnext next location in buffer area
+ * char * q a general pointer
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID * malloc() c_library
+ *
+ * side effects:
+ * Memory is allocated, if allocation fails
+ * the linker is terminated.
+ */
+
+/*
+ * To avoid wasting memory headers on small allocations, we
+ * allocate a big chunk and parcel it out as required.
+ * These static variables remember our hunk.
+ */
+
+#define STR_SPC 1024
+#define STR_MIN 16
+static char * pnext = NULL;
+static int bytes = 0;
+
+char *
+new(unsigned int n)
+{
+ char *p,*q;
+ unsigned int i;
+
+ /*
+ * Always an even byte count
+ */
+ n = (n+1) & 0xFFFE;
+
+ if (n > STR_MIN) {
+ /*
+ * For allocations larger than
+ * most structures and short strings
+ * allocate the space directly.
+ */
+ p = (char *) malloc(n);
+ } else {
+ /*
+ * For smaller structures and
+ * strings allocate from the hunk.
+ */
+ if (n > bytes) {
+ /*
+ * No space. Allocate a new hunk.
+ * We lose the pointer to any old hunk.
+ * We don't care, as the pieces are never deleted.
+ */
+ pnext = (char *) malloc (STR_SPC);
+ bytes = STR_SPC;
+ }
+ p = pnext;
+ pnext += n;
+ bytes -= n;
+ }
+ if (p == NULL) {
+ fprintf(stderr, "Out of space!\n");
+ lkexit(ER_FATAL);
+ }
+ for (i=0,q=p; i<n; i++) {
+ *q++ = 0;
+ }
+ return (p);
+}
+
+#else
+
+/*)Function char * strsto(str)
+ *
+ * char * str pointer to string to save
+ *
+ * Allocate space for "str", copy str into new space.
+ * Return a pointer to the allocated string.
+ *
+ * This function based on code by
+ * John L. Hartman
+ * jhartman@compuserve.com
+ *
+ * local variables:
+ * int l string length + 1
+ * int bytes bytes remaining in buffer area
+ * char * p pointer to head of copied string
+ * char * pnext next location in buffer area
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * char * new() assym.c
+ * char * strncpy() c_library
+ *
+ * side effects:
+ * Space allocated for string, string copied
+ * to space. Out of Space terminates assembler.
+ */
+
+/*
+ * To avoid wasting memory headers on small allocations, we
+ * allocate a big chunk and parcel it out as required.
+ * These static variables remember our hunk
+ */
+
+#define STR_SPC 1024
+static char * pnext = NULL;
+static int bytes = 0;
+
+char *
+strsto(char *str)
+{
+ int l;
+ char *p;
+
+ /*
+ * What we need, including a null.
+ */
+ l = strlen(str) + 1;
+
+ if (l > bytes) {
+ /*
+ * No space. Allocate a new hunk.
+ * We lose the pointer to any old hunk.
+ * We don't care, as the strings are never deleted.
+ */
+ pnext = (char *) new (STR_SPC);
+ bytes = STR_SPC;
+ }
+
+ /*
+ * Copy the name and terminating null.
+ */
+ p = pnext;
+ strncpy(p, str, l);
+
+ pnext += l;
+ bytes -= l;
+
+ return(p);
+}
+
+/*)Function char * new(n)
+ *
+ * unsigned int n allocation size in bytes
+ *
+ * The function new() allocates n bytes of space and returns
+ * a pointer to this memory. If no space is available the
+ * linker is terminated.
+ *
+ * local variables:
+ * char * p a general pointer
+ * char * q a general pointer
+ *
+ * global variables:
+ * none
+ *
+ * functions called:
+ * int fprintf() c_library
+ * VOID * malloc() c_library
+ *
+ * side effects:
+ * Memory is allocated, if allocation fails
+ * the linker is terminated.
+ */
+
+char *
+new(unsigned int n)
+{
+ char *p,*q;
+ unsigned int i;
+
+ if ((p = (char *) malloc(n)) == NULL) {
+ fprintf(stderr, "Out of space!\n");
+ lkexit(ER_FATAL);
+ }
+ for (i=0,q=p; i<n; i++) {
+ *q++ = 0;
+ }
+ return (p);
+}
+
+#endif
--- /dev/null
+DS80C390 flat mode support
+
+2/4/2000 Kevin Vigor (e-mail: kevin at vigor.nu)
+
+I have hacked the 8051 assembler to support the 24 bit flat address mode of
+the DS80C390 processor. This mode allows the chip to directly address up to
+4 Meg of RAM. Details can be found at Dallas' web site: www.dalsemi.com.
+
+1: Assembler changes.
+
+24 bit mode is entered via a new assembler directive, .flat24. This directive
+takes a mandatory argument, which is either the string "on" or the string
+"off". ".flat24 on" enables 24-bit mode, and ".flat24 off" puts the assembler
+into standard 8051 mode.
+
+Note that any .included files within a ".flat24 on" segment of the code will
+be compiled in 24-bit mode.
+
+In 24-bit mode, 8 instructions have altered behavior. Of these, 5 modify
+the instruction encoding, while 3 differ only in behavior. These
+instructions are discussed in the DS80C390 User's Guide, but a summary is
+included here:
+
+ACALL and AJMP now take a 19 bit offset instead of the 8051's 11 bit offset.
+An extra address byte is added to the encoded instruction.
+
+LCALL and LJMP now take a 24 bit target address instead of the 8051's 16 bit
+address. An extra address byte is added to the encoded instruction.
+
+MOV DPTR, #immed now takes a 24 bit immediate value instead of the 8051's 16
+bit address. An extra data byte is added to the encoded instruction.
+
+INC DPTR now increments the entire 24 bit DPTR. The encoding is not changed.
+
+RET and RETI restore the full 24 bit PC from the stack. The encoding is not
+changed.
+
+2: Linker changes.
+
+The linker supports (through a variety of evil hacks) 19 bit ACALL/AJMP
+relocations and 24 bit LCALL/LJMP/DPTR relocations. These changes should be
+invisible to the user.
+
+The linker can now also generated extended linear address records in the
+Intel hex output format. This is necessary for any areas located above the
+64K mark. This is enabled by the "-r" linker flag, and is disabled by
+default (but the linker will throw a warning if an extended address is
+encountered without the -r flag being enabled).
+
+Note that for various reasons, areas may still not be larger than 64K.
+However, they may be located anywhere in the 4 Meg address space via the
+assembler .org directive (for ABS areas) or the linker "-b" option.
+
+3: Examples
+
+Note that this example uses ABS areas to make the layout obvious. This code
+won't do anything useful at all, but demonstrates the instruction encoding
+in .flat24 mode vs 8051 mode.
+
+; test1.asm
+.area CODE (ABS)
+.org 0
+
+; SFRs not known to the assembler yet...
+$TA = 0x00C7
+$ACON = 0x009D
+
+; Set the chip to 24 bit flat mode via the DS "timed access" procedure.
+mov $TA, #0xAA
+mov $TA, #0x55
+mov $ACON, #0x06 ; 10 bit stack & 24 bit flat addressing.
+
+.flat24 on ; Enable 24-bit mode. The AM1 bit had better be
+ ; on...
+
+mov dptr, #myData ; Valid on the '390: myData is in the FARDATA
+ ; area at 0x300001.
+ ; Generates: 90 30 00 01
+acall _junkNear ; Within 11 bit range, but still must generate
+ ; 19 bit address for '390 flat mode.
+ ; Generates: 11 04 00
+ajmp _junkFar ; Within 16 bit range.
+ ; Generates 01 08 00
+acall _junkReallyFar ; Within 19 bit range.
+ ; Generates 91 00 00
+lcall _junkReallyReallyFar ; Within 24 bit range.
+ ; Generates 12 08 00 00
+
+; Set the chip to 8051 mode via the DS "timed access" procedure.
+mov $TA, #0x0AA
+mov $TA, #0x055
+mov $ACON, #0x00 ; 8 bit stack & 16 bit flat addressing.
+
+.flat24 off ; Now we're an 8051 again. The AM1 bit had better be
+ ; off...
+
+;mov dptr, #myData ; Can't do that: myData is too far away.
+acall _junkNear ; Within 11 bit range.
+ ; Generates 91 00
+ljmp _junkFar ; Within 16 bit range; can't AJMP, but can LJMP
+ ; Generates 02 08 00
+ret
+
+.area CODE2 (ABS)
+.org 0x400
+; This is within the 11 bit ACALL/AJMP range of the 8051.
+_junkNear:
+ret
+
+.area CODE3 (ABS)
+.org 0x800
+; This is within the 390's 19 bit ACALL/AJMP range, and inside the stock
+; 8051's 16 bit LCALL range.
+_junkFar:
+ret
+
+.area CODE4 (ABS)
+; This is within the 390's 19 bit ACALL/AJMP range and outside the
+; 8051's LCALL range.
+; Note that to link an image with an area beyond 64K (like this one),
+; the '-r' flag must be provided to the linker, and Intel Hex output format
+; must be used.
+.org 0x40000
+_junkReallyFar:
+ret
+
+.area CODE5 (ABS)
+; This is outside anybody's ACALL/AJMP range.
+.org 0x80000
+_junkReallyReallyFar:
+ret
+
+.area FARDATA (ABS)
+.org 0x300000
+; This is way, way up there.
+.byte 0x01
+myData:
+.byte 0x02
+
+; test1.asm ends.
+
--- /dev/null
+/* sdld.c
+
+ Copyright (C) 2009-2010 Borut Razem
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef _WIN32
+#include <libgen.h>
+#endif
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "sdld.h"
+
+#define NELEM(x) (sizeof (x) / sizeof (x)[0])
+
+
+static int sdld = -1;
+static enum sdld_target_e target = TARGET_ID_UNKNOWN;
+
+
+static char
+*program_name (char *path)
+{
+#ifdef _WIN32
+ static char fname[_MAX_FNAME];
+ char *p;
+
+ _splitpath (path, NULL, NULL, fname, NULL);
+ /* convert it to lower case:
+ on DOS and Windows 9x the file name in argv[0] is uppercase */
+ for (p = fname; '\0' != *p; ++p)
+ *p = tolower (*p);
+ return fname;
+#else
+ return basename (path);
+#endif
+}
+
+
+static void
+check_init(void)
+{
+ if (sdld == -1)
+ {
+ fprintf(stderr, "sdld_init not called!\n");
+ exit (1);
+ }
+}
+
+
+void
+sdld_init (char *path)
+{
+ struct tgt_s {
+ char *str;
+ enum sdld_target_e target;
+ } tgt[] = {
+ { "gb", TARGET_ID_GB, },
+ { "z80", TARGET_ID_Z80, },
+ { "z180", TARGET_ID_Z180, },
+ { "8051", TARGET_ID_8051, },
+ { "6808", TARGET_ID_6808, },
+ { "stm8", TARGET_ID_STM8, },
+ };
+ int i = NELEM (tgt);
+
+ char *progname = program_name (path);
+ if ((sdld = (strncmp(progname, "sdld", 4) == 0)) != 0)
+ {
+ /* exception: sdld is 8051 linker */
+ if (progname[4] == '\0')
+ target = TARGET_ID_8051;
+ else
+ {
+ for (i = 0; i < NELEM (tgt); ++i)
+ {
+ if (strstr(progname, tgt[i].str))
+ {
+ target = tgt[i].target;
+ break;
+ }
+ }
+ }
+ }
+ /* diagnostic message */
+ if (getenv ("SDLD_DIAG"))
+ {
+ printf ("sdld path: %s\n", path);
+ printf ("is sdld: %d\n", sdld);
+ if (sdld)
+ printf ("sdld target: %s\n", (i >= NELEM (tgt)) ? "8051" : tgt[i].str);
+ }
+}
+
+
+int
+is_sdld(void)
+{
+ check_init();
+ return sdld;
+}
+
+
+enum sdld_target_e
+get_sdld_target(void)
+{
+ check_init();
+ return target;
+}
+
+
+int
+is_sdld_target_z80_like(void)
+{
+ check_init();
+ return target == TARGET_ID_Z80 || target == TARGET_ID_Z180 || target == TARGET_ID_GB;
+}
+
+
+int
+is_sdld_target_8051_like(void)
+{
+ check_init();
+ return target == TARGET_ID_8051;
+}
--- /dev/null
+/* sdld.h
+
+ Copyright (C) 2009 Borut Razem
+
+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, 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, see <http://www.gnu.org/licenses/>. */
+
+#ifndef __SDLD_H
+#define __SDLD_H
+
+enum sdld_target_e {
+ TARGET_ID_UNKNOWN,
+ TARGET_ID_GB,
+ TARGET_ID_Z80,
+ TARGET_ID_Z180,
+ TARGET_ID_8051,
+ TARGET_ID_6808,
+ TARGET_ID_STM8,
+};
+
+void sdld_init (char *path);
+int is_sdld(void);
+enum sdld_target_e get_sdld_target(void);
+int is_sdld_target_z80_like(void);
+int is_sdld_target_8051_like(void);
+
+#define TARGET_IS_GB (get_sdld_target() == TARGET_ID_GB)
+#define TARGET_IS_Z80 (get_sdld_target() == TARGET_ID_Z80)
+#define TARGET_IS_Z180 (get_sdld_target() == TARGET_ID_Z180)
+#define TARGET_IS_8051 (get_sdld_target() == TARGET_ID_8051)
+#define TARGET_IS_6808 (get_sdld_target() == TARGET_ID_6808)
+#define TARGET_IS_STM8 (get_sdld_target() == TARGET_ID_STM8)
+
+#endif /* __SDLD_H */