1 /* neatcc code generation */
7 static struct mem ds
; /* data segment */
8 static struct mem cs
; /* code segment */
9 static long bsslen
; /* bss segment size */
11 static long *loc_off
; /* offset of locals on the stack */
12 static long loc_n
, loc_sz
; /* number of locals */
13 static long loc_pos
; /* current stack position */
14 static int *loc_mem
; /* local memory was accessed */
15 static int *loc_ptr
; /* the address of this local is fetched */
16 static int *loc_dat
; /* the number of data accesses of this local */
18 static char (*ds_name
)[NAMELEN
];/* data section symbols */
19 static long *ds_off
; /* data section offsets */
20 static long ds_n
, ds_sz
; /* number of data section symbols */
22 static int func_argc
; /* number of arguments */
23 static int func_varg
; /* varargs */
24 static int func_regs
; /* used registers */
25 static int func_maxargs
; /* the maximum number of arguments on the stack */
26 static int func_leaf
; /* a leaf function */
27 static long *ic_luse
; /* the last use of values generated by instructions */
28 static long *ic_bbeg
; /* whether each instruction begins a basic block */
30 static long ra_vmap
[N_REGS
]; /* register to intermediate value assignments */
31 static long ra_lmap
[N_REGS
]; /* register to local assignments */
32 static long ra_lmapglob
[N_REGS
]; /* global register to local assignments */
33 static long *ra_gmask
; /* the mask of good registers for each value */
34 static long ra_live
[NTMPS
]; /* live values */
35 static int ra_vmax
; /* the number of values stored on the stack */
37 static long loc_add(long pos
)
39 if (loc_n
>= loc_sz
) {
40 loc_sz
= MAX(128, loc_sz
* 2);
41 loc_off
= mextend(loc_off
, loc_n
, loc_sz
, sizeof(loc_off
[0]));
47 long o_mklocal(long sz
)
49 loc_pos
+= ALIGN(sz
, ULNG
);
50 return loc_add(loc_pos
);
53 void o_rmlocal(long addr
, long sz
)
62 void o_bsnew(char *name
, long size
, int global
)
64 out_def(name
, OUT_BSS
| (global
? OUT_GLOB
: 0), bsslen
, size
);
65 bsslen
+= ALIGN(size
, OUT_ALIGNMENT
);
68 long o_dsnew(char *name
, long size
, int global
)
72 ds_sz
= MAX(128, ds_sz
* 2);
73 ds_name
= mextend(ds_name
, ds_n
, ds_sz
, sizeof(ds_name
[0]));
74 ds_off
= mextend(ds_off
, ds_n
, ds_sz
, sizeof(ds_off
[0]));
77 strcpy(ds_name
[idx
], name
);
78 ds_off
[idx
] = mem_len(&ds
);
79 out_def(name
, OUT_DS
| (global
? OUT_GLOB
: 0), mem_len(&ds
), size
);
80 mem_putz(&ds
, ALIGN(size
, OUT_ALIGNMENT
));
84 void o_dscpy(long addr
, void *buf
, long len
)
86 mem_cpy(&ds
, addr
, buf
, len
);
89 static int dat_off(char *name
)
92 for (i
= 0; i
< ds_n
; i
++)
93 if (!strcmp(name
, ds_name
[i
]))
98 void o_dsset(char *name
, long off
, long bt
)
100 long sym_off
= dat_off(name
) + off
;
101 long num
, roff
, rsym
;
102 if (!o_popnum(&num
)) {
103 mem_cpy(&ds
, sym_off
, &num
, T_SZ(bt
));
106 if (!o_popsym(&rsym
, &roff
)) {
107 out_rel(rsym
, OUT_DS
, sym_off
);
108 mem_cpy(&ds
, sym_off
, &roff
, T_SZ(bt
));
112 /* number of register arguments */
113 static int ic_regcnt(struct ic
*ic
)
117 return o
& (O_NUM
| O_SYM
| O_LOC
) ? 2 : 3;
119 return o
& (O_NUM
| O_SYM
| O_LOC
) ? 1 : 2;
121 return o
& (O_NUM
| O_SYM
| O_LOC
) ? 1 : 2;
123 return o
& (O_NUM
| O_SYM
| O_LOC
) ? 1 : 2;
131 return o
& (O_NUM
| O_SYM
| O_LOC
) ? 1 : 2;
134 if (o
& (O_LD
| O_ST
) && o
& (O_SYM
| O_LOC
))
136 if (o
& (O_LD
| O_ST
))
137 return o
& O_NUM
? 2 : 3;
141 static int ra_vreg(int val
)
144 for (i
= 0; i
< LEN(ra_vmap
); i
++)
145 if (ra_vmap
[i
] == val
)
150 static int ra_lreg(int loc
)
153 for (i
= 0; i
< LEN(ra_lmap
); i
++)
154 if (ra_lmap
[i
] == loc
)
159 /* find a register, with the given good, acceptable, and bad register masks */
160 static long ra_regget(long iv
, long gmask
, long amask
, long bmask
)
163 gmask
&= ~bmask
& amask
;
165 if (ra_vreg(iv
) >= 0 && (1 << ra_vreg(iv
)) & (gmask
| amask
))
167 for (i
= 0; i
< N_TMPS
; i
++)
168 if ((1 << tmpregs
[i
]) & gmask
&& ra_vmap
[tmpregs
[i
]] < 0 &&
169 ra_lmap
[tmpregs
[i
]] < 0)
171 for (i
= 0; i
< N_TMPS
; i
++)
172 if ((1 << tmpregs
[i
]) & amask
&& ra_vmap
[tmpregs
[i
]] < 0 &&
173 ra_lmap
[tmpregs
[i
]] < 0)
175 for (i
= 0; i
< N_TMPS
; i
++)
176 if ((1 << tmpregs
[i
]) & gmask
)
178 for (i
= 0; i
< N_TMPS
; i
++)
179 if ((1 << tmpregs
[i
]) & amask
)
181 die("neatcc: cannot allocate an acceptable register\n");
185 /* allocate registers for a 3-operand instruction */
186 static void ra_map(struct ic
*ic
, int *r0
, int *r1
, int *r2
, long *mt
)
190 int n
= ic_regcnt(ic
);
191 int oc
= O_C(ic
->op
);
197 /* optimizing loading locals: point to local's register */
198 if (oc
== (O_LD
| O_LOC
) && ra_lreg(ic
->arg1
) >= 0 &&
199 ra_vmap
[ra_lreg(ic
->arg1
)] < 0) {
200 *r0
= ra_lreg(ic
->arg1
);
201 func_regs
|= 1 << *r0
;
204 /* do not use argument registers to hold call destination */
206 for (i
= 0; i
< MIN(ic
->arg2
, N_ARGS
); i
++)
207 all
|= (1 << argregs
[i
]);
208 /* instructions on locals can be simplified */
212 if (oc
& (O_ST
| O_LD
))
213 oc
= (oc
& ~O_LOC
) & O_NUM
;
215 if (i_reg(ic
->op
, &m0
, &m1
, &m2
, mt
))
216 die("neatcc: instruction %08lx not supported\n", ic
->op
);
218 * the registers used in global register allocation should not
219 * be used in the last instruction of a basic block.
221 if (ic
->op
& (O_JZ
| O_JCC
))
222 for (i
= 0; i
< LEN(ra_lmap
); i
++)
223 if (ra_lmapglob
[i
] >= 0 && ra_lmap
[i
] != ra_lmapglob
[i
])
225 /* allocating registers for the operands */
227 *r2
= ra_regget(ic
->arg2
, m2
, m2
, all
);
231 *r1
= ra_regget(ic
->arg1
, m1
, m1
, all
);
235 int wop
= ic
->op
& O_OUT
;
236 if (wop
&& n
>= 3 && m0
& (1 << *r2
))
238 else if (wop
&& n
>= 2 && m0
& (1 << *r1
))
241 *r0
= ra_regget(ic
->arg0
, ra_gmask
[ic
->arg0
],
246 /* if r0 is overwritten and it is a local; use another register */
247 if (n
>= 1 && oc
& O_OUT
&& ra_lmap
[*r0
] >= 0) {
248 long m3
= (m0
? m0
: m1
) & ~(all
| (1 << *r0
));
249 long arg3
= m0
? ic
->arg0
: ic
->arg1
;
251 int r3
= ra_regget(arg3
, ra_gmask
[ic
->arg0
], m3
, 0);
252 if (n
>= 2 && *r0
== *r1
)
254 if (n
>= 3 && *r0
== *r2
)
261 func_regs
|= all
| *mt
;
264 static long iv_rank(long iv
)
267 for (i
= 0; i
< LEN(ra_live
); i
++)
268 if (ra_live
[i
] == iv
)
270 die("neatcc: the specified value is not live\n");
274 static long iv_addr(long rank
)
276 return loc_pos
+ rank
* ULNG
+ ULNG
;
279 static void loc_toreg(long loc
, long off
, int reg
, int bt
)
282 i_ins(O_MK(O_LD
| O_NUM
, bt
), reg
, REG_FP
, -loc_off
[loc
] + off
);
285 static void loc_tomem(long loc
, long off
, int reg
, int bt
)
288 i_ins(O_MK(O_ST
| O_NUM
, bt
), reg
, REG_FP
, -loc_off
[loc
] + off
);
291 static void loc_toadd(long loc
, long off
, int reg
)
294 i_ins(O_ADD
| O_NUM
, reg
, REG_FP
, -loc_off
[loc
] + off
);
297 static void val_toreg(long val
, int reg
)
299 i_ins(O_MK(O_LD
| O_NUM
, ULNG
), reg
, REG_FP
, -iv_addr(iv_rank(val
)));
302 static void val_tomem(long val
, int reg
)
304 long rank
= iv_rank(val
);
305 ra_vmax
= MAX(ra_vmax
, rank
+ 1);
306 i_ins(O_MK(O_ST
| O_NUM
, ULNG
), reg
, REG_FP
, -iv_addr(rank
));
309 /* move the value to the stack */
310 static void ra_spill(int reg
)
312 if (ra_vmap
[reg
] >= 0) {
313 val_tomem(ra_vmap
[reg
], reg
);
316 if (ra_lmap
[reg
] >= 0) {
317 if (ra_lmap
[reg
] == ra_lmapglob
[reg
])
318 loc_tomem(ra_lmap
[reg
], 0, reg
, ULNG
);
323 /* set the value to the given register */
324 static void ra_vsave(long iv
, int reg
)
328 for (i
= 0; i
< LEN(ra_live
); i
++)
331 if (i
== LEN(ra_live
))
332 die("neatcc: too many live values\n");
336 /* load the value into a register */
337 static void ra_vload(long iv
, int reg
)
339 if (ra_vmap
[reg
] == iv
)
341 if (ra_vmap
[reg
] >= 0 || ra_lmap
[reg
] >= 0)
343 if (ra_vreg(iv
) >= 0) {
344 i_ins(O_MK(O_MOV
, ULNG
), reg
, ra_vreg(iv
), 0);
345 ra_vmap
[ra_vreg(iv
)] = -1;
352 /* the value is no longer needed */
353 static void ra_vdrop(long iv
)
356 for (i
= 0; i
< LEN(ra_live
); i
++)
357 if (ra_live
[i
] == iv
)
359 if (ra_vreg(iv
) >= 0)
360 ra_vmap
[ra_vreg(iv
)] = -1;
363 /* load the value of local loc into register reg */
364 static void ra_lload(long loc
, long off
, int reg
, int bt
)
366 if (ra_lreg(loc
) < 0 && !loc_ptr
[loc
] && loc_dat
[loc
] > 2) {
368 loc_toreg(loc
, off
, reg
, bt
);
370 if (ra_lreg(loc
) >= 0) {
371 if (ra_lreg(loc
) != reg
)
372 i_ins(O_MK(O_MOV
, bt
), reg
, ra_lreg(loc
), 0);
374 loc_toreg(loc
, off
, reg
, bt
);
378 /* register reg contains the value of local loc */
379 static void ra_lsave(long loc
, long off
, int reg
, int bt
)
381 int lreg
= ra_lreg(loc
);
382 if (lreg
>= 0 && ra_lmapglob
[lreg
] == ra_lmap
[lreg
]) {
383 if (ra_vmap
[lreg
] >= 0) { /* values using the same register */
384 val_tomem(ra_vmap
[lreg
], lreg
);
387 i_ins(O_MK(O_MOV
, bt
), lreg
, reg
, 0);
391 loc_tomem(loc
, off
, reg
, bt
);
392 if (!loc_ptr
[loc
] && loc_dat
[loc
] > 2 && ra_lmap
[reg
] < 0)
397 /* end of a basic block */
398 static void ra_bbend(void)
401 /* save values to memory */
402 for (i
= 0; i
< LEN(ra_vmap
); i
++)
405 /* dropping local caches */
406 for (i
= 0; i
< LEN(ra_lmap
); i
++)
407 if (ra_lmap
[i
] != ra_lmapglob
[i
] && ra_lmap
[i
] >= 0)
409 /* load global register allocations from memory */
410 for (i
= 0; i
< LEN(ra_lmap
); i
++) {
411 if (ra_lmap
[i
] != ra_lmapglob
[i
]) {
412 ra_lmap
[i
] = ra_lmapglob
[i
];
413 loc_toreg(ra_lmap
[i
], 0, i
, ULNG
);
418 /* perform global register allocation */
419 static void ra_glob(struct ic
*ic
, int ic_n
)
425 mask
= func_leaf
? R_TMPS
: R_PERM
;
426 nregs
= MIN(N_TMPS
>> 1, 4);
427 srt
= malloc(loc_n
* sizeof(srt
[0]));
429 for (i
= 0; i
< loc_n
; i
++) {
430 for (j
= i
- 1; j
>= 0 && loc_dat
[i
] > loc_dat
[srt
[j
]]; j
--)
434 /* allocating registers */
435 for (i
= 0; i
< loc_n
&& nregs
> 0; i
++) {
439 if (func_leaf
&& l
< N_ARGS
&& l
< func_argc
&&
440 ra_lmapglob
[argregs
[l
]] < 0) {
441 ra_lmapglob
[argregs
[l
]] = l
;
447 for (j
= func_leaf
? 1 : 3; j
< N_TMPS
; j
++) {
449 if (ra_lmapglob
[r
] < 0 && (1 << r
) & mask
) {
459 /* return the values written to and read from in the given instruction */
460 static void ic_info(struct ic
*ic
, long **w
, long **r1
, long **r2
, long **r3
)
462 long n
= ic_regcnt(ic
);
463 long o
= ic
->op
& O_OUT
;
470 *r1
= n
>= 2 ? &ic
->arg1
: NULL
;
471 *r2
= n
>= 3 ? &ic
->arg2
: NULL
;
473 *r1
= n
>= 1 ? &ic
->arg0
: NULL
;
474 *r2
= n
>= 2 ? &ic
->arg1
: NULL
;
475 *r3
= n
>= 3 ? &ic
->arg2
: NULL
;
479 static void ra_init(struct ic
*ic
, int ic_n
)
484 ic_luse
= calloc(ic_n
, sizeof(ic_luse
[0]));
485 ic_bbeg
= calloc(ic_n
, sizeof(ic_bbeg
[0]));
486 ra_gmask
= calloc(ic_n
, sizeof(ra_gmask
[0]));
487 loc_mem
= calloc(loc_n
, sizeof(loc_mem
[0]));
489 for (i
= ic_n
- 1; i
>= 0; --i
) {
490 long *w
, *r1
, *r2
, *r3
;
491 ic_info(ic
+ i
, &w
, &r1
, &r2
, &r3
);
493 if (!w
|| ic
[i
].op
& O_CALL
)
497 if (r1
&& !ic_luse
[*r1
])
499 if (r2
&& !ic_luse
[*r2
])
501 if (r3
&& !ic_luse
[*r3
])
503 if (ic
[i
].op
& O_CALL
)
504 for (j
= 0; j
< ic
[i
].arg2
; j
++)
505 if (!ic_luse
[ic
[i
].args
[j
]])
506 ic_luse
[ic
[i
].args
[j
]] = i
;
509 for (i
= 0; i
< ic_n
; i
++) {
512 if (i
+ 1 < ic_n
&& ic
[i
].op
& (O_JXX
| O_RET
))
514 if (ic
[i
].op
& O_JXX
&& ic
[i
].arg2
< ic_n
)
515 ic_bbeg
[ic
[i
].arg2
] = 1;
518 for (i
= 0; i
< ic_n
; i
++) {
519 int n
= ic_regcnt(ic
+ i
);
523 i_reg(op
, &m0
, &m1
, &m2
, &mt
);
524 if (n
>= 1 && !(op
& O_OUT
))
525 ra_gmask
[ic
[i
].arg0
] = m0
;
527 ra_gmask
[ic
[i
].arg1
] = m1
;
529 ra_gmask
[ic
[i
].arg2
] = m2
;
531 for (j
= 0; j
< MIN(N_ARGS
, ic
[i
].arg2
); j
++)
532 ra_gmask
[ic
[i
].args
[j
]] = 1 << argregs
[j
];
534 /* loc_ptr and loc_dat */
535 loc_ptr
= calloc(loc_n
, sizeof(loc_ptr
[0]));
536 loc_dat
= calloc(loc_n
, sizeof(loc_dat
[0]));
537 loc_sz
= calloc(loc_n
, sizeof(loc_sz
[0]));
538 for (i
= 0; i
< ic_n
; i
++) {
539 long oc
= O_C(ic
[i
].op
);
542 if (oc
== (O_LD
| O_LOC
) || oc
== (O_ST
| O_LOC
)) {
543 int loc
= ic
[i
].arg1
;
544 int sz
= T_SZ(O_T(ic
[i
].op
));
547 if (ic
[i
].arg2
|| sz
< 2 || sz
!= loc_sz
[loc
])
552 if (oc
== (O_MOV
| O_LOC
))
553 loc_ptr
[ic
[i
].arg1
]++;
558 for (i
= 0; i
< ic_n
; i
++)
559 if (ic_luse
[i
] && ic
[i
].op
& O_CALL
)
562 for (i
= 0; i
< LEN(ra_vmap
); i
++)
565 for (i
= 0; i
< N_REGS
; i
++)
568 memcpy(ra_lmap
, ra_lmapglob
, sizeof(ra_lmap
));
570 for (i
= 0; i
< LEN(ra_lmapglob
); i
++)
571 if (ra_lmapglob
[i
] >= 0)
572 func_regs
|= (1 << i
);
574 for (i
= 0; i
< LEN(ra_live
); i
++)
580 static void ra_done(void)
590 static void ic_gencode(struct ic
*ic
, int ic_n
)
595 /* loading arguments in their allocated registers */
596 for (i
= 0; i
< LEN(ra_lmap
); i
++) {
597 int loc
= ra_lmap
[i
];
598 if (loc
>= 0 && loc
< func_argc
)
599 if (loc
>= N_ARGS
|| i
!= argregs
[loc
])
600 loc_toreg(loc
, 0, i
, ULNG
);
602 /* generating code */
603 for (i
= 0; i
< ic_n
; i
++) {
606 int n
= ic_regcnt(ic
+ i
);
610 ra_map(ic
+ i
, &r0
, &r1
, &r2
, &mt
);
612 int argc
= ic
[i
].arg2
;
613 int aregs
= MIN(N_ARGS
, argc
);
614 /* arguments passed via stack */
615 for (j
= argc
- 1; j
>= aregs
; --j
) {
616 int v
= ic
[i
].args
[j
];
617 int rx
= ra_vreg(v
) >= 0 ? ra_vreg(v
) : r0
;
619 i_ins(O_MK(O_ST
| O_NUM
, ULNG
), rx
, REG_SP
,
623 func_maxargs
= MAX(func_maxargs
, argc
- aregs
);
624 /* arguments passed via registers */
625 for (j
= aregs
- 1; j
>= 0; --j
)
626 ra_vload(ic
[i
].args
[j
], argregs
[j
]);
628 /* loading the operands */
629 if (n
>= 1 && !(oc
& O_OUT
))
630 ra_vload(ic
[i
].arg0
, r0
);
631 if (n
>= 2 && !(oc
& O_LOC
))
632 ra_vload(ic
[i
].arg1
, r1
);
634 ra_vload(ic
[i
].arg2
, r2
);
635 /* dropping values that are no longer used */
636 for (j
= 0; j
< LEN(ra_live
); j
++)
637 if (ra_live
[j
] >= 0 && ic_luse
[ra_live
[j
]] <= i
)
638 ra_vdrop(ra_live
[j
]);
639 /* saving values stored in registers that may change */
640 for (j
= 0; j
< N_REGS
; j
++)
643 /* overwriting a value that is needed later (unless loading a local to its register) */
644 if (n
>= 1 && oc
& O_OUT
)
645 if (oc
!= (O_LD
| O_LOC
) || ra_lmap
[r0
] != ic
[i
].arg1
||
648 /* before the last instruction of a basic block; for jumps */
649 if (i
+ 1 < ic_n
&& ic_bbeg
[i
+ 1] && oc
& O_JXX
)
651 /* performing the instruction */
653 i_ins(op
, r0
, r1
, oc
& O_NUM
? ic
[i
].arg2
: r2
);
655 i_ins(op
, r0
, r1
, r2
);
656 if (oc
== (O_LD
| O_NUM
))
657 i_ins(op
, r0
, r1
, ic
[i
].arg2
);
658 if (oc
== (O_LD
| O_LOC
))
659 ra_lload(ic
[i
].arg1
, ic
[i
].arg2
, r0
, O_T(op
));
660 if (oc
== (O_ST
| O_NUM
))
661 i_ins(op
, r0
, r1
, ic
[i
].arg2
);
662 if (oc
== (O_ST
| O_LOC
))
663 ra_lsave(ic
[i
].arg1
, ic
[i
].arg2
, r0
, O_T(op
));
667 i_ins(op
, r0
, r0
, 0);
668 if (oc
== (O_MOV
| O_NUM
))
669 i_ins(op
, r0
, ic
[i
].arg1
, 0);
670 if (oc
== (O_MOV
| O_LOC
))
671 loc_toadd(ic
[i
].arg1
, ic
[i
].arg2
, r0
);
672 if (oc
== (O_MOV
| O_SYM
))
673 i_ins(op
, r0
, ic
[i
].arg1
, ic
[i
].arg2
);
675 i_ins(op
, r0
, r1
, 0);
676 if (oc
== (O_CALL
| O_SYM
))
677 i_ins(op
, r0
, ic
[i
].arg1
, 0);
679 i_ins(op
, 0, 0, ic
[i
].arg2
);
681 i_ins(op
, r0
, 0, ic
[i
].arg2
);
683 i_ins(op
, r0
, oc
& O_NUM
? ic
[i
].arg1
: r1
, ic
[i
].arg2
);
685 i_ins(op
, r0
, r1
, r2
);
687 i_ins(op
, r0
, r1
, r2
);
688 /* saving back the output register */
690 ra_vsave(ic
[i
].arg0
, r0
);
691 /* after the last instruction of a basic block */
692 if (i
+ 1 < ic_n
&& ic_bbeg
[i
+ 1] && !(oc
& O_JXX
))
698 static void ic_reset(void)
709 void o_func_beg(char *name
, int argc
, int global
, int varg
)
716 for (i
= 0; i
< argc
; i
++)
717 loc_add(I_ARG0
+ -i
* ULNG
);
718 out_def(name
, (global
? OUT_GLOB
: 0) | OUT_CS
, mem_len(&cs
), 0);
721 void o_code(char *name
, char *c
, long c_len
)
723 out_def(name
, OUT_CS
, mem_len(&cs
), 0);
724 mem_put(&cs
, c
, c_len
);
727 void o_func_end(void)
732 long sargs_last
= -1;
735 long c_len
, *rsym
, *rflg
, *roff
, rcnt
;
736 int locs
= 0; /* accessing locals on the stack */
738 ic_get(&ic
, &ic_n
); /* the intermediate code */
739 ra_init(ic
, ic_n
); /* initialize register allocation */
740 ic_gencode(ic
, ic_n
); /* generating machine code */
741 /* deciding which arguments to save */
742 for (i
= 0; i
< func_argc
; i
++)
745 for (i
= 0; i
< N_ARGS
&& (func_varg
|| i
< sargs_last
); i
++)
746 sargs
|= 1 << argregs
[i
];
747 /* computing the amount of stack subtraction */
748 for (i
= 0; i
< loc_n
; i
++)
751 spsub
= (locs
|| ra_vmax
) ? loc_pos
+ ra_vmax
* ULNG
: 0;
752 for (i
= 0; i
< N_TMPS
; i
++)
753 if (((1 << tmpregs
[i
]) & func_regs
& R_PERM
) != 0)
756 spsub
+= func_maxargs
* ULNG
;
757 /* adding function prologue and epilogue */
758 i_wrap(func_argc
, sargs
, spsub
, spsub
|| locs
|| !func_leaf
,
759 func_regs
& R_PERM
, -sregs_pos
);
761 i_code(&c
, &c_len
, &rsym
, &rflg
, &roff
, &rcnt
);
762 for (i
= 0; i
< rcnt
; i
++) /* adding the relocations */
763 out_rel(rsym
[i
], rflg
[i
], roff
[i
] + mem_len(&cs
));
764 mem_put(&cs
, c
, c_len
); /* appending function code */
769 for (i
= 0; i
< ic_n
; i
++)
770 if (ic
[i
].op
& O_CALL
)
779 out_write(fd
, mem_buf(&cs
), mem_len(&cs
), mem_buf(&ds
), mem_len(&ds
));