obj.c 25 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502
  1. #define EXTERN
  2. #include "l.h"
  3. #include <ar.h>
  4. #ifndef DEFAULT
  5. #define DEFAULT '9'
  6. #endif
  7. char *noname = "<none>";
  8. char symname[] = SYMDEF;
  9. char thechar = '8';
  10. char *thestring = "386";
  11. /*
  12. * -H0 -T0x40004C -D0x10000000 is garbage unix
  13. * -H1 -T0xd0 -R4 is unix coff
  14. * -H2 -T4128 -R4096 is plan9 format
  15. * -H3 -Tx -Rx is MS-DOS .COM
  16. * -H4 -Tx -Rx is fake MS-DOS .EXE
  17. * -H5 -T0x80100020 -R4096 is ELF
  18. */
  19. static int
  20. isobjfile(char *f)
  21. {
  22. int n, v;
  23. Biobuf *b;
  24. char buf1[5], buf2[SARMAG];
  25. b = Bopen(f, OREAD);
  26. if(b == nil)
  27. return 0;
  28. n = Bread(b, buf1, 5);
  29. if(n == 5 && (buf1[2] == 1 && buf1[3] == '<' || buf1[3] == 1 && buf1[4] == '<'))
  30. v = 1; /* good enough for our purposes */
  31. else{
  32. Bseek(b, 0, 0);
  33. n = Bread(b, buf2, SARMAG);
  34. v = n == SARMAG && strncmp(buf2, ARMAG, SARMAG) == 0;
  35. }
  36. Bterm(b);
  37. return v;
  38. }
  39. void
  40. main(int argc, char *argv[])
  41. {
  42. int i, c;
  43. char *a;
  44. Binit(&bso, 1, OWRITE);
  45. cout = -1;
  46. listinit();
  47. memset(debug, 0, sizeof(debug));
  48. nerrors = 0;
  49. outfile = "8.out";
  50. HEADTYPE = -1;
  51. INITTEXT = -1;
  52. INITDAT = -1;
  53. INITRND = -1;
  54. INITENTRY = 0;
  55. ARGBEGIN {
  56. default:
  57. c = ARGC();
  58. if(c >= 0 && c < sizeof(debug))
  59. debug[c]++;
  60. break;
  61. case 'o': /* output to (next arg) */
  62. outfile = ARGF();
  63. break;
  64. case 'E':
  65. a = ARGF();
  66. if(a)
  67. INITENTRY = a;
  68. break;
  69. case 'H':
  70. a = ARGF();
  71. if(a)
  72. HEADTYPE = atolwhex(a);
  73. break;
  74. case 'T':
  75. a = ARGF();
  76. if(a)
  77. INITTEXT = atolwhex(a);
  78. break;
  79. case 'D':
  80. a = ARGF();
  81. if(a)
  82. INITDAT = atolwhex(a);
  83. break;
  84. case 'R':
  85. a = ARGF();
  86. if(a)
  87. INITRND = atolwhex(a);
  88. break;
  89. case 'x': /* produce export table */
  90. doexp = 1;
  91. if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
  92. readundefs(ARGF(), SEXPORT);
  93. break;
  94. case 'u': /* produce dynamically loadable module */
  95. dlm = 1;
  96. debug['l']++;
  97. if(argv[1] != nil && argv[1][0] != '-' && !isobjfile(argv[1]))
  98. readundefs(ARGF(), SIMPORT);
  99. break;
  100. } ARGEND
  101. USED(argc);
  102. if(*argv == 0) {
  103. diag("usage: 8l [-options] objects");
  104. errorexit();
  105. }
  106. if(!debug['9'] && !debug['U'] && !debug['B'])
  107. debug[DEFAULT] = 1;
  108. if(HEADTYPE == -1) {
  109. if(debug['U'])
  110. HEADTYPE = 1;
  111. if(debug['B'])
  112. HEADTYPE = 2;
  113. if(debug['9'])
  114. HEADTYPE = 2;
  115. }
  116. switch(HEADTYPE) {
  117. default:
  118. diag("unknown -H option");
  119. errorexit();
  120. case 0: /* this is garbage */
  121. HEADR = 20L+56L;
  122. if(INITTEXT == -1)
  123. INITTEXT = 0x40004CL;
  124. if(INITDAT == -1)
  125. INITDAT = 0x10000000L;
  126. if(INITRND == -1)
  127. INITRND = 0;
  128. break;
  129. case 1: /* is unix coff */
  130. HEADR = 0xd0L;
  131. if(INITTEXT == -1)
  132. INITTEXT = 0xd0;
  133. if(INITDAT == -1)
  134. INITDAT = 0x400000;
  135. if(INITRND == -1)
  136. INITRND = 0;
  137. break;
  138. case 2: /* plan 9 */
  139. HEADR = 32L;
  140. if(INITTEXT == -1)
  141. INITTEXT = 4096+32;
  142. if(INITDAT == -1)
  143. INITDAT = 0;
  144. if(INITRND == -1)
  145. INITRND = 4096;
  146. break;
  147. case 3: /* MS-DOS .COM */
  148. HEADR = 0;
  149. if(INITTEXT == -1)
  150. INITTEXT = 0x0100;
  151. if(INITDAT == -1)
  152. INITDAT = 0;
  153. if(INITRND == -1)
  154. INITRND = 4;
  155. break;
  156. case 4: /* fake MS-DOS .EXE */
  157. HEADR = 0x200;
  158. if(INITTEXT == -1)
  159. INITTEXT = 0x0100;
  160. if(INITDAT == -1)
  161. INITDAT = 0;
  162. if(INITRND == -1)
  163. INITRND = 4;
  164. HEADR += (INITTEXT & 0xFFFF);
  165. if(debug['v'])
  166. Bprint(&bso, "HEADR = 0x%ld\n", HEADR);
  167. break;
  168. case 5: /* elf executable */
  169. HEADR = rnd(52L+3*32L, 16);
  170. if(INITTEXT == -1)
  171. INITTEXT = 0x80100020L;
  172. if(INITDAT == -1)
  173. INITDAT = 0;
  174. if(INITRND == -1)
  175. INITRND = 4096;
  176. break;
  177. }
  178. if(INITDAT != 0 && INITRND != 0)
  179. print("warning: -D0x%lux is ignored because of -R0x%lux\n",
  180. INITDAT, INITRND);
  181. if(debug['v'])
  182. Bprint(&bso, "HEADER = -H0x%ld -T0x%lux -D0x%lux -R0x%lux\n",
  183. HEADTYPE, INITTEXT, INITDAT, INITRND);
  184. Bflush(&bso);
  185. for(i=1; optab[i].as; i++)
  186. if(i != optab[i].as) {
  187. diag("phase error in optab: %d", i);
  188. errorexit();
  189. }
  190. maxop = i;
  191. for(i=0; i<Ymax; i++)
  192. ycover[i*Ymax + i] = 1;
  193. ycover[Yi0*Ymax + Yi8] = 1;
  194. ycover[Yi1*Ymax + Yi8] = 1;
  195. ycover[Yi0*Ymax + Yi32] = 1;
  196. ycover[Yi1*Ymax + Yi32] = 1;
  197. ycover[Yi8*Ymax + Yi32] = 1;
  198. ycover[Yal*Ymax + Yrb] = 1;
  199. ycover[Ycl*Ymax + Yrb] = 1;
  200. ycover[Yax*Ymax + Yrb] = 1;
  201. ycover[Ycx*Ymax + Yrb] = 1;
  202. ycover[Yrx*Ymax + Yrb] = 1;
  203. ycover[Yax*Ymax + Yrx] = 1;
  204. ycover[Ycx*Ymax + Yrx] = 1;
  205. ycover[Yax*Ymax + Yrl] = 1;
  206. ycover[Ycx*Ymax + Yrl] = 1;
  207. ycover[Yrx*Ymax + Yrl] = 1;
  208. ycover[Yf0*Ymax + Yrf] = 1;
  209. ycover[Yal*Ymax + Ymb] = 1;
  210. ycover[Ycl*Ymax + Ymb] = 1;
  211. ycover[Yax*Ymax + Ymb] = 1;
  212. ycover[Ycx*Ymax + Ymb] = 1;
  213. ycover[Yrx*Ymax + Ymb] = 1;
  214. ycover[Yrb*Ymax + Ymb] = 1;
  215. ycover[Ym*Ymax + Ymb] = 1;
  216. ycover[Yax*Ymax + Yml] = 1;
  217. ycover[Ycx*Ymax + Yml] = 1;
  218. ycover[Yrx*Ymax + Yml] = 1;
  219. ycover[Yrl*Ymax + Yml] = 1;
  220. ycover[Ym*Ymax + Yml] = 1;
  221. for(i=0; i<D_NONE; i++) {
  222. reg[i] = -1;
  223. if(i >= D_AL && i <= D_BH)
  224. reg[i] = (i-D_AL) & 7;
  225. if(i >= D_AX && i <= D_DI)
  226. reg[i] = (i-D_AX) & 7;
  227. if(i >= D_F0 && i <= D_F0+7)
  228. reg[i] = (i-D_F0) & 7;
  229. }
  230. zprg.link = P;
  231. zprg.pcond = P;
  232. zprg.back = 2;
  233. zprg.as = AGOK;
  234. zprg.from.type = D_NONE;
  235. zprg.from.index = D_NONE;
  236. zprg.from.scale = 1;
  237. zprg.to = zprg.from;
  238. pcstr = "%.6lux ";
  239. nuxiinit();
  240. histgen = 0;
  241. textp = P;
  242. datap = P;
  243. edatap = P;
  244. pc = 0;
  245. dtype = 4;
  246. cout = create(outfile, 1, 0775);
  247. if(cout < 0) {
  248. diag("cannot create %s", outfile);
  249. errorexit();
  250. }
  251. version = 0;
  252. cbp = buf.cbuf;
  253. cbc = sizeof(buf.cbuf);
  254. firstp = prg();
  255. lastp = firstp;
  256. if(INITENTRY == 0) {
  257. INITENTRY = "_main";
  258. if(debug['p'])
  259. INITENTRY = "_mainp";
  260. if(!debug['l'])
  261. lookup(INITENTRY, 0)->type = SXREF;
  262. } else
  263. lookup(INITENTRY, 0)->type = SXREF;
  264. while(*argv)
  265. objfile(*argv++);
  266. if(!debug['l'])
  267. loadlib();
  268. firstp = firstp->link;
  269. if(firstp == P)
  270. errorexit();
  271. if(doexp || dlm){
  272. EXPTAB = "_exporttab";
  273. zerosig(EXPTAB);
  274. zerosig("etext");
  275. zerosig("edata");
  276. zerosig("end");
  277. if(dlm){
  278. import();
  279. HEADTYPE = 2;
  280. INITTEXT = INITDAT = 0;
  281. INITRND = 8;
  282. INITENTRY = EXPTAB;
  283. }
  284. export();
  285. }
  286. patch();
  287. follow();
  288. dodata();
  289. dostkoff();
  290. if(debug['p'])
  291. if(debug['1'])
  292. doprof1();
  293. else
  294. doprof2();
  295. span();
  296. doinit();
  297. asmb();
  298. undef();
  299. if(debug['v']) {
  300. Bprint(&bso, "%5.2f cpu time\n", cputime());
  301. Bprint(&bso, "%ld symbols\n", nsymbol);
  302. Bprint(&bso, "%ld memory used\n", thunk);
  303. Bprint(&bso, "%d sizeof adr\n", sizeof(Adr));
  304. Bprint(&bso, "%d sizeof prog\n", sizeof(Prog));
  305. }
  306. Bflush(&bso);
  307. errorexit();
  308. }
  309. void
  310. loadlib(void)
  311. {
  312. int i;
  313. long h;
  314. Sym *s;
  315. loop:
  316. xrefresolv = 0;
  317. for(i=0; i<libraryp; i++) {
  318. if(debug['v'])
  319. Bprint(&bso, "%5.2f autolib: %s (from %s)\n", cputime(), library[i], libraryobj[i]);
  320. objfile(library[i]);
  321. }
  322. if(xrefresolv)
  323. for(h=0; h<nelem(hash); h++)
  324. for(s = hash[h]; s != S; s = s->link)
  325. if(s->type == SXREF)
  326. goto loop;
  327. }
  328. void
  329. errorexit(void)
  330. {
  331. if(nerrors) {
  332. if(cout >= 0)
  333. remove(outfile);
  334. exits("error");
  335. }
  336. exits(0);
  337. }
  338. void
  339. objfile(char *file)
  340. {
  341. long off, esym, cnt, l;
  342. int f, work;
  343. Sym *s;
  344. char magbuf[SARMAG];
  345. char name[100], pname[150];
  346. struct ar_hdr arhdr;
  347. char *e, *start, *stop;
  348. if(file[0] == '-' && file[1] == 'l') {
  349. if(debug['9'])
  350. sprint(name, "/%s/lib/lib", thestring);
  351. else
  352. sprint(name, "/usr/%clib/lib", thechar);
  353. strcat(name, file+2);
  354. strcat(name, ".a");
  355. file = name;
  356. }
  357. if(debug['v'])
  358. Bprint(&bso, "%5.2f ldobj: %s\n", cputime(), file);
  359. Bflush(&bso);
  360. f = open(file, 0);
  361. if(f < 0) {
  362. diag("cannot open file: %s", file);
  363. errorexit();
  364. }
  365. l = read(f, magbuf, SARMAG);
  366. if(l != SARMAG || strncmp(magbuf, ARMAG, SARMAG)){
  367. /* load it as a regular file */
  368. l = seek(f, 0L, 2);
  369. seek(f, 0L, 0);
  370. ldobj(f, l, file);
  371. close(f);
  372. return;
  373. }
  374. l = read(f, &arhdr, SAR_HDR);
  375. if(l != SAR_HDR) {
  376. diag("%s: short read on archive file symbol header", file);
  377. goto out;
  378. }
  379. if(strncmp(arhdr.name, symname, strlen(symname))) {
  380. diag("%s: first entry not symbol header", file);
  381. goto out;
  382. }
  383. esym = SARMAG + SAR_HDR + atolwhex(arhdr.size);
  384. off = SARMAG + SAR_HDR;
  385. /*
  386. * just bang the whole symbol file into memory
  387. */
  388. seek(f, off, 0);
  389. cnt = esym - off;
  390. start = malloc(cnt + 10);
  391. cnt = read(f, start, cnt);
  392. if(cnt <= 0){
  393. close(f);
  394. return;
  395. }
  396. stop = &start[cnt];
  397. memset(stop, 0, 10);
  398. work = 1;
  399. while(work) {
  400. if(debug['v'])
  401. Bprint(&bso, "%5.2f library pass: %s\n", cputime(), file);
  402. Bflush(&bso);
  403. work = 0;
  404. for(e = start; e < stop; e = strchr(e+5, 0) + 1) {
  405. s = lookup(e+5, 0);
  406. if(s->type != SXREF)
  407. continue;
  408. sprint(pname, "%s(%s)", file, s->name);
  409. if(debug['v'])
  410. Bprint(&bso, "%5.2f library: %s\n", cputime(), pname);
  411. Bflush(&bso);
  412. l = e[1] & 0xff;
  413. l |= (e[2] & 0xff) << 8;
  414. l |= (e[3] & 0xff) << 16;
  415. l |= (e[4] & 0xff) << 24;
  416. seek(f, l, 0);
  417. l = read(f, &arhdr, SAR_HDR);
  418. if(l != SAR_HDR)
  419. goto bad;
  420. if(strncmp(arhdr.fmag, ARFMAG, sizeof(arhdr.fmag)))
  421. goto bad;
  422. l = atolwhex(arhdr.size);
  423. ldobj(f, l, pname);
  424. if(s->type == SXREF) {
  425. diag("%s: failed to load: %s", file, s->name);
  426. errorexit();
  427. }
  428. work = 1;
  429. xrefresolv = 1;
  430. }
  431. }
  432. return;
  433. bad:
  434. diag("%s: bad or out of date archive", file);
  435. out:
  436. close(f);
  437. }
  438. int
  439. zaddr(uchar *p, Adr *a, Sym *h[])
  440. {
  441. int c, t, i;
  442. long l;
  443. Sym *s;
  444. Auto *u;
  445. t = p[0];
  446. c = 1;
  447. if(t & T_INDEX) {
  448. a->index = p[c];
  449. a->scale = p[c+1];
  450. c += 2;
  451. } else {
  452. a->index = D_NONE;
  453. a->scale = 0;
  454. }
  455. a->offset = 0;
  456. if(t & T_OFFSET) {
  457. a->offset = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
  458. c += 4;
  459. }
  460. a->sym = S;
  461. if(t & T_SYM) {
  462. a->sym = h[p[c]];
  463. c++;
  464. }
  465. a->type = D_NONE;
  466. if(t & T_FCONST) {
  467. a->ieee.l = p[c] | (p[c+1]<<8) | (p[c+2]<<16) | (p[c+3]<<24);
  468. a->ieee.h = p[c+4] | (p[c+5]<<8) | (p[c+6]<<16) | (p[c+7]<<24);
  469. c += 8;
  470. a->type = D_FCONST;
  471. } else
  472. if(t & T_SCONST) {
  473. for(i=0; i<NSNAME; i++)
  474. a->scon[i] = p[c+i];
  475. c += NSNAME;
  476. a->type = D_SCONST;
  477. }
  478. if(t & T_TYPE) {
  479. a->type = p[c];
  480. c++;
  481. }
  482. s = a->sym;
  483. if(s == S)
  484. return c;
  485. t = a->type;
  486. if(t != D_AUTO && t != D_PARAM)
  487. return c;
  488. l = a->offset;
  489. for(u=curauto; u; u=u->link) {
  490. if(u->asym == s)
  491. if(u->type == t) {
  492. if(u->aoffset > l)
  493. u->aoffset = l;
  494. return c;
  495. }
  496. }
  497. while(nhunk < sizeof(Auto))
  498. gethunk();
  499. u = (Auto*)hunk;
  500. nhunk -= sizeof(Auto);
  501. hunk += sizeof(Auto);
  502. u->link = curauto;
  503. curauto = u;
  504. u->asym = s;
  505. u->aoffset = l;
  506. u->type = t;
  507. return c;
  508. }
  509. void
  510. addlib(char *obj)
  511. {
  512. char name[1024], comp[256], *p;
  513. int i;
  514. if(histfrogp <= 0)
  515. return;
  516. if(histfrog[0]->name[1] == '/') {
  517. sprint(name, "");
  518. i = 1;
  519. } else
  520. if(histfrog[0]->name[1] == '.') {
  521. sprint(name, ".");
  522. i = 0;
  523. } else {
  524. if(debug['9'])
  525. sprint(name, "/%s/lib", thestring);
  526. else
  527. sprint(name, "/usr/%clib", thechar);
  528. i = 0;
  529. }
  530. for(; i<histfrogp; i++) {
  531. snprint(comp, sizeof comp, histfrog[i]->name+1);
  532. for(;;) {
  533. p = strstr(comp, "$O");
  534. if(p == 0)
  535. break;
  536. memmove(p+1, p+2, strlen(p+2)+1);
  537. p[0] = thechar;
  538. }
  539. for(;;) {
  540. p = strstr(comp, "$M");
  541. if(p == 0)
  542. break;
  543. if(strlen(comp)+strlen(thestring)-2+1 >= sizeof comp) {
  544. diag("library component too long");
  545. return;
  546. }
  547. memmove(p+strlen(thestring), p+2, strlen(p+2)+1);
  548. memmove(p, thestring, strlen(thestring));
  549. }
  550. if(strlen(name) + strlen(comp) + 3 >= sizeof(name)) {
  551. diag("library component too long");
  552. return;
  553. }
  554. strcat(name, "/");
  555. strcat(name, comp);
  556. }
  557. for(i=0; i<libraryp; i++)
  558. if(strcmp(name, library[i]) == 0)
  559. return;
  560. if(libraryp == nelem(library)){
  561. diag("too many autolibs; skipping %s", name);
  562. return;
  563. }
  564. p = malloc(strlen(name) + 1);
  565. strcpy(p, name);
  566. library[libraryp] = p;
  567. p = malloc(strlen(obj) + 1);
  568. strcpy(p, obj);
  569. libraryobj[libraryp] = p;
  570. libraryp++;
  571. }
  572. void
  573. addhist(long line, int type)
  574. {
  575. Auto *u;
  576. Sym *s;
  577. int i, j, k;
  578. u = malloc(sizeof(Auto));
  579. s = malloc(sizeof(Sym));
  580. s->name = malloc(2*(histfrogp+1) + 1);
  581. u->asym = s;
  582. u->type = type;
  583. u->aoffset = line;
  584. u->link = curhist;
  585. curhist = u;
  586. j = 1;
  587. for(i=0; i<histfrogp; i++) {
  588. k = histfrog[i]->value;
  589. s->name[j+0] = k>>8;
  590. s->name[j+1] = k;
  591. j += 2;
  592. }
  593. }
  594. void
  595. histtoauto(void)
  596. {
  597. Auto *l;
  598. while(l = curhist) {
  599. curhist = l->link;
  600. l->link = curauto;
  601. curauto = l;
  602. }
  603. }
  604. void
  605. collapsefrog(Sym *s)
  606. {
  607. int i;
  608. /*
  609. * bad encoding of path components only allows
  610. * MAXHIST components. if there is an overflow,
  611. * first try to collapse xxx/..
  612. */
  613. for(i=1; i<histfrogp; i++)
  614. if(strcmp(histfrog[i]->name+1, "..") == 0) {
  615. memmove(histfrog+i-1, histfrog+i+1,
  616. (histfrogp-i-1)*sizeof(histfrog[0]));
  617. histfrogp--;
  618. goto out;
  619. }
  620. /*
  621. * next try to collapse .
  622. */
  623. for(i=0; i<histfrogp; i++)
  624. if(strcmp(histfrog[i]->name+1, ".") == 0) {
  625. memmove(histfrog+i, histfrog+i+1,
  626. (histfrogp-i-1)*sizeof(histfrog[0]));
  627. goto out;
  628. }
  629. /*
  630. * last chance, just truncate from front
  631. */
  632. memmove(histfrog+0, histfrog+1,
  633. (histfrogp-1)*sizeof(histfrog[0]));
  634. out:
  635. histfrog[histfrogp-1] = s;
  636. }
  637. void
  638. nopout(Prog *p)
  639. {
  640. p->as = ANOP;
  641. p->from.type = D_NONE;
  642. p->to.type = D_NONE;
  643. }
  644. uchar*
  645. readsome(int f, uchar *buf, uchar *good, uchar *stop, int max)
  646. {
  647. int n;
  648. n = stop - good;
  649. memmove(buf, good, stop - good);
  650. stop = buf + n;
  651. n = MAXIO - n;
  652. if(n > max)
  653. n = max;
  654. n = read(f, stop, n);
  655. if(n <= 0)
  656. return 0;
  657. return stop + n;
  658. }
  659. void
  660. ldobj(int f, long c, char *pn)
  661. {
  662. long ipc;
  663. Prog *p, *t;
  664. uchar *bloc, *bsize, *stop;
  665. int v, o, r, skip;
  666. Sym *h[NSYM], *s, *di;
  667. ulong sig;
  668. static int files;
  669. static char **filen;
  670. char **nfilen;
  671. if((files&15) == 0){
  672. nfilen = malloc((files+16)*sizeof(char*));
  673. memmove(nfilen, filen, files*sizeof(char*));
  674. free(filen);
  675. filen = nfilen;
  676. }
  677. filen[files++] = strdup(pn);
  678. bsize = buf.xbuf;
  679. bloc = buf.xbuf;
  680. di = S;
  681. newloop:
  682. memset(h, 0, sizeof(h));
  683. version++;
  684. histfrogp = 0;
  685. ipc = pc;
  686. skip = 0;
  687. loop:
  688. if(c <= 0)
  689. goto eof;
  690. r = bsize - bloc;
  691. if(r < 100 && r < c) { /* enough for largest prog */
  692. bsize = readsome(f, buf.xbuf, bloc, bsize, c);
  693. if(bsize == 0)
  694. goto eof;
  695. bloc = buf.xbuf;
  696. goto loop;
  697. }
  698. o = bloc[0] | (bloc[1] << 8);
  699. if(o <= AXXX || o >= ALAST) {
  700. if(o < 0)
  701. goto eof;
  702. diag("%s: opcode out of range %d", pn, o);
  703. print(" probably not a .8 file\n");
  704. errorexit();
  705. }
  706. if(o == ANAME || o == ASIGNAME) {
  707. sig = 0;
  708. if(o == ASIGNAME) {
  709. sig = bloc[2] | (bloc[3]<<8) | (bloc[4]<<16) | (bloc[5]<<24);
  710. bloc += 4;
  711. c -= 4;
  712. }
  713. stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
  714. if(stop == 0){
  715. bsize = readsome(f, buf.xbuf, bloc, bsize, c);
  716. if(bsize == 0)
  717. goto eof;
  718. bloc = buf.xbuf;
  719. stop = memchr(&bloc[4], 0, bsize-&bloc[4]);
  720. if(stop == 0){
  721. fprint(2, "%s: name too long\n", pn);
  722. errorexit();
  723. }
  724. }
  725. v = bloc[2]; /* type */
  726. o = bloc[3]; /* sym */
  727. bloc += 4;
  728. c -= 4;
  729. r = 0;
  730. if(v == D_STATIC)
  731. r = version;
  732. s = lookup((char*)bloc, r);
  733. c -= &stop[1] - bloc;
  734. bloc = stop + 1;
  735. if(debug['S'] && r == 0)
  736. sig = 1729;
  737. if(sig != 0){
  738. if(s->sig != 0 && s->sig != sig)
  739. diag("incompatible type signatures %lux(%s) and %lux(%s) for %s", s->sig, filen[s->file], sig, pn, s->name);
  740. s->sig = sig;
  741. s->file = files-1;
  742. }
  743. if(debug['W'])
  744. print(" ANAME %s\n", s->name);
  745. h[o] = s;
  746. if((v == D_EXTERN || v == D_STATIC) && s->type == 0)
  747. s->type = SXREF;
  748. if(v == D_FILE) {
  749. if(s->type != SFILE) {
  750. histgen++;
  751. s->type = SFILE;
  752. s->value = histgen;
  753. }
  754. if(histfrogp < MAXHIST) {
  755. histfrog[histfrogp] = s;
  756. histfrogp++;
  757. } else
  758. collapsefrog(s);
  759. }
  760. goto loop;
  761. }
  762. while(nhunk < sizeof(Prog))
  763. gethunk();
  764. p = (Prog*)hunk;
  765. nhunk -= sizeof(Prog);
  766. hunk += sizeof(Prog);
  767. p->as = o;
  768. p->line = bloc[2] | (bloc[3] << 8) | (bloc[4] << 16) | (bloc[5] << 24);
  769. p->back = 2;
  770. r = zaddr(bloc+6, &p->from, h) + 6;
  771. r += zaddr(bloc+r, &p->to, h);
  772. bloc += r;
  773. c -= r;
  774. if(debug['W'])
  775. print("%P\n", p);
  776. switch(p->as) {
  777. case AHISTORY:
  778. if(p->to.offset == -1) {
  779. addlib(pn);
  780. histfrogp = 0;
  781. goto loop;
  782. }
  783. addhist(p->line, D_FILE); /* 'z' */
  784. if(p->to.offset)
  785. addhist(p->to.offset, D_FILE1); /* 'Z' */
  786. histfrogp = 0;
  787. goto loop;
  788. case AEND:
  789. histtoauto();
  790. if(curtext != P)
  791. curtext->to.autom = curauto;
  792. curauto = 0;
  793. curtext = P;
  794. if(c)
  795. goto newloop;
  796. return;
  797. case AGLOBL:
  798. s = p->from.sym;
  799. if(s->type == 0 || s->type == SXREF) {
  800. s->type = SBSS;
  801. s->value = 0;
  802. }
  803. if(s->type != SBSS) {
  804. diag("%s: redefinition: %s in %s",
  805. pn, s->name, TNAME);
  806. s->type = SBSS;
  807. s->value = 0;
  808. }
  809. if(p->to.offset > s->value)
  810. s->value = p->to.offset;
  811. goto loop;
  812. case ADYNT:
  813. if(p->to.sym == S) {
  814. diag("DYNT without a sym\n%P", p);
  815. break;
  816. }
  817. di = p->to.sym;
  818. p->from.scale = 4;
  819. if(di->type == SXREF) {
  820. if(debug['z'])
  821. Bprint(&bso, "%P set to %d\n", p, dtype);
  822. di->type = SCONST;
  823. di->value = dtype;
  824. dtype += 4;
  825. }
  826. if(p->from.sym == S)
  827. break;
  828. p->from.offset = di->value;
  829. p->from.sym->type = SDATA;
  830. if(curtext == P) {
  831. diag("DYNT not in text: %P", p);
  832. break;
  833. }
  834. p->to.sym = curtext->from.sym;
  835. p->to.type = D_ADDR;
  836. p->to.index = D_EXTERN;
  837. goto data;
  838. case AINIT:
  839. if(p->from.sym == S) {
  840. diag("INIT without a sym\n%P", p);
  841. break;
  842. }
  843. if(di == S) {
  844. diag("INIT without previous DYNT\n%P", p);
  845. break;
  846. }
  847. p->from.offset = di->value;
  848. p->from.sym->type = SDATA;
  849. goto data;
  850. case ADATA:
  851. data:
  852. if(edatap == P)
  853. datap = p;
  854. else
  855. edatap->link = p;
  856. edatap = p;
  857. p->link = P;
  858. goto loop;
  859. case AGOK:
  860. diag("%s: GOK opcode in %s", pn, TNAME);
  861. pc++;
  862. goto loop;
  863. case ATEXT:
  864. if(curtext != P) {
  865. histtoauto();
  866. curtext->to.autom = curauto;
  867. curauto = 0;
  868. }
  869. skip = 0;
  870. curtext = p;
  871. s = p->from.sym;
  872. if(s == S) {
  873. diag("%s: no TEXT symbol: %P", pn, p);
  874. errorexit();
  875. }
  876. if(s->type != 0 && s->type != SXREF) {
  877. if(p->from.scale & DUPOK) {
  878. skip = 1;
  879. goto casdef;
  880. }
  881. diag("%s: redefinition: %s\n%P", pn, s->name, p);
  882. }
  883. s->type = STEXT;
  884. s->value = pc;
  885. lastp->link = p;
  886. lastp = p;
  887. p->pc = pc;
  888. pc++;
  889. if(textp == P) {
  890. textp = p;
  891. etextp = p;
  892. goto loop;
  893. }
  894. etextp->pcond = p;
  895. etextp = p;
  896. goto loop;
  897. case AFMOVF:
  898. case AFADDF:
  899. case AFSUBF:
  900. case AFSUBRF:
  901. case AFMULF:
  902. case AFDIVF:
  903. case AFDIVRF:
  904. case AFCOMF:
  905. case AFCOMFP:
  906. if(skip)
  907. goto casdef;
  908. if(p->from.type == D_FCONST) {
  909. /* size sb 9 max */
  910. sprint(literal, "$%lux", ieeedtof(&p->from.ieee));
  911. s = lookup(literal, 0);
  912. if(s->type == 0) {
  913. s->type = SBSS;
  914. s->value = 4;
  915. t = prg();
  916. t->as = ADATA;
  917. t->line = p->line;
  918. t->from.type = D_EXTERN;
  919. t->from.sym = s;
  920. t->from.scale = 4;
  921. t->to = p->from;
  922. if(edatap == P)
  923. datap = t;
  924. else
  925. edatap->link = t;
  926. edatap = t;
  927. t->link = P;
  928. }
  929. p->from.type = D_EXTERN;
  930. p->from.sym = s;
  931. p->from.offset = 0;
  932. }
  933. goto casdef;
  934. case AFMOVD:
  935. case AFADDD:
  936. case AFSUBD:
  937. case AFSUBRD:
  938. case AFMULD:
  939. case AFDIVD:
  940. case AFDIVRD:
  941. case AFCOMD:
  942. case AFCOMDP:
  943. if(skip)
  944. goto casdef;
  945. if(p->from.type == D_FCONST) {
  946. /* size sb 18 max */
  947. sprint(literal, "$%lux.%lux",
  948. p->from.ieee.l, p->from.ieee.h);
  949. s = lookup(literal, 0);
  950. if(s->type == 0) {
  951. s->type = SBSS;
  952. s->value = 8;
  953. t = prg();
  954. t->as = ADATA;
  955. t->line = p->line;
  956. t->from.type = D_EXTERN;
  957. t->from.sym = s;
  958. t->from.scale = 8;
  959. t->to = p->from;
  960. if(edatap == P)
  961. datap = t;
  962. else
  963. edatap->link = t;
  964. edatap = t;
  965. t->link = P;
  966. }
  967. p->from.type = D_EXTERN;
  968. p->from.sym = s;
  969. p->from.offset = 0;
  970. }
  971. goto casdef;
  972. casdef:
  973. default:
  974. if(skip)
  975. nopout(p);
  976. if(p->to.type == D_BRANCH)
  977. p->to.offset += ipc;
  978. lastp->link = p;
  979. lastp = p;
  980. p->pc = pc;
  981. pc++;
  982. goto loop;
  983. }
  984. goto loop;
  985. eof:
  986. diag("truncated object file: %s", pn);
  987. }
  988. Sym*
  989. lookup(char *symb, int v)
  990. {
  991. Sym *s;
  992. char *p;
  993. long h;
  994. int l, c;
  995. h = v;
  996. for(p=symb; c = *p; p++)
  997. h = h+h+h + c;
  998. l = (p - symb) + 1;
  999. if(h < 0)
  1000. h = ~h;
  1001. h %= NHASH;
  1002. for(s = hash[h]; s != S; s = s->link)
  1003. if(s->version == v)
  1004. if(memcmp(s->name, symb, l) == 0)
  1005. return s;
  1006. while(nhunk < sizeof(Sym))
  1007. gethunk();
  1008. s = (Sym*)hunk;
  1009. nhunk -= sizeof(Sym);
  1010. hunk += sizeof(Sym);
  1011. s->name = malloc(l + 1);
  1012. memmove(s->name, symb, l);
  1013. s->link = hash[h];
  1014. s->type = 0;
  1015. s->version = v;
  1016. s->value = 0;
  1017. s->sig = 0;
  1018. hash[h] = s;
  1019. nsymbol++;
  1020. return s;
  1021. }
  1022. Prog*
  1023. prg(void)
  1024. {
  1025. Prog *p;
  1026. while(nhunk < sizeof(Prog))
  1027. gethunk();
  1028. p = (Prog*)hunk;
  1029. nhunk -= sizeof(Prog);
  1030. hunk += sizeof(Prog);
  1031. *p = zprg;
  1032. return p;
  1033. }
  1034. Prog*
  1035. copyp(Prog *q)
  1036. {
  1037. Prog *p;
  1038. p = prg();
  1039. *p = *q;
  1040. return p;
  1041. }
  1042. Prog*
  1043. appendp(Prog *q)
  1044. {
  1045. Prog *p;
  1046. p = prg();
  1047. p->link = q->link;
  1048. q->link = p;
  1049. p->line = q->line;
  1050. return p;
  1051. }
  1052. void
  1053. gethunk(void)
  1054. {
  1055. char *h;
  1056. long nh;
  1057. nh = NHUNK;
  1058. if(thunk >= 5L*NHUNK) {
  1059. nh = 5L*NHUNK;
  1060. if(thunk >= 25L*NHUNK)
  1061. nh = 25L*NHUNK;
  1062. }
  1063. h = mysbrk(nh);
  1064. if(h == (char*)-1) {
  1065. diag("out of memory");
  1066. errorexit();
  1067. }
  1068. hunk = h;
  1069. nhunk = nh;
  1070. thunk += nh;
  1071. }
  1072. void
  1073. doprof1(void)
  1074. {
  1075. Sym *s;
  1076. long n;
  1077. Prog *p, *q;
  1078. if(debug['v'])
  1079. Bprint(&bso, "%5.2f profile 1\n", cputime());
  1080. Bflush(&bso);
  1081. s = lookup("__mcount", 0);
  1082. n = 1;
  1083. for(p = firstp->link; p != P; p = p->link) {
  1084. if(p->as == ATEXT) {
  1085. q = prg();
  1086. q->line = p->line;
  1087. q->link = datap;
  1088. datap = q;
  1089. q->as = ADATA;
  1090. q->from.type = D_EXTERN;
  1091. q->from.offset = n*4;
  1092. q->from.sym = s;
  1093. q->from.scale = 4;
  1094. q->to = p->from;
  1095. q->to.type = D_CONST;
  1096. q = prg();
  1097. q->line = p->line;
  1098. q->pc = p->pc;
  1099. q->link = p->link;
  1100. p->link = q;
  1101. p = q;
  1102. p->as = AADDL;
  1103. p->from.type = D_CONST;
  1104. p->from.offset = 1;
  1105. p->to.type = D_EXTERN;
  1106. p->to.sym = s;
  1107. p->to.offset = n*4 + 4;
  1108. n += 2;
  1109. continue;
  1110. }
  1111. }
  1112. q = prg();
  1113. q->line = 0;
  1114. q->link = datap;
  1115. datap = q;
  1116. q->as = ADATA;
  1117. q->from.type = D_EXTERN;
  1118. q->from.sym = s;
  1119. q->from.scale = 4;
  1120. q->to.type = D_CONST;
  1121. q->to.offset = n;
  1122. s->type = SBSS;
  1123. s->value = n*4;
  1124. }
  1125. void
  1126. doprof2(void)
  1127. {
  1128. Sym *s2, *s4;
  1129. Prog *p, *q, *ps2, *ps4;
  1130. if(debug['v'])
  1131. Bprint(&bso, "%5.2f profile 2\n", cputime());
  1132. Bflush(&bso);
  1133. s2 = lookup("_profin", 0);
  1134. s4 = lookup("_profout", 0);
  1135. if(s2->type != STEXT || s4->type != STEXT) {
  1136. diag("_profin/_profout not defined");
  1137. return;
  1138. }
  1139. ps2 = P;
  1140. ps4 = P;
  1141. for(p = firstp; p != P; p = p->link) {
  1142. if(p->as == ATEXT) {
  1143. if(p->from.sym == s2) {
  1144. p->from.scale = 1;
  1145. ps2 = p;
  1146. }
  1147. if(p->from.sym == s4) {
  1148. p->from.scale = 1;
  1149. ps4 = p;
  1150. }
  1151. }
  1152. }
  1153. for(p = firstp; p != P; p = p->link) {
  1154. if(p->as == ATEXT) {
  1155. curtext = p;
  1156. if(p->from.scale & NOPROF) { /* dont profile */
  1157. for(;;) {
  1158. q = p->link;
  1159. if(q == P)
  1160. break;
  1161. if(q->as == ATEXT)
  1162. break;
  1163. p = q;
  1164. }
  1165. continue;
  1166. }
  1167. /*
  1168. * JMPL profin
  1169. */
  1170. q = prg();
  1171. q->line = p->line;
  1172. q->pc = p->pc;
  1173. q->link = p->link;
  1174. p->link = q;
  1175. p = q;
  1176. p->as = ACALL;
  1177. p->to.type = D_BRANCH;
  1178. p->pcond = ps2;
  1179. p->to.sym = s2;
  1180. continue;
  1181. }
  1182. if(p->as == ARET) {
  1183. /*
  1184. * RET
  1185. */
  1186. q = prg();
  1187. q->as = ARET;
  1188. q->from = p->from;
  1189. q->to = p->to;
  1190. q->link = p->link;
  1191. p->link = q;
  1192. /*
  1193. * JAL profout
  1194. */
  1195. p->as = ACALL;
  1196. p->from = zprg.from;
  1197. p->to = zprg.to;
  1198. p->to.type = D_BRANCH;
  1199. p->pcond = ps4;
  1200. p->to.sym = s4;
  1201. p = q;
  1202. continue;
  1203. }
  1204. }
  1205. }
  1206. void
  1207. nuxiinit(void)
  1208. {
  1209. int i, c;
  1210. for(i=0; i<4; i++) {
  1211. c = find1(0x04030201L, i+1);
  1212. if(i < 2)
  1213. inuxi2[i] = c;
  1214. if(i < 1)
  1215. inuxi1[i] = c;
  1216. inuxi4[i] = c;
  1217. fnuxi4[i] = c;
  1218. fnuxi8[i] = c;
  1219. fnuxi8[i+4] = c+4;
  1220. }
  1221. if(debug['v']) {
  1222. Bprint(&bso, "inuxi = ");
  1223. for(i=0; i<1; i++)
  1224. Bprint(&bso, "%d", inuxi1[i]);
  1225. Bprint(&bso, " ");
  1226. for(i=0; i<2; i++)
  1227. Bprint(&bso, "%d", inuxi2[i]);
  1228. Bprint(&bso, " ");
  1229. for(i=0; i<4; i++)
  1230. Bprint(&bso, "%d", inuxi4[i]);
  1231. Bprint(&bso, "\nfnuxi = ");
  1232. for(i=0; i<4; i++)
  1233. Bprint(&bso, "%d", fnuxi4[i]);
  1234. Bprint(&bso, " ");
  1235. for(i=0; i<8; i++)
  1236. Bprint(&bso, "%d", fnuxi8[i]);
  1237. Bprint(&bso, "\n");
  1238. }
  1239. Bflush(&bso);
  1240. }
  1241. int
  1242. find1(long l, int c)
  1243. {
  1244. char *p;
  1245. int i;
  1246. p = (char*)&l;
  1247. for(i=0; i<4; i++)
  1248. if(*p++ == c)
  1249. return i;
  1250. return 0;
  1251. }
  1252. int
  1253. find2(long l, int c)
  1254. {
  1255. short *p;
  1256. int i;
  1257. p = (short*)&l;
  1258. for(i=0; i<4; i+=2) {
  1259. if(((*p >> 8) & 0xff) == c)
  1260. return i;
  1261. if((*p++ & 0xff) == c)
  1262. return i+1;
  1263. }
  1264. return 0;
  1265. }
  1266. long
  1267. ieeedtof(Ieee *e)
  1268. {
  1269. int exp;
  1270. long v;
  1271. if(e->h == 0)
  1272. return 0;
  1273. exp = (e->h>>20) & ((1L<<11)-1L);
  1274. exp -= (1L<<10) - 2L;
  1275. v = (e->h & 0xfffffL) << 3;
  1276. v |= (e->l >> 29) & 0x7L;
  1277. if((e->l >> 28) & 1) {
  1278. v++;
  1279. if(v & 0x800000L) {
  1280. v = (v & 0x7fffffL) >> 1;
  1281. exp++;
  1282. }
  1283. }
  1284. if(exp <= -126 || exp >= 130)
  1285. diag("double fp to single fp overflow");
  1286. v |= ((exp + 126) & 0xffL) << 23;
  1287. v |= e->h & 0x80000000L;
  1288. return v;
  1289. }
  1290. double
  1291. ieeedtod(Ieee *ieeep)
  1292. {
  1293. Ieee e;
  1294. double fr;
  1295. int exp;
  1296. if(ieeep->h & (1L<<31)) {
  1297. e.h = ieeep->h & ~(1L<<31);
  1298. e.l = ieeep->l;
  1299. return -ieeedtod(&e);
  1300. }
  1301. if(ieeep->l == 0 && ieeep->h == 0)
  1302. return 0;
  1303. fr = ieeep->l & ((1L<<16)-1L);
  1304. fr /= 1L<<16;
  1305. fr += (ieeep->l>>16) & ((1L<<16)-1L);
  1306. fr /= 1L<<16;
  1307. fr += (ieeep->h & (1L<<20)-1L) | (1L<<20);
  1308. fr /= 1L<<21;
  1309. exp = (ieeep->h>>20) & ((1L<<11)-1L);
  1310. exp -= (1L<<10) - 2L;
  1311. return ldexp(fr, exp);
  1312. }
  1313. void
  1314. undefsym(Sym *s)
  1315. {
  1316. int n;
  1317. n = imports;
  1318. if(s->value != 0)
  1319. diag("value != 0 on SXREF");
  1320. if(n >= 1<<Rindex)
  1321. diag("import index %d out of range", n);
  1322. s->value = n<<Roffset;
  1323. s->type = SUNDEF;
  1324. imports++;
  1325. }
  1326. void
  1327. zerosig(char *sp)
  1328. {
  1329. Sym *s;
  1330. s = lookup(sp, 0);
  1331. s->sig = 0;
  1332. }
  1333. void
  1334. readundefs(char *f, int t)
  1335. {
  1336. int i, n;
  1337. Sym *s;
  1338. Biobuf *b;
  1339. char *l, buf[256], *fields[64];
  1340. if(f == nil)
  1341. return;
  1342. b = Bopen(f, OREAD);
  1343. if(b == nil){
  1344. diag("could not open %s: %r", f);
  1345. errorexit();
  1346. }
  1347. while((l = Brdline(b, '\n')) != nil){
  1348. n = Blinelen(b);
  1349. if(n >= sizeof(buf)){
  1350. diag("%s: line too long", f);
  1351. errorexit();
  1352. }
  1353. memmove(buf, l, n);
  1354. buf[n-1] = '\0';
  1355. n = getfields(buf, fields, nelem(fields), 1, " \t\r\n");
  1356. if(n == nelem(fields)){
  1357. diag("%s: bad format", f);
  1358. errorexit();
  1359. }
  1360. for(i = 0; i < n; i++){
  1361. s = lookup(fields[i], 0);
  1362. s->type = SXREF;
  1363. s->subtype = t;
  1364. if(t == SIMPORT)
  1365. nimports++;
  1366. else
  1367. nexports++;
  1368. }
  1369. }
  1370. Bterm(b);
  1371. }