From: Alan Cox Date: Wed, 31 Dec 2014 22:30:15 +0000 (+0000) Subject: bankld: initial hackery to create a banking sdldz80 X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=7903699e910a2e79275cc10bc89dbf302ea9ffd5;p=FUZIX.git bankld: initial hackery to create a banking sdldz80 The modifications here are - emit a modified ihx file format giving the bank identifier, so that we can split the .ihx files and generate a set of bin files for the overlaid areas. - spot and output extra inter-bank relocation entries into the modified ihx file that can be read and processed by binmunge. The follow basically is Link with modified sdldz80 Run bihx This produces relocs.dat - relocation between banks common.ihx - ihx file for the common bank bank[123].ihx - relocation for the banks and then reprocesses the ihx files into .bin versions using makebin binmunge the reads the relocs.dat and patches the resulting binary data to use RST in place of CALL and stubs for the rest --- diff --git a/Kernel/tools/bankld/Makefile b/Kernel/tools/bankld/Makefile new file mode 100644 index 00000000..4d119323 --- /dev/null +++ b/Kernel/tools/bankld/Makefile @@ -0,0 +1,21 @@ +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 diff --git a/Kernel/tools/bankld/README b/Kernel/tools/bankld/README new file mode 100644 index 00000000..873f437e --- /dev/null +++ b/Kernel/tools/bankld/README @@ -0,0 +1,17 @@ + +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 diff --git a/Kernel/tools/bankld/aslink.h b/Kernel/tools/bankld/aslink.h new file mode 100644 index 00000000..5c6a988e --- /dev/null +++ b/Kernel/tools/bankld/aslink.h @@ -0,0 +1,1319 @@ +/* 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 . + * + * + * Alan R. Baldwin + * 721 Berkeley St. + * Kent, Ohio 44240 + * + * With enhancements from + * John L. Hartman (JLH) + * jhartman@compuserve.com + */ + +/* + * System Include Files + */ + +#include +#include +#include +#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 +#ifndef PATH_MAX /* POSIX, but not required */ + #if defined(__BORLANDC__) || defined(_MSC_VER) + #include + #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 diff --git a/Kernel/tools/bankld/asxxxx_config.h b/Kernel/tools/bankld/asxxxx_config.h new file mode 100644 index 00000000..a5637d35 --- /dev/null +++ b/Kernel/tools/bankld/asxxxx_config.h @@ -0,0 +1,11 @@ +#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 */ diff --git a/Kernel/tools/bankld/lk_readnl.c b/Kernel/tools/bankld/lk_readnl.c new file mode 100644 index 00000000..5eecf9dc --- /dev/null +++ b/Kernel/tools/bankld/lk_readnl.c @@ -0,0 +1,93 @@ +/* + 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; +} diff --git a/Kernel/tools/bankld/lk_readnl.h b/Kernel/tools/bankld/lk_readnl.h new file mode 100644 index 00000000..b02cffb9 --- /dev/null +++ b/Kernel/tools/bankld/lk_readnl.h @@ -0,0 +1,44 @@ +/* + 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 + +#ifdef __cplusplus +extern "C" +{ +#endif + + char *lk_readnl (char *s, int size, FILE * stream); + +#ifdef __cplusplus +} +#endif + +#endif /* __LK_READNL_H */ diff --git a/Kernel/tools/bankld/lkaomf51.c b/Kernel/tools/bankld/lkaomf51.c new file mode 100644 index 00000000..d88732fc --- /dev/null +++ b/Kernel/tools/bankld/lkaomf51.c @@ -0,0 +1,1119 @@ +/* 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 . */ + +#include +#include +#include +#include +#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=0)?procedure[symbol[j].Procedure].name:"GLOBAL", + symbol[j].Address, + k<6?UsageTypeName[k]:"???"); + } + + fprintf(DumpFile,"\nPROCEDURES:\n"); + for(j=0; j %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; iProcedure && 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; j2) /*If there are any symbols*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize); /*Record Length*/ + OutputByte(0x01); /*DEF TYPE: Public symbols*/ + for(k=0; k2) /*If there are any symbols*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize); /*Record Length*/ + OutputByte(0x00); /*DEF TYPE: Local symbols*/ + for(k=0; k2) /*If there are any symbols*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize); /*Record Length*/ + OutputByte(0x00); /*DEF TYPE: Local symbols*/ + for(i=0; i2) /*If there are any line numbers*/ + { + OutputByte(0x12); /*REC TYPE*/ + OutputWord(recsize); /*Record Length*/ + OutputByte(0x03); /*DEF TYPE: Line numbers*/ + for(i=0; i i) + { + /*Content Record*/ + OutputByte(0x06);/*REC TYPE*/ + OutputWord(k-i+4);/*Record Length*/ + OutputByte(0x00);/*SEG ID*/ + OutputWord(i); /*Offset*/ + for ( ; 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|L.}$$$(),
,," + 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(),
,,*/ + 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(),
,,,,, */ + 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=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. */ + +/* + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#include + +#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, +}; diff --git a/Kernel/tools/bankld/lkar.h b/Kernel/tools/bankld/lkar.h new file mode 100644 index 00000000..717ed783 --- /dev/null +++ b/Kernel/tools/bankld/lkar.h @@ -0,0 +1,89 @@ +/* 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 . */ + +#ifndef __LKAR_H +#define __LKAR_H + +#include +#include + + +#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 "!\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 */ diff --git a/Kernel/tools/bankld/lkarea.c b/Kernel/tools/bankld/lkarea.c new file mode 100644 index 00000000..314f13da --- /dev/null +++ b/Kernel/tools/bankld/lkarea.c @@ -0,0 +1,1299 @@ +/* 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 . + * + * + * 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_ and l_ 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_ the start address of the area + * l_ 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_ the start address of the area + * l_ 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)) && (ja_size=0; j(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; ja_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; ja_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)) && (ja_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 */ + diff --git a/Kernel/tools/bankld/lkbank.c b/Kernel/tools/bankld/lkbank.c new file mode 100644 index 00000000..22dfd76e --- /dev/null +++ b/Kernel/tools/bankld/lkbank.c @@ -0,0 +1,644 @@ +/* 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 . + * + * + * 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; + } +} diff --git a/Kernel/tools/bankld/lkdata.c b/Kernel/tools/bankld/lkdata.c new file mode 100644 index 00000000..bb839009 --- /dev/null +++ b/Kernel/tools/bankld/lkdata.c @@ -0,0 +1,623 @@ +/* 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 . + * + * + * 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' +}; diff --git a/Kernel/tools/bankld/lkelf.c b/Kernel/tools/bankld/lkelf.c new file mode 100644 index 00000000..46c6914c --- /dev/null +++ b/Kernel/tools/bankld/lkelf.c @@ -0,0 +1,804 @@ +/* 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 . */ + +#include +#include +#include +#include +#include + +#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; ie_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; ia_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(); +} diff --git a/Kernel/tools/bankld/lkeval.c b/Kernel/tools/bankld/lkeval.c new file mode 100644 index 00000000..e4662c95 --- /dev/null +++ b/Kernel/tools/bankld/lkeval.c @@ -0,0 +1,449 @@ +/* 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 . + * + * + * 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); +} diff --git a/Kernel/tools/bankld/lkhead.c b/Kernel/tools/bankld/lkhead.c new file mode 100644 index 00000000..f7970a05 --- /dev/null +++ b/Kernel/tools/bankld/lkhead.c @@ -0,0 +1,313 @@ +/* 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 . + * + * + * 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++; + } +} diff --git a/Kernel/tools/bankld/lkihx.c b/Kernel/tools/bankld/lkihx.c new file mode 100644 index 00000000..355c96f1 --- /dev/null +++ b/Kernel/tools/bankld/lkihx.c @@ -0,0 +1,278 @@ +/* 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 . */ + +#include +#include +#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; +} diff --git a/Kernel/tools/bankld/lklex.c b/Kernel/tools/bankld/lklex.c new file mode 100644 index 00000000..6979c92e --- /dev/null +++ b/Kernel/tools/bankld/lklex.c @@ -0,0 +1,669 @@ +/* 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 . + * + * + * 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; +} diff --git a/Kernel/tools/bankld/lklib.c b/Kernel/tools/bankld/lklib.c new file mode 100644 index 00000000..e6da0ca5 --- /dev/null +++ b/Kernel/tools/bankld/lklib.c @@ -0,0 +1,253 @@ +/* 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 . */ + +/* + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#include + +#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, +}; diff --git a/Kernel/tools/bankld/lklibr.c b/Kernel/tools/bankld/lklibr.c new file mode 100644 index 00000000..1124fff8 --- /dev/null +++ b/Kernel/tools/bankld/lklibr.c @@ -0,0 +1,856 @@ +/* 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 . + * + * + * 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 +#include + +#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 +} diff --git a/Kernel/tools/bankld/lklibr.h b/Kernel/tools/bankld/lklibr.h new file mode 100644 index 00000000..21f21264 --- /dev/null +++ b/Kernel/tools/bankld/lklibr.h @@ -0,0 +1,95 @@ +/* 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 . */ + +/* + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#ifndef __LKLIBR_H +#define __LKLIBR_H + +#include + +#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 */ diff --git a/Kernel/tools/bankld/lklist.c b/Kernel/tools/bankld/lklist.c new file mode 100644 index 00000000..71106c95 --- /dev/null +++ b/Kernel/tools/bankld/lklist.c @@ -0,0 +1,1304 @@ +/* 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 . + * + * + * 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= 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;is_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; is_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; is_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; is_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; + } +} diff --git a/Kernel/tools/bankld/lkmain.c b/Kernel/tools/bankld/lkmain.c new file mode 100644 index 00000000..f68e8f93 --- /dev/null +++ b/Kernel/tools/bankld/lkmain.c @@ -0,0 +1,1896 @@ +/* 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 . + * + * + * 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> %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- : \"%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- : \"%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); + } +} diff --git a/Kernel/tools/bankld/lkmem.c b/Kernel/tools/bankld/lkmem.c new file mode 100644 index 00000000..0e87c2d8 --- /dev/null +++ b/Kernel/tools/bankld/lkmem.c @@ -0,0 +1,702 @@ +/* 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 . */ + +#include +#include +#include +#include +#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_addra_addr; + } + + else if (EQ(xp->a_id, "ISEG")) + { + IRam.Size+=xp->a_size; + if(xp->a_addra_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_addra_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_addra_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_addra_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_addra_addr; + } + + else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG")) + { + XRam.Size+=xp->a_size; + if(xp->a_addra_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_addra_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(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; + } +} + diff --git a/Kernel/tools/bankld/lknoice.c b/Kernel/tools/bankld/lknoice.c new file mode 100644 index 00000000..39725411 --- /dev/null +++ b/Kernel/tools/bankld/lknoice.c @@ -0,0 +1,656 @@ +/* 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 . + * + * + * 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 diff --git a/Kernel/tools/bankld/lkout.c b/Kernel/tools/bankld/lkout.c new file mode 100644 index 00000000..090ee6a8 --- /dev/null +++ b/Kernel/tools/bankld/lkout.c @@ -0,0 +1,957 @@ +/* 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 . + * + * + * 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; ja_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; is_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; is_axp->a_bap->a_ofp == ofp)) { + symadr = symval(sp); + for (i=0,addr=symadr; i>=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>=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; is_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; +} diff --git a/Kernel/tools/bankld/lkrel.c b/Kernel/tools/bankld/lkrel.c new file mode 100644 index 00000000..2210fec2 --- /dev/null +++ b/Kernel/tools/bankld/lkrel.c @@ -0,0 +1,156 @@ +/* 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 . */ + +/* + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#include + +#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, "")) + 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; +} diff --git a/Kernel/tools/bankld/lkrel.h b/Kernel/tools/bankld/lkrel.h new file mode 100644 index 00000000..ec846e85 --- /dev/null +++ b/Kernel/tools/bankld/lkrel.h @@ -0,0 +1,51 @@ +/* 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 . */ + +/* + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#ifndef __LKREL_H +#define __LKREL_H + +#include + +#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 */ diff --git a/Kernel/tools/bankld/lkrloc.c b/Kernel/tools/bankld/lkrloc.c new file mode 100644 index 00000000..30f01a7a --- /dev/null +++ b/Kernel/tools/bankld/lkrloc.c @@ -0,0 +1,414 @@ +/* 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 . + * + * + * 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 +#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); +} diff --git a/Kernel/tools/bankld/lkrloc3.c b/Kernel/tools/bankld/lkrloc3.c new file mode 100644 index 00000000..033057fb --- /dev/null +++ b/Kernel/tools/bankld/lkrloc3.c @@ -0,0 +1,1357 @@ +/* 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 . + * + * + * 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; ia_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[] = ""; + +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= 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 */ diff --git a/Kernel/tools/bankld/lks19.c b/Kernel/tools/bankld/lks19.c new file mode 100644 index 00000000..517fc2db --- /dev/null +++ b/Kernel/tools/bankld/lks19.c @@ -0,0 +1,226 @@ +/* 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 . */ + +#include +#include +#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> 8; + fprintf(ofp, "S1%02X%04X", reclen, rtadr0); + for (i=0; i. */ + +/* + * With contributions for the + * object libraries from + * Ken Hornstein + * kenh@cmf.nrl.navy.mil + * + */ + +/* + * Extensions: P. Felber + */ + +#include +#include + +#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 "" +#define SDCCLIB_MAGIC_LEN (sizeof ("") - 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, "")) + { + 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, "") ? 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, "")) + { + /*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, "")) + { + 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, "")) + { + return This; /* Finish, get out of here */ + } + break; + + case 2: + if (EQ (FLine, "")) + { + 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 and 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, "")) + state = 1; + break; + + case 1: + if (EQ (str, "")) + 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, "")) + { + /* 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, "")) + { + /* 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, "")) + { + /* Reached the end of the index. The symbol is not in this library. */ + return 0; + } + break; + + case 2: + if (EQ (FLine, "")) + { + /* 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, +}; diff --git a/Kernel/tools/bankld/lksdcdb.c b/Kernel/tools/bankld/lksdcdb.c new file mode 100644 index 00000000..b2f3b83d --- /dev/null +++ b/Kernel/tools/bankld/lksdcdb.c @@ -0,0 +1,179 @@ +/* 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 . + * + * + * 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 + diff --git a/Kernel/tools/bankld/lksym.c b/Kernel/tools/bankld/lksym.c new file mode 100644 index 00000000..e389f4e4 --- /dev/null +++ b/Kernel/tools/bankld/lksym.c @@ -0,0 +1,757 @@ +/* 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 . + * + * + * 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; is_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; ih_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 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. */ + +#ifndef _WIN32 +#include +#endif +#include +#include +#include +#include + +#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; +} diff --git a/Kernel/tools/bankld/sdld.h b/Kernel/tools/bankld/sdld.h new file mode 100644 index 00000000..9fdc6a61 --- /dev/null +++ b/Kernel/tools/bankld/sdld.h @@ -0,0 +1,44 @@ +/* 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 . */ + +#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 */