09185650b5bc7827f7a3d9c9a0b61baf1d4b374f
[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=1,
49   DSEG,
50   XSEG,
51   BSEG,
52   XINIT,
53   XISEG,
54   GSINIT,
55   GSFINAL,
56   HOME,
57   MAX_SEGMENTS
58 };
59
60 struct SEGMENT {
61   short id;
62   char *name;
63   int start;
64   int current;
65 } segments[MAX_SEGMENTS]={
66   {0,       "????",    0, 0},
67   {CSEG,    "CSEG",    0, 0},
68   {DSEG,    "DSEG",    0, 0},
69   {XSEG,    "XSEG",    0, 0},
70   {BSEG,    "BSEG",    0, 0},
71   {XINIT,   "XINIT",   0, 0},
72   {XISEG,   "XISEG",   0, 0},
73   {GSINIT,  "GSINIT",  0, 0},
74   {GSFINAL, "GSFINAL", 0, 0},
75   {HOME,    "HOME",    0, 0},
76 };
77
78 char *libPaths[128];
79 int nlibPaths=0;
80 char *libFiles[128];
81 int nlibFiles=0;
82
83 static char outFileName[PATH_MAX];
84
85 int currentArea=0;
86
87 int getAreaID(char *area) {
88   int i;
89   for (i=1; i<MAX_SEGMENTS; i++) {
90     if (strcmp(segments[i].name, area)==0) {
91       return segments[i].id;
92     }
93   }
94   return 0;
95 }
96
97 void addToRefs(char *ref) {
98   fprintf (stderr, "Ref: %s\n", ref);
99 }
100
101 void addToDefs(char *def, int address) {
102   fprintf (stderr, "Def: %s 0x%04x\n", def, address);
103 }
104
105 void syntaxError (char *err) {
106   fprintf (stderr, "error while parsing '%s'\n", err);
107   exit(1);
108 }
109
110 void baseName(char *name, char*base) {
111   int i, first, last;
112
113   // find the last path seperator in name
114   for (first=strlen(name)-1; 
115        (name[first]!='/' && name[first]!='\\') && first;
116        first--);
117   if (name[first]=='/' || name[first]=='\\') {
118     first++;
119   }
120
121   // find the last ext seperator in name
122   for (last=strlen(name)-1; 
123        (name[last]!='.' && last);
124        last--);
125   if (!last) {
126     last=strlen(name);
127   }
128
129   fprintf (stderr, "baseName: %s %d %d\n", name, first, last);
130   // fill the base with the baseName
131   for (i=first; i<last; i++) {
132     base[i-first]=name[i];
133   }
134   base[i]='\0';
135 }
136   
137 void readModule(char *module) {
138   double hisVersion;
139   char line[132];
140   FILE *relModule;
141   char moduleName[PATH_MAX];
142   int areas, globals;
143   int currentLine=1;
144
145   if ((relModule=fopen(module, "r"))==NULL) {
146     perror (module);
147     exit (1);
148   }
149   printf ("ReadModule: %s\n", module);
150
151   // first we need to check if this is a valid file
152   if (sscanf(fgets(line, 132, relModule), 
153              "SDCCXA rel, version %lf", &hisVersion)!=1) {
154     fprintf (stderr, "%s is not a valid input file\n", module);
155     exit (1);
156   }
157   if (hisVersion!=version) {
158     fprintf (stderr, "WARNING: version conflict; "
159              "we(%1.1f) != %s(%1.1f)\n", 
160              version, module, hisVersion);
161   }
162   currentLine++;
163   
164   // H 7 areas 168 global symbols
165   if (sscanf(fgets(line, 132, relModule),
166              "H %d areas %d global symbols",
167              &areas, &globals)!=2) {
168     syntaxError(line);
169   }
170   currentLine++;
171
172   // M module
173   if (sscanf(fgets(line, 132, relModule),
174              "M %s", moduleName)!=1) {
175     syntaxError(line);
176   }
177   fprintf (stderr, "module %s has %d area%s and %d globals\n",
178            moduleName, areas, areas==1?"":"s", globals);
179   currentLine++;
180
181   // now for the ASTR tags
182   while (fgets(line, 132, relModule)) {
183     switch (line[0]) 
184       {
185       case 'A': {
186         char area[32];
187         int size, flags;
188         if (sscanf(line, "A %[^ ] size %d flags %d",
189                    area, &size, &flags)!=3) {
190           fprintf (stderr, "%s:%d error in A record line\n", module, 
191                    currentLine);
192           exit (1);
193         }
194         // do we know this area?
195         if (!(currentArea=getAreaID(area))) {
196           fprintf (stderr, "%s:%d unknown area: %s\n", module,
197                    currentLine, area);
198           exit (1);
199         }
200         fprintf (stderr, "Area: %s size: %d\n", area, size);
201         // never mind about the size and flags for now
202         break;
203       }
204       case 'S': {
205         char symbol[132];
206         char refdef[132];
207         unsigned int address;
208         if (sscanf(line, "S %[^ ] %s", symbol, refdef)!=2) {
209           fprintf (stderr, "%s:%d syntax error near \"%s\"\n",
210                    module, currentLine, line);
211           exit (1);
212         }
213         if (strncmp(refdef, "Ref", 3)==0) {
214           addToRefs(symbol);
215         } else if (strncmp(refdef, "Def", 3)==0) {
216           sscanf (refdef, "Def%04x", &address);
217           addToDefs(symbol, address);
218         } else {
219           fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n", 
220                    module, currentLine, line);
221           exit (1);
222         }
223         break;
224       }
225       case 'T': {
226         unsigned int address;
227         unsigned int byte;
228         char *tline=NULL;
229         if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
230           fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
231           exit (1);
232         }
233         fprintf (stderr, "%04x:", address);
234         for ( ;
235               (tline=strtok(NULL, " \t\n")) && 
236                 (sscanf(tline, "%02x", &byte)==1);
237               fprintf (stderr, " %02x", byte))
238           ; // how about that one, hey?
239         fprintf (stderr, "\n");
240         break;
241       }
242       case 'R':
243         fprintf (stderr, "%s", line);
244         break;
245       default:
246         fprintf (stderr, "%s:%d unknown record \"%s\"\n",
247                  module, currentLine, line);
248         break;
249       }
250     currentLine++;
251   }
252   // that's all for now, thanks for watching */
253   fclose (relModule);
254 }
255
256 void writeModule() {
257   fprintf (stderr, "WriteModule: %s\n", outFileName);
258   // oops, forgot something :) */
259 }
260
261 void relocate() {
262 }
263
264 void usage (char * progName, int errNo) {
265   fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
266   if (errNo) {
267     exit (errNo);
268   }
269 }
270
271 int main(int argc, char **argv) {
272   FILE *linkCommandsFile;
273   char linkCommandsPath[PATH_MAX];
274   char linkCommand[PATH_MAX];
275
276   if (argc!=2) {
277     usage(argv[0], 1);
278   }
279
280   // read in the commands
281   sprintf (linkCommandsPath, "%s.lnk", argv[1]);
282   if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
283     perror(linkCommandsPath);
284     exit(1);
285   }
286   while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
287     linkCommand[strlen(linkCommand)-1]='\0';
288
289     // skip empty lines
290     if (!*linkCommand) {
291       continue;
292     }
293
294     puts (linkCommand);
295     if (*linkCommand=='-') {
296       switch (linkCommand[1]) 
297         {
298         case 'm':
299           // probably -muxi, ignore for now
300           break;
301         case 'e':
302           // -e, always in the last line, ignore for now
303           break;
304         case 'b': 
305           {
306             // a segment start address like: "-b XSEG = 0x4000"
307             int s;
308             char *seg=strtok(&linkCommand[3], " \t");
309             for (s=0; s<MAX_SEGMENTS; s++) {
310               if (strcmp(segments[s].name, seg)==0) {
311                 strtok(NULL, " \t"); // skip the '='
312                 if (sscanf(strtok(NULL, " \t"), "%x", 
313                            &segments[s].start)!=1) {
314                   syntaxError(linkCommand);
315                 }
316                 fprintf (stderr, "%s starts at 0x%04x\n", segments[s].name,
317                          segments[s].start);
318                 break;
319               }
320             }
321             if (s==MAX_SEGMENTS) {
322               syntaxError(linkCommand);
323             }
324           }
325           break;
326         case 'k':
327           // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
328           libPaths[nlibPaths++]=strdup(&linkCommand[3]);
329           break;
330         case 'l':
331           // a lib file like: "-l libsdcc"; one/line
332           libFiles[nlibFiles++]=strdup(&linkCommand[3]);
333           break;
334         default:
335           syntaxError(linkCommand);
336         }
337     } else {
338       // not a switch, must be an inputfile; one/line
339       readModule(linkCommand);
340     }
341   }
342   relocate();
343   writeModule();
344   return 0;
345 }
346