comparison lwasm/pseudo.c @ 151:427e268e876b

renamed src to lwasm to better reflect its purpose
author lost
date Fri, 30 Jan 2009 04:01:55 +0000
parents src/pseudo.c@2ba8f9ef1417
children f0527dc3804d
comparison
equal deleted inserted replaced
150:f0881c115010 151:427e268e876b
1 /*
2 pseudo.c
3 Copyright © 2009 William Astle
4
5 This file is part of LWASM.
6
7 LWASM is free software: you can redistribute it and/or modify it under the
8 terms of the GNU General Public License as published by the Free Software
9 Foundation, either version 3 of the License, or (at your option) any later
10 version.
11
12 This program is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 more details.
16
17 You should have received a copy of the GNU General Public License along with
18 this program. If not, see <http://www.gnu.org/licenses/>.
19
20
21 This file implements the various pseudo operations.
22 */
23
24 #include <stdlib.h>
25 #include <string.h>
26 #include "lwasm.h"
27 #include "instab.h"
28 #include "expr.h"
29 #include "util.h"
30
31 extern int lwasm_read_file(asmstate_t *as, const char *filename);
32
33 OPFUNC(pseudo_org)
34 {
35 int v, r;
36
37 if (as -> csect)
38 {
39 register_error(as, l, 1, "ORG not allowed within sections");
40 return;
41 }
42
43 if (as -> passnum != 1)
44 {
45 // org is not needed to be processed on pass 2
46 // this will prevent phasing errors for forward references that
47 // resolve on the second pass
48 // we saved the org address in l -> codeaddr on pass 1
49 as -> addr = l -> codeaddr;
50 return;
51 }
52
53 if (l -> sym)
54 {
55 register_error(as, l, 1, "No symbol allowed with ORG");
56 }
57
58 r = lwasm_expr_result2(as, l, p, EXPR_PASS1CONST, &v, 0);
59 if (r != 0)
60 return;
61 l -> codeaddr = v;
62 l -> addrset = 1;
63 as -> addr = v;
64 }
65
66 /*
67 The operand for include is a string optionally enclosed in "
68 */
69 OPFUNC(pseudo_include)
70 {
71 int v1;
72 char *fn;
73
74 // only include files on pass 1
75 // but make sure local include context is right
76 // for the next line...
77 if (as -> passnum != 1)
78 {
79 as -> context = lwasm_next_context(as);
80 return;
81 }
82
83 while (**p && isspace(**p))
84 (*p)++;
85
86 if (!**p)
87 {
88 register_error(as, l, 1, "Bad file name");
89 return;
90 }
91
92 if (**p == '"')
93 {
94 // search for ending "
95 (*p)++;
96 for (v1 = 0; *((*p)+v1) && *((*p)+v1) != '"'; v1++)
97 /* do nothing */ ;
98 if (*((*p)+v1) != '"')
99 {
100 register_error(as, l, 1, "Bad file name");
101 return;
102 }
103 }
104 else
105 {
106 // search for a space type character
107 for (v1 = 0; *((*p)+v1) && !isspace(*((*p)+v1)); v1++)
108 ;
109 }
110
111 fn = lwasm_alloc(v1 + 1);
112 memcpy(fn, *p, v1);
113 fn[v1] = '\0';
114
115 // end local label context on include
116 as -> context = lwasm_next_context(as);
117 if (lwasm_read_file(as, fn) < 0)
118 {
119 register_error(as, l, 1, "File include error (%s)", fn);
120 }
121 lwasm_free(fn);
122 }
123
124 OPFUNC(pseudo_rmb)
125 {
126 int r, v;
127
128 if (as -> passnum == 2)
129 {
130 as -> addr += l -> nocodelen;
131 return;
132 }
133 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, -1);
134 if (r != 0)
135 return;
136 l -> nocodelen = v;
137 as -> addr += v;
138 }
139
140 OPFUNC(pseudo_rmd)
141 {
142 int r, v;
143
144 if (as -> passnum == 2)
145 {
146 as -> addr += l -> nocodelen;
147 return;
148 }
149 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
150 if (r != 0)
151 return;
152 v *= 2;
153 l -> nocodelen = v;
154 as -> addr += v;
155 }
156
157 OPFUNC(pseudo_rmq)
158 {
159 int r, v;
160
161 if (as -> passnum == 2)
162 {
163 as -> addr += l -> nocodelen;
164 return;
165 }
166 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
167 if (r != 0)
168 return;
169 v *= 4;
170 l -> nocodelen = v;
171 as -> addr += v;
172 }
173
174 OPFUNC(pseudo_zmb)
175 {
176 int r, v;
177
178 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
179 if (r != 0)
180 return;
181 while (v--)
182 lwasm_emit(as, l, 0);
183 }
184
185 OPFUNC(pseudo_zmd)
186 {
187 int r, v;
188
189 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
190 if (r != 0)
191 return;
192 v *= 2;
193 while (v--)
194 lwasm_emit(as, l, 0);
195 }
196
197 OPFUNC(pseudo_zmq)
198 {
199 int r, v;
200
201 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
202 if (r != 0)
203 return;
204 v *= 4;
205 while (v--)
206 lwasm_emit(as, l, 0);
207 }
208
209 OPFUNC(pseudo_end)
210 {
211 int r, v;
212 lwasm_expr_stack_t *s;
213
214
215 as -> endseen = 1;
216
217 // address only matters for DECB output
218 if (as -> outformat != OUTPUT_DECB)
219 return;
220
221 r = lwasm_expr_result2(as, l, p, 0, &v, 0);
222 if (r != 0)
223 {
224 register_error(as, l, 2, "Bad operand");
225 }
226
227 v = v & 0xffff;
228 if (as -> passnum == 2)
229 {
230 as -> execaddr = v;
231 l -> symaddr = v;
232 l -> addrset = 2;
233 }
234 }
235
236
237 OPFUNC(pseudo_align)
238 {
239 int cn;
240 int r, v;
241
242 if (as -> passnum == 2)
243 {
244 while (as -> addr < l -> symaddr)
245 lwasm_emit(as, l, 0);
246 return;
247 }
248
249 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
250 if (r != 0)
251 {
252 l -> symaddr = as -> addr;
253 return;
254 }
255
256 if (v < 1)
257 {
258 register_error(as, l, 1, "Illegal alignment %d", v);
259 return;
260 }
261
262 cn = l -> codeaddr % v;
263 if (cn)
264 cn = v - cn;
265
266 while (cn--)
267 {
268 lwasm_emit(as, l, 0);
269 }
270 l -> symaddr = as -> addr;
271 }
272
273 OPFUNC(pseudo_equ)
274 {
275 int r, v;
276
277 if (l -> sym == NULL)
278 {
279 register_error(as, l, 1, "No symbol specified");
280 return;
281 }
282
283 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
284 if (r < 0)
285 v = 0;
286
287 l -> symaddr = v & 0xFFFF;
288 l -> addrset = 2;
289
290 // note: we need to do this because the symbol might have resolved
291 // to a constant!
292 lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_FORCE);
293 }
294
295 OPFUNC(pseudo_set)
296 {
297 int r, v;
298
299 // set MUST run on both passes as the symbol value changes!
300
301 if (l -> sym == NULL)
302 {
303 register_error(as, l, 1, "No symbol specified");
304 return;
305 }
306
307 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
308 if (r < 0)
309 v = 0;
310
311 l -> symaddr = v & 0xFFFF;
312 l -> addrset = 2;
313
314 lwasm_register_symbol(as, l, l -> sym, v, (r > 0 ? SYMBOL_COMPLEX: SYMBOL_NORM) | SYMBOL_SET);
315 }
316
317 OPFUNC(pseudo_setdp)
318 {
319 int r, v;
320
321 if (as -> outformat == OUTPUT_OBJ)
322 {
323 register_error(as, l, 1, "SETDP not permitted with OBJ target");
324 return;
325 }
326
327 // setdp is needed on both passes; must resolve to a constant on pass 1
328 r = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v, 0);
329 if (r != 0)
330 return;
331
332 if (v < -127 || v > 255)
333 {
334 register_error(as, l, 1, "Byte overflow");
335 return;
336 }
337
338 l -> symaddr = v & 0xFF;
339 l -> addrset = 2;
340
341 as -> dpval = v & 0xFF;
342 }
343
344 OPFUNC(pseudo_fcc)
345 {
346 int delim = 0;
347
348 delim = **p;
349 if (!delim)
350 {
351 register_error(as, l, 1, "Bad operand");
352 return;
353 }
354 *p += 1;
355 while (**p && **p != delim)
356 {
357 lwasm_emit(as, l, **p);
358 (*p)++;
359 }
360 if (**p)
361 (*p)++;
362 }
363
364
365 OPFUNC(pseudo_fcs)
366 {
367 int delim = 0;
368
369 delim = **p;
370 if (!delim)
371 {
372 register_error(as, l, 1, "Bad operand");
373 return;
374 }
375 *p += 1;
376 while (**p && **p != delim)
377 {
378 if (!*((*p) + 1) || *((*p) + 1) == delim)
379 lwasm_emit(as, l, **p | 0x80);
380 else
381 lwasm_emit(as, l, **p);
382 (*p)++;
383 }
384 if (**p)
385 (*p)++;
386 }
387
388 OPFUNC(pseudo_fcn)
389 {
390 int delim = 0;
391
392 delim = **p;
393 if (!delim)
394 {
395 register_error(as, l, 1, "Bad operand");
396 return;
397 }
398 *p += 1;
399 while (**p && **p != delim)
400 {
401 lwasm_emit(as, l, **p);
402 (*p)++;
403 }
404 if (**p)
405 (*p)++;
406 lwasm_emit(as, l, 0);
407 }
408
409 // FIXME: handle external, etc., references in a useful manner
410 OPFUNC(pseudo_fcb)
411 {
412 int r, v;
413
414 fcb_again:
415 r = lwasm_expr_result2(as, l, p, 0, &v, -1);
416 if (r < 0)
417 return;
418
419 if (r > 0)
420 {
421 register_error(as, l, 2, "Illegal external or inter-segment reference");
422 v = 0;
423 }
424
425 if (v < -127 || v > 255)
426 {
427 register_error(as, l, 1, "Byte overflow");
428 }
429
430 lwasm_emit(as, l, v);
431 if (**p == ',')
432 {
433 (*p)++;
434 goto fcb_again;
435 }
436 }
437
438 // FIXME: handle external references in an intelligent way
439 OPFUNC(pseudo_fdb)
440 {
441 int r, v;
442 int extseen = 0;
443 char *p1;
444
445 fdb_again:
446 p1 = *p;
447 r = lwasm_expr_result2(as, l, p, 0, &v, -1);
448 if (r < 0)
449 return;
450
451 if (r > 0 && extseen == 1)
452 {
453 register_error(as, l, 2, "Illegal external or inter-segment reference (only 1 per FDB line)");
454 v = 0;
455 }
456 else if (r > 0)
457 {
458 l -> relocoff = as -> addr - l -> codeaddr;
459 *p = p1;
460 r = lwasm_expr_result2(as, l, p, 0, &v, 0);
461 }
462
463 lwasm_emit(as, l, v >> 8);
464 lwasm_emit(as, l, v & 0xff);
465 if (**p == ',')
466 {
467 (*p)++;
468 goto fdb_again;
469 }
470 }
471
472 // FIXME: handle external references in a sensible way
473 OPFUNC(pseudo_fqb)
474 {
475 int r, v;
476
477 fqb_again:
478 r = lwasm_expr_result2(as, l, p, 0, &v, -1);
479 if (r < 0)
480 return;
481
482 if (r > 0)
483 {
484 register_error(as, l, 2, "Illegal external or inter-segment reference");
485 v = 0;
486 }
487
488 lwasm_emit(as, l, v >> 24);
489 lwasm_emit(as, l, v >> 16);
490 lwasm_emit(as, l, v >> 8);
491 lwasm_emit(as, l, v & 0xff);
492 if (**p == ',')
493 {
494 (*p)++;
495 goto fqb_again;
496 }
497 }
498
499 // don't need to do anything if we are executing one of these
500 OPFUNC(pseudo_endc)
501 {
502 if (as -> skipcond && !(as -> skipmacro))
503 {
504 as -> skipcount -= 1;
505 if (as -> skipcount <= 0)
506 {
507 as -> skipcond = 0;
508 }
509 }
510 return;
511 }
512
513 // if "else" executes, we must be going into an "ignore" state
514 OPFUNC(pseudo_else)
515 {
516 if (as -> skipmacro)
517 return;
518
519 if (as -> skipcond)
520 {
521 if (as -> skipcount == 1)
522 {
523 as -> skipcount = 0;
524 as -> skipcond = 0;
525 }
526 return;
527 }
528
529 as -> skipcond = 1;
530 as -> skipcount = 1;
531 }
532
533 OPFUNC(pseudo_ifne)
534 {
535 int v1;
536 int rval;
537
538 if (as -> skipcond && !(as -> skipmacro))
539 {
540 as -> skipcount++;
541 return;
542 }
543
544 rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0);
545 if (rval != 0)
546 return;
547 if (!v1)
548 {
549 as -> skipcond = 1;
550 as -> skipcount = 1;
551 }
552 }
553
554 OPFUNC(pseudo_ifdef)
555 {
556 lwasm_symbol_ent_t *se;
557 char *sym;
558 char *p2;
559
560 if (as -> skipcond && !(as -> skipmacro))
561 {
562 as -> skipcount++;
563 return;
564 }
565
566 if (as -> passnum != 1)
567 {
568 if (!(l -> fsize))
569 {
570 as -> skipcond = 1;
571 as -> skipcount = 1;
572 }
573 return;
574 }
575
576 if (!**p)
577 {
578 register_error(as, l, 1, "Need symbol name");
579 return;
580 }
581
582 for (p2 = *p; *p2 && !isspace(*p2); p2++)
583 /* do nothing */ ;
584
585 sym = lwasm_alloc(p2 - *p + 1);
586 memcpy(sym, *p, p2 - *p);
587 sym[p2 - *p] = '\0';
588
589 *p = p2;
590
591 se = lwasm_find_symbol(as, sym, l -> context);
592 if (!se)
593 se = lwasm_find_symbol(as, sym, -1);
594
595 lwasm_free(sym);
596
597 if (!se)
598 {
599 as -> skipcond = 1;
600 as -> skipcount = 1;
601 l -> fsize = 0;
602 }
603 else
604 {
605 l -> fsize = 1;
606 }
607 }
608
609 OPFUNC(pseudo_ifndef)
610 {
611 lwasm_symbol_ent_t *se;
612 char *sym;
613 char *p2;
614
615 if (as -> skipcond && !(as -> skipmacro))
616 {
617 as -> skipcount++;
618 return;
619 }
620
621 if (as -> passnum != 1)
622 {
623 if (l -> fsize)
624 {
625 as -> skipcond = 1;
626 as -> skipcount = 1;
627 }
628 return;
629 }
630
631 if (!**p)
632 {
633 register_error(as, l, 1, "Need symbol name");
634 return;
635 }
636
637 for (p2 = *p; *p2 && !isspace(*p2); p2++)
638 /* do nothing */ ;
639
640 sym = lwasm_alloc(p2 - *p + 1);
641 memcpy(sym, *p, p2 - *p);
642 sym[p2 - *p] = '\0';
643
644 *p = p2;
645
646 se = lwasm_find_symbol(as, sym, l -> context);
647 if (!se)
648 se = lwasm_find_symbol(as, sym, -1);
649
650 lwasm_free(sym);
651
652 if (se)
653 {
654 as -> skipcond = 1;
655 as -> skipcount = 1;
656 l -> fsize = 0;
657 }
658 else
659 {
660 l -> fsize = 1;
661 }
662 }
663
664 OPFUNC(pseudo_ifeq)
665 {
666 int v1;
667 int rval;
668
669 if (as -> skipcond && !(as -> skipmacro))
670 {
671 as -> skipcount++;
672 return;
673 }
674
675 rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0);
676 if (rval != 0)
677 return;
678 if (v1)
679 {
680 as -> skipcond = 1;
681 as -> skipcount = 1;
682 }
683 }
684
685 OPFUNC(pseudo_iflt)
686 {
687 int v1;
688 int rval;
689
690 if (as -> skipcond && !(as -> skipmacro))
691 {
692 as -> skipcount++;
693 return;
694 }
695
696 rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0);
697 if (rval != 0)
698 return;
699 if (v1 >= 0)
700 {
701 as -> skipcond = 1;
702 as -> skipcount = 1;
703 }
704 }
705
706 OPFUNC(pseudo_ifle)
707 {
708 int v1;
709 int rval;
710
711 if (as -> skipcond && !(as -> skipmacro))
712 {
713 as -> skipcount++;
714 return;
715 }
716
717 rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0);
718 if (rval != 0)
719 return;
720 if (v1 > 0)
721 {
722 as -> skipcond = 1;
723 as -> skipcount = 1;
724 }
725 }
726
727 OPFUNC(pseudo_ifgt)
728 {
729 int v1;
730 int rval;
731
732 if (as -> skipcond && !(as -> skipmacro))
733 {
734 as -> skipcount++;
735 return;
736 }
737
738 rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0);
739 if (rval != 0)
740 return;
741 if (v1 <= 0)
742 {
743 as -> skipcond = 1;
744 as -> skipcount = 1;
745 }
746 }
747
748 OPFUNC(pseudo_ifge)
749 {
750 int v1;
751 int rval;
752
753 if (as -> skipcond && !(as -> skipmacro))
754 {
755 as -> skipcount++;
756 return;
757 }
758
759 rval = lwasm_expr_result2(as, l, p, EXPR_SECTCONST | EXPR_PASS1CONST, &v1, 0);
760 if (rval != 0)
761 return;
762 if (v1 < 0)
763 {
764 as -> skipcond = 1;
765 as -> skipcount = 1;
766 }
767 }
768
769 OPFUNC(pseudo_error)
770 {
771 register_error(as, l, 1, "User error: %s", *p);
772 }
773
774
775 OPFUNC(pseudo_section)
776 {
777 sectiontab_t *s;
778 char *p2;
779 char *sn;
780 char *opts;
781
782
783 if (as -> outformat != OUTPUT_OBJ)
784 {
785 register_error(as, l, 1, "Sections only supported for obj target");
786 return;
787 }
788
789 if (as -> csect)
790 {
791 as -> csect -> offset = as -> addr;
792 as -> csect = NULL;
793 }
794
795 if (!**p)
796 {
797 register_error(as, l, 1, "Need section name");
798 return;
799 }
800
801 for (p2 = *p; *p2 && !isspace(*p2); p2++)
802 /* do nothing */ ;
803
804 sn = lwasm_alloc(p2 - *p + 1);
805 memcpy(sn, *p, p2 - *p);
806 sn[p2 - *p] = '\0';
807
808 *p = p2;
809
810 opts = strchr(sn, ',');
811 if (opts)
812 {
813 *opts++ = '\0';
814 }
815
816 // have we seen the section name already?
817 for (s = as -> sections; s; s = s -> next)
818 {
819 if (!strcmp(s -> name, sn))
820 break;
821 }
822
823 if (s && as -> passnum == 1)
824 {
825 lwasm_free(sn);
826 if (opts)
827 {
828 register_error(as, l, 1, "Section options can only be specified the first time");
829 return;
830 }
831 }
832 else if (!s)
833 {
834 s = lwasm_alloc(sizeof(sectiontab_t));
835 s -> name = sn;
836 s -> offset = 0;
837 s -> flags = 0;
838 s -> obytes = NULL;
839 s -> oblen = 0;
840 s -> obsize = 0;
841 s -> rl = NULL;
842 s -> exports = NULL;
843 // parse options; only one "bss"
844 if (opts && as -> passnum == 1)
845 {
846 if (!strcasecmp(opts, "bss"))
847 {
848 s -> flags = SECTION_BSS;
849 }
850 else
851 {
852 register_error(as, l, 1, "Unrecognized section option '%s'", opts);
853 lwasm_free(s -> name);
854 lwasm_free(s);
855 return;
856 }
857 }
858
859 s -> next = as -> sections;
860 as -> sections = s;
861 }
862 as -> addr = s -> offset;
863 as -> csect = s;
864 as -> context = lwasm_next_context(as);
865 }
866
867 OPFUNC(pseudo_endsection)
868 {
869 if (as -> outformat != OUTPUT_OBJ)
870 {
871 register_error(as, l, 1, "Sections only supported for obj target");
872 return;
873 }
874
875 if (!(as -> csect))
876 {
877 register_error(as, l, 1, "ENDSECTION when not in a section");
878 return;
879 }
880
881 as -> csect -> offset = as -> addr;
882 as -> addr = 0;
883 as -> csect = 0;
884 as -> context = lwasm_next_context(as);
885 }
886
887 OPFUNC(pseudo_extern)
888 {
889 if (as -> passnum != 1)
890 return;
891
892 if (as -> outformat != OUTPUT_OBJ)
893 {
894 register_error(as, l, 1, "External references only supported for obj target");
895 return;
896 }
897
898 if (as -> csect)
899 {
900 register_error(as, l, 1, "Cannot declare external symbols within a section");
901 return;
902 }
903
904 lwasm_register_symbol(as, l, l -> sym, 0, SYMBOL_EXTERN);
905 }
906
907 OPFUNC(pseudo_export)
908 {
909 lwasm_symbol_ent_t *se;
910 export_list_t *ex;
911
912 if (as -> outformat != OUTPUT_OBJ)
913 {
914 register_error(as, l, 1, "Symbol exports only supported for obj target");
915 return;
916 }
917
918 if (as -> passnum == 1)
919 return;
920
921 // the symbol better be defined at this point (pass 2)
922 // local symbols cannot be exported nor can "global" symbols
923 se = lwasm_find_symbol(as, l -> sym, -1);
924 if (!se)
925 {
926 register_error(as, l, 2, "Exported symbols must be fully defined within a section");
927 return;
928 }
929 if (se -> sect == NULL)
930 {
931 register_error(as, l, 2, "Only non-local symbols within a section can be exported");
932 return;
933 }
934
935 if (se -> flags & SYMBOL_SET)
936 {
937 register_error(as, l, 2, "You cannot export symbols defined with SET");
938 return;
939 }
940
941 // if the symbol is not already a simple value, re-evaluate it
942 // and see if it becomes simple
943
944
945 if (se -> flags & SYMBOL_COMPLEX)
946 {
947 register_error(as, l, 2, "Exported symbols must be fully resolved on pass 2");
948 return;
949 }
950
951 // search for existing export
952 for (ex = se -> sect -> exports; ex; ex = ex -> next)
953 if (!strcmp(l -> sym, ex -> sym))
954 break;
955 if (ex)
956 {
957 register_error(as, l, 2, "Symbol %s already exported", l -> sym);
958 return;
959 }
960
961 // add an external reference
962 ex = lwasm_alloc(sizeof(export_list_t));
963 ex -> next = se -> sect -> exports;
964 se -> sect -> exports = ex;
965 ex -> offset = se -> value;
966 ex -> sym = lwasm_strdup(se -> sym);
967 }