1 /* WORK IN PROGRESS: do not watch this if you don't have the legal
2 age in your country to watch this.
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.
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
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
19 The relocatable format looks like the known one, BUT ISN'T.
21 The only things that are handled now are:
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
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
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
45 #include "xa_version.h"
65 } segments[MAX_SEGMENTS]={
71 {XINIT, "XINIT", 0, 0},
72 {XISEG, "XISEG", 0, 0},
73 {GSINIT, "GSINIT", 0, 0},
74 {GSFINAL, "GSFINAL", 0, 0},
83 static char outFileName[PATH_MAX];
87 int getAreaID(char *area) {
89 for (i=1; i<MAX_SEGMENTS; i++) {
90 if (strcmp(segments[i].name, area)==0) {
91 return segments[i].id;
97 void addToRefs(char *ref) {
98 fprintf (stderr, "Ref: %s\n", ref);
101 void addToDefs(char *def, int address) {
102 fprintf (stderr, "Def: %s 0x%04x\n", def, address);
105 void syntaxError (char *err) {
106 fprintf (stderr, "error while parsing '%s'\n", err);
110 void baseName(char *name, char*base) {
113 // find the last path seperator in name
114 for (first=strlen(name)-1;
115 (name[first]!='/' && name[first]!='\\') && first;
117 if (name[first]=='/' || name[first]=='\\') {
121 // find the last ext seperator in name
122 for (last=strlen(name)-1;
123 (name[last]!='.' && last);
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];
137 void readModule(char *module) {
141 char moduleName[PATH_MAX];
145 if ((relModule=fopen(module, "r"))==NULL) {
149 printf ("ReadModule: %s\n", module);
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);
157 if (hisVersion!=version) {
158 fprintf (stderr, "WARNING: version conflict; "
159 "we(%1.1f) != %s(%1.1f)\n",
160 version, module, hisVersion);
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) {
173 if (sscanf(fgets(line, 132, relModule),
174 "M %s", moduleName)!=1) {
177 fprintf (stderr, "module %s has %d area%s and %d globals\n",
178 moduleName, areas, areas==1?"":"s", globals);
181 // now for the ASTR tags
182 while (fgets(line, 132, relModule)) {
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,
194 // do we know this area?
195 if (!(currentArea=getAreaID(area))) {
196 fprintf (stderr, "%s:%d unknown area: %s\n", module,
200 fprintf (stderr, "Area: %s size: %d\n", area, size);
201 // never mind about the size and flags for now
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);
213 if (strncmp(refdef, "Ref", 3)==0) {
215 } else if (strncmp(refdef, "Def", 3)==0) {
216 sscanf (refdef, "Def%04x", &address);
217 addToDefs(symbol, address);
219 fprintf (stderr, "%s:%d found invalid symbol definition \"%s\"\n",
220 module, currentLine, line);
226 unsigned int address;
229 if (sscanf(strtok(&line[2], " "), "%04x", &address)!=1) {
230 fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
233 fprintf (stderr, "%04x:", address);
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");
243 fprintf (stderr, "%s", line);
246 fprintf (stderr, "%s:%d unknown record \"%s\"\n",
247 module, currentLine, line);
252 // that's all for now, thanks for watching */
257 fprintf (stderr, "WriteModule: %s\n", outFileName);
258 // oops, forgot something :) */
264 void usage (char * progName, int errNo) {
265 fprintf (stderr, "usage: %s lnkCmdFile\n", progName);
271 int main(int argc, char **argv) {
272 FILE *linkCommandsFile;
273 char linkCommandsPath[PATH_MAX];
274 char linkCommand[PATH_MAX];
280 // read in the commands
281 sprintf (linkCommandsPath, "%s.lnk", argv[1]);
282 if (!(linkCommandsFile=fopen(linkCommandsPath, "r"))) {
283 perror(linkCommandsPath);
286 while (fgets(linkCommand, PATH_MAX, linkCommandsFile)) {
287 linkCommand[strlen(linkCommand)-1]='\0';
295 if (*linkCommand=='-') {
296 switch (linkCommand[1])
299 // probably -muxi, ignore for now
302 // -e, always in the last line, ignore for now
306 // a segment start address like: "-b XSEG = 0x4000"
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);
316 fprintf (stderr, "%s starts at 0x%04x\n", segments[s].name,
321 if (s==MAX_SEGMENTS) {
322 syntaxError(linkCommand);
327 // a lib path like: "-k /usr/local/share/sdcc/lib/xa51"; one/line
328 libPaths[nlibPaths++]=strdup(&linkCommand[3]);
331 // a lib file like: "-l libsdcc"; one/line
332 libFiles[nlibFiles++]=strdup(&linkCommand[3]);
335 syntaxError(linkCommand);
338 // not a switch, must be an inputfile; one/line
339 readModule(linkCommand);