xa51, work in progress
[fw/sdcc] / as / xa51 / xa_link.c
1 /* WORK IN PROGRESS: do not watch this if you don't have the legal
2    age in your country to watch this.
3 */
4
5 /* This program is distributed in the hope that it will be useful,
6  * but WITHOUT ANY WARRANTY; without even the implied warranty of
7  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
8  * GNU General Public License for more details.
9
10  * You should have received a copy of the GNU General Public License
11  * along with this program; if not, write to the Free Software
12  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
13  */
14
15 /* This is a cheap hack. The xa51 has a couple of ways to scramble
16    relocation info into it's opcode that the standard linker can't
17    handle. 
18
19    The relocatable format looks like the known one, BUT ISN'T.
20
21    The only things that are handled now are:
22
23    "SDCCXA rel, version %f" must be the first line, sort of MAGIC word
24    "H %d areas %d global symbols" defines the # of areas and globals
25    "S <symbol> [Ref0000 | DefXXXX]" Def's are supposed to be defined in
26      their own area/segment
27    "A <seg> size %d flags %d" switch to another segment. this can happen
28      multiple times and should be equal. flags is ignored for now
29    "T xx xx bb bb ..." where xx xx is the address within the current segment
30      and bb are the bytes
31    "R xx <how> <symbol>" the relocation info. xx is the offset within the
32      previous "T .." line. <how> could be something like REL_FF, REL_FFFF, 
33      ABS_F0FF. symbol is the (previous) defined symbol it refers to
34
35    So, this is not a standalone linker. It will only link files generated
36    by xa_asm, which will only process files generated by the xa51 sdcc
37    port.
38 */
39
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <limits.h>
43 #include <string.h>
44
45 #include "xa_version.h"
46
47 enum {
48   CSEG=0,
49   DSEG,
50   XSEG,
51   BSEG,
52   MAX_SEGMENTS
53 };
54
55 struct SEGMENT {
56   short id;
57   char *name;
58   int start;
59   int current;
60 } segments[MAX_SEGMENTS]={
61   {CSEG, "CSEG", 0, 0},
62   {DSEG, "DSEG", 0, 0},
63   {XSEG, "XSEG", 0, 0},
64   {BSEG, "BSEG", 0, 0}
65 };
66
67 char *libPaths[128];
68 int nlibPaths=0;
69 char *libFiles[128];
70 int nlibFiles=0;
71
72 static char outFileName[PATH_MAX];
73
74 void syntaxError (char *err) {
75   fprintf (stderr, "error while parsing '%s'\n", err);
76   exit(1);
77 }
78
79 void baseName(char *name, char*base) {
80   int i, first, last;
81
82   // find the last path seperator in name
83   for (first=strlen(name)-1; 
84        (name[first]!='/' && name[first]!='\\') && first;
85        first--);
86   if (name[first]=='/' || name[first]=='\\') {
87     first++;
88   }
89
90   // find the last ext seperator in name
91   for (last=strlen(name)-1; 
92        (name[last]!='.' && last);
93        last--);
94   if (!last) {
95     last=strlen(name);
96   }
97
98   fprintf (stderr, "baseName: %s %d %d\n", name, first, last);
99   // fill the base with the baseName
100   for (i=first; i<last; i++) {
101     base[i-first]=name[i];
102   }
103   base[i]='\0';
104 }
105   
106 void readModule(char *module) {
107   double hisVersion;
108   char line[132];
109   FILE *relModule;
110
111   if ((relModule=fopen(module, "r"))==NULL) {
112     perror (module);
113     exit (1);
114   }
115   printf ("ReadModule: %s\n", module);
116
117   // first we need to check if this is a valid file
118   if (sscanf(fgets(line, 132, relModule), 
119       "SDCCXA rel, version %lf", &hisVersion)!=1) {
120     fprintf (stderr, "%s is not a valid input file\n", module);
121     exit (1);
122   }
123   if (hisVersion!=version) {
124     fprintf (stderr, "WARNING: version conflict; "
125              "we(%1.1f) != %s(%1.1f)\n", 
126              version, module, hisVersion);
127   }
128
129   // 
130   fprintf (stderr, "Wow! This seems a nice module: v %1.1f.\n", hisVersion);
131   // that's all for now, thanks for watching */
132   fclose (relModule);
133 }
134
135 void writeModule() {
136   fprintf (stderr, "WriteModule: %s\n", outFileName);
137   // oops, forgot something :) */
138 }
139
140 void relocate() {
141 }
142
143 void usage (char * progName, int errNo) {
144   fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
145   if (errNo) {
146     exit (errNo);
147   }
148 }
149
150 int main(int argc, char **argv) {
151   FILE *linkCommandsFile;
152   char linkCommandsPath[PATH_MAX];
153   char linkCommand[PATH_MAX];
154
155   if (argc!=2) {
156     usage(argv[0], 1);
157   }
158
159   // read in the commands
160   sprintf (linkCommandsPath, "%s.lnk", argv[1]);
161   if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
162     perror(linkCommandsPath);
163     exit(1);
164   }
165   while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
166     linkCommand[strlen(linkCommand)-1]='\0';
167
168     // skip empty lines
169     if (!*linkCommand) {
170       continue;
171     }
172
173     puts (linkCommand);
174     if (*linkCommand=='-') {
175       switch (linkCommand[1]) 
176         {
177         case 'm':
178           // probably -muxi, ignore for now
179           break;
180         case 'e':
181           // -e, always in the last line, ignore for now
182           break;
183         case 'b': 
184           {
185             // a segment start address like: "-b XSEG = 0x4000"
186             int s;
187             char *seg=strtok(&linkCommand[3], " \t");
188             for (s=0; s<MAX_SEGMENTS; s++) {
189               if (strcmp(segments[s].name, seg)==0) {
190                 strtok(NULL, " \t"); // skip the '='
191                 if (sscanf(strtok(NULL, " \t"), "%x", 
192                            &segments[s].start)!=1) {
193                   syntaxError(linkCommand);
194                 }
195                 break;
196               }
197             }
198             if (s==MAX_SEGMENTS) {
199               syntaxError(linkCommand);
200             }
201           }
202           break;
203         case 'k':
204           // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
205           libPaths[nlibPaths++]=strdup(&linkCommand[3]);
206           break;
207         case 'l':
208           // a lib file like: "-l libsdcc"; one/line
209           libFiles[nlibFiles++]=strdup(&linkCommand[3]);
210           break;
211         default:
212           syntaxError(linkCommand);
213         }
214     } else {
215       // not a switch, must be an inputfile; one/line
216       readModule(linkCommand);
217     }
218   }
219   relocate();
220   writeModule();
221   return 0;
222 }
223