Commit | Line | Data |
---|---|---|
c618de01 SC |
1 | /* BFD library support routines for architectures. |
2 | Copyright (C) 1990-1991 Free Software Foundation, Inc. | |
3 | Hacked by John Gilmore of Cygnus Support. | |
4a81b561 | 4 | |
c618de01 | 5 | This file is part of BFD, the Binary File Descriptor library. |
4a81b561 | 6 | |
c618de01 | 7 | This program is free software; you can redistribute it and/or modify |
4a81b561 | 8 | it under the terms of the GNU General Public License as published by |
c618de01 SC |
9 | the Free Software Foundation; either version 2 of the License, or |
10 | (at your option) any later version. | |
4a81b561 | 11 | |
c618de01 | 12 | This program is distributed in the hope that it will be useful, |
4a81b561 DHW |
13 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
15 | GNU General Public License for more details. | |
16 | ||
17 | You should have received a copy of the GNU General Public License | |
c618de01 SC |
18 | along with this program; if not, write to the Free Software |
19 | Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ | |
20 | ||
21 | /*doc* | |
22 | @section Architectures | |
23 | BFD's idea of an architecture is implimented in @code{archures.c}. BFD | |
6724ff46 | 24 | keeps two atoms in a BFD describing the architecture of the data |
188d6d22 | 25 | attached to the BFD, the @code{enum bfd_architecture arch} field and |
c618de01 SC |
26 | the @code{unsigned long machine} field. |
27 | */ | |
28 | ||
29 | /*proto* bfd_architecture | |
30 | This enum gives the object file's CPU | |
31 | architecture, in a global sense. E.g. what processor family does it | |
32 | belong to? There is another field, which indicates what processor | |
33 | within the family is in use. The machine gives a number which | |
34 | distingushes different versions of the architecture, containing for | |
35 | example 2 and 3 for Intel i960 KA and i960 KB, and 68020 and 68030 for | |
36 | Motorola 68020 and 68030. | |
37 | ||
38 | *+ | |
39 | enum bfd_architecture | |
40 | { | |
41 | bfd_arch_unknown, {* File arch not known *} | |
42 | bfd_arch_obscure, {* Arch known, not one of these *} | |
43 | bfd_arch_m68k, {* Motorola 68xxx *} | |
44 | bfd_arch_vax, {* DEC Vax *} | |
45 | bfd_arch_i960, {* Intel 960 *} | |
46 | {* The order of the following is important. | |
47 | lower number indicates a machine type that | |
48 | only accepts a subset of the instructions | |
49 | available to machines with higher numbers. | |
50 | The exception is the "ca", which is | |
51 | incompatible with all other machines except | |
52 | "core". *} | |
53 | ||
54 | #define bfd_mach_i960_core 1 | |
55 | #define bfd_mach_i960_ka_sa 2 | |
56 | #define bfd_mach_i960_kb_sb 3 | |
57 | #define bfd_mach_i960_mc 4 | |
58 | #define bfd_mach_i960_xa 5 | |
59 | #define bfd_mach_i960_ca 6 | |
60 | ||
61 | bfd_arch_a29k, {* AMD 29000 *} | |
62 | bfd_arch_sparc, {* SPARC *} | |
63 | bfd_arch_mips, {* MIPS Rxxxx *} | |
64 | bfd_arch_i386, {* Intel 386 *} | |
65 | bfd_arch_ns32k, {* National Semiconductor 32xxx *} | |
66 | bfd_arch_tahoe, {* CCI/Harris Tahoe *} | |
67 | bfd_arch_i860, {* Intel 860 *} | |
68 | bfd_arch_romp, {* IBM ROMP RS/6000 *} | |
69 | bfd_arch_alliant, {* Alliant *} | |
70 | bfd_arch_convex, {* Convex *} | |
71 | bfd_arch_m88k, {* Motorola 88xxx *} | |
72 | bfd_arch_pyramid, {* Pyramid Technology *} | |
73 | bfd_arch_h8_300, {* Hitachi H8/300 *} | |
74 | bfd_arch_last | |
75 | }; | |
76 | *- | |
77 | ||
78 | stuff | |
79 | ||
80 | */ | |
81 | ||
82 | ||
4a81b561 DHW |
83 | |
84 | /* $Id$ */ | |
85 | ||
c618de01 | 86 | #include <sysdep.h> |
4a81b561 | 87 | #include "bfd.h" |
4a81b561 DHW |
88 | |
89 | static char *prt_num_mach (); | |
90 | static boolean scan_num_mach (); | |
91 | static char *prt_960_mach (); | |
92 | static boolean scan_960_mach (); | |
93 | ||
94 | struct arch_print { | |
c618de01 SC |
95 | enum bfd_architecture arch; |
96 | char *astr; | |
97 | char *(*mach_print)(); | |
98 | boolean (*mach_scan)(); | |
4a81b561 DHW |
99 | } arch_print[] = { |
100 | ||
c618de01 SC |
101 | {bfd_arch_unknown, "unknown", prt_num_mach, scan_num_mach}, |
102 | {bfd_arch_obscure, "obscure", prt_num_mach, scan_num_mach}, | |
103 | {bfd_arch_m68k, "m68k", prt_num_mach, scan_num_mach}, | |
104 | {bfd_arch_vax, "vax", prt_num_mach, scan_num_mach}, | |
105 | {bfd_arch_i960, "i960", prt_960_mach, scan_960_mach}, | |
106 | {bfd_arch_a29k, "a29k", prt_num_mach, scan_num_mach}, | |
107 | {bfd_arch_sparc, "sparc", prt_num_mach, scan_num_mach}, | |
108 | {bfd_arch_mips, "mips", prt_num_mach, scan_num_mach}, | |
109 | {bfd_arch_i386, "i386", prt_num_mach, scan_num_mach}, | |
110 | {bfd_arch_ns32k, "ns32k", prt_num_mach, scan_num_mach}, | |
111 | {bfd_arch_tahoe, "tahoe", prt_num_mach, scan_num_mach}, | |
112 | {bfd_arch_i860, "i860", prt_num_mach, scan_num_mach}, | |
113 | {bfd_arch_romp, "romp", prt_num_mach, scan_num_mach}, | |
114 | {bfd_arch_alliant, "alliant", prt_num_mach, scan_num_mach}, | |
115 | {bfd_arch_convex, "convex", prt_num_mach, scan_num_mach}, | |
116 | {bfd_arch_m88k, "m88k", prt_num_mach, scan_num_mach}, | |
117 | {bfd_arch_pyramid, "pyramid", prt_num_mach, scan_num_mach}, | |
118 | {bfd_arch_h8_300, "H8/300", prt_num_mach, scan_num_mach}, | |
119 | {bfd_arch_unknown, (char *)0, prt_num_mach, scan_num_mach}, | |
4a81b561 DHW |
120 | }; |
121 | ||
c618de01 SC |
122 | /*proto* bfd_prinable_arch_mach |
123 | Return a printable string representing the architecture and machine | |
124 | type. The result is only good until the next call to | |
6724ff46 | 125 | @code{bfd_printable_arch_mach}. |
c618de01 SC |
126 | *; PROTO(CONST char *,bfd_printable_arch_mach, |
127 | (enum bfd_architecture arch, unsigned long machine)); | |
128 | */ | |
129 | ||
130 | CONST char * | |
131 | DEFUN(bfd_printable_arch_mach,(arch, machine), | |
132 | enum bfd_architecture arch AND | |
133 | unsigned long machine) | |
4a81b561 DHW |
134 | { |
135 | struct arch_print *ap; | |
136 | ||
137 | for (ap = arch_print; ap->astr; ap++) { | |
138 | if (ap->arch == arch) { | |
139 | if (machine == 0) | |
c618de01 | 140 | return ap->astr; |
4a81b561 DHW |
141 | return (*ap->mach_print)(ap, machine); |
142 | } | |
143 | } | |
144 | return "UNKNOWN!"; | |
145 | } | |
146 | ||
147 | static char * | |
148 | prt_num_mach (ap, machine) | |
149 | struct arch_print *ap; | |
150 | unsigned long machine; | |
151 | { | |
152 | static char result[20]; | |
153 | ||
154 | sprintf(result, "%s:%ld", ap->astr, (long) machine); | |
155 | return result; | |
156 | } | |
157 | ||
c618de01 SC |
158 | /*proto* |
159 | *i bfd_scan_arch_mach | |
160 | Scan a string and attempt to turn it into an archive and machine type combination. | |
161 | *; PROTO(boolean, bfd_scan_arch_mach, | |
162 | (CONST char *, enum bfd_architecture *, unsigned long *)); | |
163 | */ | |
4a81b561 DHW |
164 | |
165 | boolean | |
4cddd1c9 SC |
166 | DEFUN(bfd_scan_arch_mach,(string, archp, machinep), |
167 | CONST char *string AND | |
168 | enum bfd_architecture *archp AND | |
169 | unsigned long *machinep) | |
4a81b561 DHW |
170 | { |
171 | struct arch_print *ap; | |
172 | int len; | |
173 | ||
174 | /* First look for an architecture, possibly followed by machtype. */ | |
175 | for (ap = arch_print; ap->astr; ap++) { | |
176 | if (ap->astr[0] != string[0]) | |
177 | continue; | |
178 | len = strlen (ap->astr); | |
179 | if (!strncmp (ap->astr, string, len)) { | |
180 | /* We found the architecture, now see about the machine type */ | |
181 | if (archp) | |
c618de01 | 182 | *archp = ap->arch; |
4a81b561 | 183 | if (string[len] != '\0') { |
c618de01 SC |
184 | if (ap->mach_scan (string+len, ap, archp, machinep, 1)) |
185 | return true; | |
4a81b561 DHW |
186 | } |
187 | if (machinep) | |
c618de01 | 188 | *machinep = 0; |
4a81b561 DHW |
189 | return true; |
190 | } | |
191 | } | |
192 | ||
193 | /* Couldn't find an architecture -- try for just a machine type */ | |
194 | for (ap = arch_print; ap->astr; ap++) { | |
195 | if (ap->mach_scan (string, ap, archp, machinep, 0)) | |
196 | return true; | |
197 | } | |
198 | ||
199 | return false; | |
200 | } | |
201 | ||
202 | static boolean | |
203 | scan_num_mach (string, ap, archp, machinep, archspec) | |
204 | char *string; | |
205 | struct arch_print *ap; | |
206 | enum bfd_architecture *archp; | |
207 | unsigned long *machinep; | |
208 | int archspec; | |
209 | { | |
210 | enum bfd_architecture arch; | |
211 | unsigned long machine; | |
212 | char achar; | |
213 | ||
214 | if (archspec) { | |
215 | ||
216 | /* Architecture already specified, now go for machine type. */ | |
217 | if (string[0] != ':') | |
218 | return false; | |
219 | /* We'll take any valid number that occupies the entire string */ | |
220 | if (1 != sscanf (string+1, "%lu%c", &machine, &achar)) | |
221 | return false; | |
222 | arch = ap->arch; | |
223 | ||
224 | } else { | |
225 | ||
226 | /* We couldn't identify an architecture prefix. Perhaps the entire | |
227 | thing is a machine type. Be a lot picker. */ | |
228 | if (1 != sscanf (string, "%lu%c", &machine, &achar)) | |
229 | return false; | |
230 | switch (machine) { | |
231 | case 68010: | |
232 | case 68020: | |
233 | case 68030: | |
234 | case 68040: | |
235 | case 68332: | |
c618de01 SC |
236 | case 68050: arch = bfd_arch_m68k; break; |
237 | case 68000: arch = bfd_arch_m68k; machine = 0; break; | |
4a81b561 DHW |
238 | |
239 | case 80960: | |
c618de01 | 240 | case 960: arch = bfd_arch_i960; machine = 0; break; |
4a81b561 DHW |
241 | |
242 | case 386: | |
c618de01 SC |
243 | case 80386: arch = bfd_arch_i386; machine = 0; break; |
244 | case 486: arch = bfd_arch_i386; break; | |
4a81b561 | 245 | |
c618de01 | 246 | case 29000: arch = bfd_arch_a29k; machine = 0; break; |
4a81b561 DHW |
247 | |
248 | case 32016: | |
249 | case 32032: | |
250 | case 32132: | |
251 | case 32232: | |
252 | case 32332: | |
253 | case 32432: | |
c618de01 SC |
254 | case 32532: arch = bfd_arch_ns32k; break; |
255 | case 32000: arch = bfd_arch_ns32k; machine = 0; break; | |
4a81b561 DHW |
256 | |
257 | case 860: | |
c618de01 | 258 | case 80860: arch = bfd_arch_i860; machine = 0; break; |
4a81b561 | 259 | |
c618de01 | 260 | default: return false; |
4a81b561 DHW |
261 | } |
262 | } | |
263 | ||
264 | if (archp) | |
265 | *archp = arch; | |
266 | if (machinep) | |
267 | *machinep = machine; | |
268 | return true; | |
269 | } | |
270 | \f | |
271 | /* Intel 960 machine variants. */ | |
272 | ||
273 | static char * | |
274 | prt_960_mach (ap, machine) | |
275 | struct arch_print *ap; | |
276 | unsigned long machine; | |
277 | { | |
278 | static char result[20]; | |
279 | char *str; | |
280 | ||
281 | switch (machine) { | |
c618de01 SC |
282 | case bfd_mach_i960_core: str = "core"; break; |
283 | case bfd_mach_i960_kb_sb: str = "kb"; break; | |
284 | case bfd_mach_i960_mc: str = "mc"; break; | |
285 | case bfd_mach_i960_xa: str = "xa"; break; | |
286 | case bfd_mach_i960_ca: str = "ca"; break; | |
287 | case bfd_mach_i960_ka_sa: str = "ka"; break; | |
4a81b561 | 288 | default: |
c618de01 | 289 | return prt_num_mach (ap, machine); |
4a81b561 DHW |
290 | } |
291 | sprintf (result, "%s:%s", ap->astr, str); | |
292 | return result; | |
293 | } | |
294 | ||
295 | static boolean | |
296 | scan_960_mach (string, ap, archp, machinep, archspec) | |
297 | char *string; | |
298 | struct arch_print *ap; | |
299 | enum bfd_architecture *archp; | |
300 | unsigned long *machinep; | |
301 | int archspec; | |
302 | { | |
303 | unsigned long machine; | |
304 | ||
305 | if (!archspec) | |
306 | return false; | |
307 | if (string[0] != ':') | |
308 | return false; | |
309 | string++; | |
310 | if (string[0] == '\0') | |
311 | return false; | |
312 | if (string[0] == 'c' && string[1] == 'o' && string[2] == 'r' && | |
313 | string[3] == 'e' && string[4] == '\0') | |
314 | machine = bfd_mach_i960_core; | |
c618de01 | 315 | else if (string[1] == '\0' || string[2] != '\0') /* rest are 2-char */ |
4a81b561 DHW |
316 | return false; |
317 | else if (string[0] == 'k' && string[1] == 'b') | |
318 | machine = bfd_mach_i960_kb_sb; | |
319 | else if (string[0] == 's' && string[1] == 'b') | |
320 | machine = bfd_mach_i960_kb_sb; | |
321 | else if (string[0] == 'm' && string[1] == 'c') | |
322 | machine = bfd_mach_i960_mc; | |
323 | else if (string[0] == 'x' && string[1] == 'a') | |
324 | machine = bfd_mach_i960_xa; | |
325 | else if (string[0] == 'c' && string[1] == 'a') | |
326 | machine = bfd_mach_i960_ca; | |
327 | else if (string[0] == 'k' && string[1] == 'a') | |
328 | machine = bfd_mach_i960_ka_sa; | |
329 | else if (string[0] == 's' && string[1] == 'a') | |
330 | machine = bfd_mach_i960_ka_sa; | |
331 | else | |
332 | return false; | |
333 | ||
334 | if (archp) | |
335 | *archp = ap->arch; | |
336 | if (machinep) | |
337 | *machinep = machine; | |
338 | return true; | |
339 | } | |
340 | ||
341 | ||
342 | \f | |
c618de01 SC |
343 | /*proto* |
344 | *i bfd_arch_compatible | |
345 | This routine is used to determine whether two BFDs' architectures and machine types are | |
346 | compatible. It calculates the lowest common denominator between the | |
6724ff46 | 347 | two architectures and machine types implied by the BFDs and sets the |
c618de01 SC |
348 | objects pointed at by @var{archp} and @var{machine} if non NULL. |
349 | ||
6724ff46 | 350 | This routine returns @code{true} if the BFDs are of compatible type, |
c618de01 SC |
351 | otherwise @code{false}. |
352 | *; PROTO(boolean, bfd_arch_compatible, | |
353 | (bfd *abfd, | |
354 | bfd *bbfd, | |
355 | enum bfd_architecture *archp, | |
356 | unsigned long *machinep)); | |
357 | *-*/ | |
4a81b561 DHW |
358 | |
359 | boolean | |
c618de01 SC |
360 | DEFUN(bfd_arch_compatible,(abfd, bbfd, archp, machinep), |
361 | bfd *abfd AND | |
362 | bfd *bbfd AND | |
363 | enum bfd_architecture *archp AND | |
364 | unsigned long *machinep) | |
4a81b561 DHW |
365 | { |
366 | enum bfd_architecture archa, archb; | |
367 | unsigned long macha, machb; | |
368 | int pick_a; | |
369 | ||
370 | archa = bfd_get_architecture (abfd); | |
371 | archb = bfd_get_architecture (bbfd); | |
372 | macha = bfd_get_machine (abfd); | |
373 | machb = bfd_get_machine (bbfd); | |
374 | ||
375 | if (archb == bfd_arch_unknown) | |
c618de01 | 376 | pick_a = 1; |
4a81b561 | 377 | else if (archa == bfd_arch_unknown) |
c618de01 | 378 | pick_a = 0; |
4a81b561 | 379 | else if (archa != archb) |
c618de01 | 380 | return false; /* Not compatible */ |
4a81b561 DHW |
381 | else { |
382 | /* Architectures are the same. Check machine types. */ | |
c618de01 | 383 | if (macha == machb) /* Same machine type */ |
4a81b561 | 384 | pick_a = 1; |
c618de01 | 385 | else if (machb == 0) /* B is default */ |
4a81b561 | 386 | pick_a = 1; |
c618de01 | 387 | else if (macha == 0) /* A is default */ |
4a81b561 DHW |
388 | pick_a = 0; |
389 | else switch (archa) { | |
390 | /* If particular machine types of one architecture are not | |
c618de01 SC |
391 | compatible with each other, this is the place to put those tests |
392 | (returning false if incompatible). */ | |
fc723380 JG |
393 | |
394 | case bfd_arch_i960: | |
c618de01 SC |
395 | /* The i960 has two distinct subspecies which may not interbreed: |
396 | CORE CA | |
397 | CORE KA KB MC | |
398 | Any architecture on the same line is compatible, the one on | |
399 | the right is the least restrictive. */ | |
400 | /* So, if either is a ca then the other must be a be core or ca */ | |
401 | if (macha == bfd_mach_i960_ca) { | |
402 | if (machb != bfd_mach_i960_ca && | |
403 | machb != bfd_mach_i960_core) { | |
404 | return false; | |
405 | } | |
406 | pick_a = 1; | |
407 | } | |
408 | else if (machb == bfd_mach_i960_ca) { | |
409 | if (macha != bfd_mach_i960_ca && | |
410 | macha != bfd_mach_i960_core) { | |
411 | return false; | |
412 | } | |
413 | pick_a = 0; | |
414 | } | |
415 | else { | |
416 | /* This must be from the bottom row, so take the higest */ | |
417 | pick_a = (macha > machb); | |
418 | } | |
419 | break; | |
4a81b561 DHW |
420 | |
421 | /* For these chips, as far as we care, "lower" numbers are included | |
c618de01 SC |
422 | by "higher" numbers, e.g. merge 68010 and 68020 into 68020, |
423 | 386 and 486 into 486, etc. This will need to change | |
424 | if&when we care about things like 68332. */ | |
4a81b561 DHW |
425 | case bfd_arch_m68k: |
426 | case bfd_arch_ns32k: | |
427 | case bfd_arch_i386: | |
428 | pick_a = (macha > machb); | |
429 | break; | |
430 | ||
431 | /* By default, pick first file's type, for lack of something better. */ | |
432 | default: | |
433 | pick_a = 1; | |
434 | } | |
435 | } | |
436 | ||
437 | /* Set result based on our pick */ | |
438 | if (!pick_a) { | |
439 | archa = archb; | |
440 | macha = machb; | |
441 | } | |
442 | if (archp) | |
443 | *archp = archa; | |
444 | if (machinep) | |
445 | *machinep = macha; | |
446 | ||
447 | return true; | |
448 | } | |
c618de01 SC |
449 | |
450 | ||
451 | /*proto* bfd_set_arch_mach | |
452 | Set atch mach | |
453 | *+ | |
454 | #define bfd_set_arch_mach(abfd, arch, mach) \ | |
455 | BFD_SEND (abfd, _bfd_set_arch_mach,\ | |
456 | (abfd, arch, mach)) | |
457 | *- | |
458 | */ | |
459 | ||
460 | ||
461 | foo() { } | |
462 | ||
463 | ||
464 |