1 /* ld.c - linker for Introl format (6809 C) object files 6809/8086/80386 */
2 
3 /* Copyright (C) 1994 Bruce Evans */
4 
5 #include "syshead.h"
6 #include "const.h"
7 #include "byteord.h"
8 #include "type.h"
9 #include "globvar.h"
10 
11 #define MAX_LIBS	(NR_STDLIBS + 5)
12 #ifdef MC6809
13 #define NR_STDLIBS	1
14 #else
15 #define NR_STDLIBS	0
16 #endif
17 
18 PUBLIC bin_off_t text_base_value = 0;	/* XXX */
19 PUBLIC bin_off_t data_base_value = 0;	/* XXX */
20 PUBLIC bin_off_t heap_top_value  = 0;	/* XXX */
21 PUBLIC int headerless = 0;
22 #ifndef VERY_SMALL_MEMORY
23 PUBLIC int v7 = 0;
24 #endif
25 #ifndef MSDOS
26 PUBLIC int cpm86 = 0;
27 #endif
28 PUBLIC char hexdigit[] = "0123456789abcdef";
29 
30 PRIVATE bool_t flag[128];
31 PRIVATE char *libs[MAX_LIBS] = {
32 #ifdef MC6809
33     "/usr/local/lib/m09/",
34 #endif
35     0
36 };
37 PRIVATE int lastlib = NR_STDLIBS;
38 
39 FORWARD char *buildname P((char *pre, char *mid, char *suf));
40 FORWARD char *expandlib P((char *fn));
41 
buildname(pre,mid,suf)42 PRIVATE char *buildname(pre, mid, suf)
43 char *pre;
44 char *mid;
45 char *suf;
46 {
47     char *name;
48 
49     name = ourmalloc(strlen(pre) + strlen(mid) + strlen(suf) + 1);
50     strcpy(name, pre);
51     strcat(name, mid);
52     strcat(name, suf);
53     return name;
54 }
55 
expandlib(fn)56 PRIVATE char *expandlib(fn)
57 char *fn;
58 {
59     char *path, *s;
60     int i;
61 
62     for (i = lastlib - 1; i >= 0; --i)
63     {
64 	path = ourmalloc(strlen(libs[i]) + strlen(fn) + 2);
65 	strcpy(path, libs[i]);
66 	s = path + strlen(path);
67 	if (s!=path && s[-1] != '/') strcat(path, "/");
68 	strcat(path, fn);
69 	if (access(path, R_OK) == 0)
70 	    return path;
71 	ourfree(path);
72     }
73     return NUL_PTR;
74 }
75 
main(argc,argv)76 PUBLIC int main(argc, argv)
77 int argc;
78 char **argv;
79 {
80     register char *arg;
81     int argn;
82     static char crtprefix[] = "crt";
83     static char crtsuffix[] = ".o";
84     char *infilename;
85     static char libprefix[] = "lib";
86     static char libsuffix[] = ".a";
87     char *outfilename;
88     char *tfn;
89     int icount=0;
90 
91     ioinit(argv[0]);
92     objinit();
93     syminit();
94     typeconv_init(INT_BIG_ENDIAN, LONG_BIG_ENDIAN);
95 #ifndef MC6809
96     flag['3'] = sizeof(char *) >= 4;
97 #endif
98     outfilename = NUL_PTR;
99     for (argn = 1; argn < argc; ++argn)
100     {
101 	arg = argv[argn];
102 	if (*arg != '-')
103 	{
104 	    readsyms(arg, flag['t']);
105 	    icount++;
106 	}
107 	else
108 	    switch (arg[1])
109 	    {
110 	    case 'v':
111 	       version_msg();
112 	    case 'r':		/* relocatable output */
113 	    case 't':		/* trace modules linked */
114 	       if (icount > 0) usage();
115 #ifdef REL_OUTPUT
116 	    case 'B':		/* Broken -r for dosemu. */
117 #endif
118 	    case '0':		/* use 16-bit libraries */
119 	    case '3':		/* use 32-bit libraries */
120 	    case 'M':		/* print symbols linked */
121 	    case 'i':		/* separate I & D output */
122 	    case 'm':		/* print modules linked */
123 	    case 's':		/* strip symbols */
124 	    case 'z':		/* unmapped zero page */
125 	    case 'N':		/* Native format a.out */
126 	    case 'd':		/* Make a headerless outfile */
127 #ifndef MSDOS
128 	    case 'c':		/* Write header in CP/M-86 format */
129 #endif
130 	    case 'y':		/* Use a newer symbol table */
131 #ifndef VERY_SMALL_MEMORY
132 	    case '7':		/* Produce a UNIX v7 a.out header */
133 #endif
134 		if (arg[2] == 0)
135 		    flag[(int) arg[1]] = TRUE;
136 		else if (arg[2] == '-' && arg[3] == 0)
137 		    flag[(int) arg[1]] = FALSE;
138 		else
139 		    usage();
140 		if (arg[1] == '0')	/* flag 0 is negative logic flag 3 */
141 		    flag['3'] = !flag['0'];
142 		break;
143 	    case 'C':		/* startfile name */
144 		tfn = buildname(crtprefix, arg + 2, crtsuffix);
145 		if ((infilename = expandlib(tfn)) == NUL_PTR)
146 		    infilename = tfn;
147 		    /*fatalerror(tfn);	* XXX - need to describe failure */
148 		readsyms(infilename, flag['t']);
149 		icount++;
150 		break;
151 	    case 'L':		/* library path */
152 		if (lastlib < MAX_LIBS)
153 		    libs[lastlib++] = arg + 2;
154 		else
155 		    fatalerror("too many library paths");
156 		break;
157 	    case 'O':		/* library file name */
158 		if ((infilename = expandlib(arg + 2)) == NUL_PTR)
159 		    infilename = arg+2;
160 		    /* fatalerror(arg);	* XXX */
161 		readsyms(infilename, flag['t']);
162 		break;
163 	    case 'T':		/* text base address */
164 		if (arg[2] == 0 && ++argn >= argc)
165 		    usage();
166 		errno = 0;
167 		if (arg[2] == 0 )
168 		   text_base_value = strtoul(argv[argn], (char **)0, 16);
169 		else
170 		   text_base_value = strtoul(arg+2, (char **)0, 16);
171 		if (errno != 0)
172 		    use_error("invalid text address");
173 		break;
174 	    case 'D':		/* data base address */
175 		if (arg[2] == 0 && ++argn >= argc)
176 		    usage();
177 		errno = 0;
178 		if (arg[2] == 0 )
179 		   data_base_value = strtoul(argv[argn], (char **)0, 16);
180 		else
181 		   data_base_value = strtoul(arg+2, (char **)0, 16);
182 		if (errno != 0)
183 		    use_error("invalid data address");
184 		break;
185 	    case 'H':		/* heap top address */
186 		if (arg[2] == 0 && ++argn >= argc)
187 		    usage();
188 		errno = 0;
189 		if (arg[2] == 0 )
190 		   heap_top_value = strtoul(argv[argn], (char **)0, 16);
191 		else
192 		   heap_top_value = strtoul(arg+2, (char **)0, 16);
193 		if (errno != 0)
194 		    use_error("invalid heap top");
195 		break;
196 	    case 'l':		/* library name */
197 		tfn = buildname(libprefix, arg + 2, libsuffix);
198 		if ((infilename = expandlib(tfn)) == NUL_PTR)
199 		    infilename = tfn;
200 		    /* fatalerror(tfn);	* XXX */
201 		readsyms(infilename, flag['t']);
202 		icount+=2;
203 		break;
204 	    case 'o':		/* output file name */
205 		if (arg[2] != 0 || ++argn >= argc || outfilename != NUL_PTR)
206 		    usage();
207 		outfilename = argv[argn];
208 		break;
209 	    default:
210 		usage();
211 	    }
212     }
213     if(icount==0) usage();
214 
215 #ifdef BUGCOMPAT
216     if( icount==1 && ( flag['r'] && !flag['N'] ) ) {
217        flag['r'] = 0;
218        flag['B'] = 1;
219     }
220 #endif
221 
222 #ifdef REL_OUTPUT
223 #ifndef MSDOS
224     if( flag['r'] && !flag['N'] )
225     {
226        /* Do a relocatable link -- actually fake it with 'ar.c' */
227        ld86r(argc, argv);
228     }
229 #endif
230 #endif
231 
232 #ifdef MSDOS
233     /* MSDOS Native is special, we make a COM file */
234     if( flag['N'] )
235     {
236        flag['N'] = 0;
237        flag['d'] = 1;
238        text_base_value = 0x100;
239     }
240 #endif
241 
242     /* Headerless executables can't use symbols. */
243     headerless = flag['d'];
244     if( headerless ) flag['s'] = 1;
245 
246 #ifndef VERY_SMALL_MEMORY
247     /* UNIX seventh edition executables */
248     v7 = flag['7'];
249 #endif
250 
251 #ifndef MSDOS
252     /* CP/M-86 executables can't use symbols. */
253     cpm86 = flag['c'];
254     if ( cpm86 ) flag['s'] = 1;
255 #endif
256 
257     linksyms(flag['r'] | flag['B']);
258     if (outfilename == NUL_PTR)
259 	outfilename = "a.out";
260 #ifndef MSDOS
261     if( flag['N'] )
262        writebin(outfilename, flag['i'], flag['3'], flag['s'],
263 	     flag['z'] & flag['3']);
264     else
265 #endif
266     if( flag['B'] )
267        write_dosemu(outfilename, flag['i'], flag['3'], flag['s'],
268 	  flag['z'] & flag['3']);
269     else
270        write_elks(outfilename, flag['i'], flag['3'], flag['s'],
271 	     flag['z'], flag['y']);
272     if (flag['m'])
273 	dumpmods();
274     if (flag['M'])
275 	dumpsyms();
276     flusherr();
277     return errcount ? 1 : 0;
278 }
279