1 |
/* |
/* |
2 |
Copyright William Schelter. All rights reserved. |
Copyright William Schelter. All rights reserved. |
3 |
There is a companion file rsym.c which is used to build |
There is a companion file rsym.c which is used to build |
4 |
a list of the external symbols in a COFF or A.OUT object file, for |
a list of the external symbols in a COFF or A.OUT object file, for |
5 |
example saved_kcl. These are loaded into kcl, and the |
example saved_kcl. These are loaded into kcl, and the |
6 |
linking is done directly inside kcl. This saves a good |
linking is done directly inside kcl. This saves a good |
7 |
deal of time. For example a tiny file foo.o with one definition |
deal of time. For example a tiny file foo.o with one definition |
8 |
can be loaded in .04 seconds. This is much faster than |
can be loaded in .04 seconds. This is much faster than |
9 |
previously possible in kcl. |
previously possible in kcl. |
10 |
The function fasload from unixfasl.c is replaced by the fasload |
The function fasload from unixfasl.c is replaced by the fasload |
11 |
in this file. |
in this file. |
12 |
this file is included in unixfasl.c |
this file is included in unixfasl.c |
13 |
via #include "../c/sfasl.c" |
via #include "../c/sfasl.c\n" |
14 |
*/ |
*/ |
15 |
|
|
16 |
|
|
17 |
/* for testing in standalone manner define STAND |
/* for testing in standalone manner define STAND |
18 |
You may then compile this file cc -g -DSTAND -DDEBUG -I../hn |
You may then compile this file cc -g -DSTAND -DDEBUG -I../hn |
19 |
a.out /tmp/foo.o /public/gcl/unixport/saved_kcl /public/gcl/unixport/ |
a.out /tmp/foo.o /public/gcl/unixport/saved_kcl /public/gcl/unixport/ |
20 |
will write a /tmp/sfasltest file |
will write a /tmp/sfasltest file |
21 |
which you can use comp to compare with one produced by ld. |
which you can use comp to compare with one produced by ld. |
22 |
*/ |
*/ |
23 |
|
/*#define DEBUG*/ |
24 |
#define IN_SFASL |
#define IN_SFASL |
25 |
|
|
26 |
/* #ifdef STAND */ |
/* #ifdef STAND */ |
55 |
|
|
56 |
#ifdef DEBUG |
#ifdef DEBUG |
57 |
#define debug sfasldebug |
#define debug sfasldebug |
58 |
int sfasldebug=0; |
int sfasldebug=1; |
59 |
#define dprintf(s,ar) if(debug) { printf(" ( s )",ar) ; fflush(stdout);} |
#define dprintf(s,ar) if ( debug ) { fprintf ( stderr, ( s ), ar ) ; fflush(stderr); } |
60 |
#define STAT |
#define STAT |
61 |
|
|
62 |
#else /* end debug */ |
#else /* end debug */ |
63 |
#define dprintf(s,ar) |
#define dprintf(s,ar) |
64 |
#define STAT static |
#define STAT static |
65 |
#endif |
#endif |
70 |
#define PTABLE_EXTRA 20 |
#define PTABLE_EXTRA 20 |
71 |
|
|
72 |
struct sfasl_info { |
struct sfasl_info { |
73 |
struct syment *s_symbol_table; |
struct syment *s_symbol_table; |
74 |
char *s_start_address; |
char *s_start_address; |
75 |
char *s_start_data; |
char *s_start_data; |
76 |
char *s_my_string_table; |
char *s_my_string_table; |
77 |
int s_extra_bss; |
int s_extra_bss; |
78 |
char *s_the_start; |
char *s_the_start; |
|
|
|
79 |
}; |
}; |
80 |
|
|
81 |
struct sfasl_info *sfaslp; |
struct sfasl_info *sfaslp; |
82 |
|
|
83 |
#define symbol_table sfaslp->s_symbol_table |
#define symbol_table sfaslp->s_symbol_table |
86 |
#define extra_bss sfaslp->s_extra_bss |
#define extra_bss sfaslp->s_extra_bss |
87 |
#define the_start sfaslp->s_the_start |
#define the_start sfaslp->s_the_start |
88 |
|
|
89 |
|
#ifdef DEBUG |
90 |
|
|
91 |
|
#define describe_sym describe_sym1 |
92 |
|
void describe_sym1 ( int n, int aux_to_go ) |
93 |
|
{ |
94 |
|
char *str; |
95 |
|
char tem[9]; |
96 |
|
struct syment *sym; |
97 |
|
sym = &symbol_table[n]; |
98 |
|
if ( sym->n_zeroes == 0 ) { |
99 |
|
str = &my_string_table[sym->n_offset]; |
100 |
|
} else { |
101 |
|
if ( sym->n_name[SYMNMLEN -1] != 0 ) { |
102 |
|
/* MAKE IT NULL TERMINATED */ |
103 |
|
strncpy ( tem, sym->n_name, SYMNMLEN ); |
104 |
|
tem[SYMNMLEN] = '\0'; |
105 |
|
str = &tem[0]; |
106 |
|
} else { |
107 |
|
str = sym->n_name; |
108 |
|
} |
109 |
|
} |
110 |
|
if ( aux_to_go > 0 ) { |
111 |
|
fprintf ( stderr," symbol_table[%3d] (%8x): auxiliary entry (%d to go)\n", n, &symbol_table[n], aux_to_go - 1 ); |
112 |
|
} else { |
113 |
|
if ( sym->n_zeroes == 0 ) { |
114 |
|
fprintf ( stderr, |
115 |
|
"symbol_table[%3d] (%8x) (%22s): " |
116 |
|
"n_offset %d, n_value %d, n_scnum %d, n_type %d, " |
117 |
|
"n_sclass %d, n_numaux %d\n", |
118 |
|
n, |
119 |
|
&symbol_table[n], |
120 |
|
str, |
121 |
|
symbol_table[n].n_offset, |
122 |
|
symbol_table[n].n_value, |
123 |
|
symbol_table[n].n_scnum, |
124 |
|
symbol_table[n].n_type, |
125 |
|
symbol_table[n].n_sclass, |
126 |
|
symbol_table[n].n_numaux ); |
127 |
|
} else { |
128 |
|
fprintf ( stderr, |
129 |
|
"symbol_table[%3d] (%8x) (%22s): " |
130 |
|
"n_value %d, n_scnum %d, n_type %d, " |
131 |
|
"n_sclass %d, n_numaux %d\n", |
132 |
|
n, |
133 |
|
&symbol_table[n], |
134 |
|
str, |
135 |
|
symbol_table[n].n_value , |
136 |
|
symbol_table[n].n_scnum , |
137 |
|
symbol_table[n].n_type , |
138 |
|
symbol_table[n].n_sclass , |
139 |
|
symbol_table[n].n_numaux ); |
140 |
|
} |
141 |
|
} |
142 |
|
} |
143 |
|
#else |
144 |
|
# define describe_sym(a,b) |
145 |
|
#endif /* DEBUG */ |
146 |
|
|
|
#ifndef describe_sym |
|
|
#define describe_sym(a) |
|
|
#endif |
|
147 |
|
|
148 |
#ifdef STAND |
#ifdef STAND |
149 |
#include "rel_stand.c" |
#include "rel_stand.c" |
157 |
void relocate_symbols ( unsigned int length ); |
void relocate_symbols ( unsigned int length ); |
158 |
void set_symbol_address ( struct syment *sym, char *string ); |
void set_symbol_address ( struct syment *sym, char *string ); |
159 |
|
|
160 |
int |
int fasload ( object faslfile ) |
161 |
fasload(faslfile) |
{ |
162 |
object faslfile; |
long fasl_vector_start; |
163 |
{ long fasl_vector_start; |
struct filehdr fileheader; |
164 |
struct filehdr fileheader; |
struct sfasl_info sfasl_info_buf; |
|
struct sfasl_info sfasl_info_buf; |
|
165 |
#ifdef COFF |
#ifdef COFF |
166 |
struct scnhdr section[10]; |
struct scnhdr section[10]; |
167 |
struct aouthdr header; |
struct aouthdr header; |
168 |
#endif |
#endif |
169 |
int textsize, datasize, bsssize,nsyms; |
int textsize, datasize, bsssize, nsyms; |
170 |
#if defined ( READ_IN_STRING_TABLE ) || defined ( HPUX ) |
#if defined ( READ_IN_STRING_TABLE ) || defined ( HPUX ) |
171 |
int string_size=0; |
int string_size=0; |
172 |
#endif |
#endif |
173 |
|
|
174 |
object memory, data; |
object memory, data; |
175 |
FILE *fp; |
FILE *fp; |
176 |
char filename[MAXPATHLEN]; |
char filename[MAXPATHLEN]; |
177 |
int i; |
int i; |
178 |
int init_address=0; |
int init_address=0; |
179 |
|
int aux_to_go = 0; |
180 |
|
|
181 |
#ifndef STAND |
#ifndef STAND |
182 |
object *old_vs_base = vs_base; |
object *old_vs_base = vs_base; |
183 |
object *old_vs_top = vs_top; |
object *old_vs_top = vs_top; |
184 |
#endif |
#endif |
185 |
sfaslp = &sfasl_info_buf; |
sfaslp = &sfasl_info_buf; |
186 |
|
|
187 |
extra_bss=0; |
extra_bss=0; |
188 |
#ifdef STAND |
#ifdef STAND |
189 |
strcpy(filename,faslfile); |
strcpy(filename,faslfile); |
190 |
fp=fopen(filename,"r"); |
fp=fopen(filename,"r"); |
191 |
#else |
#else |
192 |
coerce_to_filename(faslfile, filename); |
coerce_to_filename(faslfile, filename); |
193 |
faslfile = open_stream(faslfile, smm_input, Cnil, sKerror); |
faslfile = open_stream(faslfile, smm_input, Cnil, sKerror); |
194 |
vs_push(faslfile); |
vs_push(faslfile); |
195 |
fp = faslfile->sm.sm_fp; |
fp = faslfile->sm.sm_fp; |
|
#endif |
|
|
|
|
|
HEADER_SEEK(fp); |
|
|
if(!fread((char *)&fileheader, sizeof(struct filehdr), 1, fp)) |
|
|
FEerror("Could not get the header",0,0); |
|
|
nsyms = NSYMS(fileheader); |
|
|
#ifdef COFF |
|
|
|
|
|
#ifdef AIX3 |
|
|
setup_for_aix_load(); |
|
196 |
#endif |
#endif |
197 |
|
|
198 |
fread(&header,1,fileheader.f_opthdr,fp); |
HEADER_SEEK(fp); |
199 |
|
if ( !fread ( (char *) &fileheader, sizeof(struct filehdr), 1, fp ) ) { |
200 |
|
FEerror("Could not get the header",0,0); |
201 |
|
} |
202 |
|
nsyms = NSYMS(fileheader); |
203 |
|
|
204 |
fread(§ion[1],fileheader.f_nscns,sizeof (struct scnhdr),fp); |
#ifdef COFF |
205 |
textsize = section[TEXT_NSCN].s_size; |
# ifdef AIX3 |
206 |
datasize = section[DATA_NSCN].s_size; |
setup_for_aix_load(); |
207 |
if (strcmp(section[BSS_NSCN].s_name, ".bss") == 0) |
# endif |
208 |
bsssize=section[BSS_NSCN].s_size; |
|
209 |
else bsssize=section[BSS_NSCN].s_size = 0; |
fread ( &header, 1, fileheader.f_opthdr, fp ); |
210 |
|
fread ( §ion[1], |
211 |
|
fileheader.f_nscns, |
212 |
|
sizeof ( struct scnhdr ), |
213 |
|
fp ); |
214 |
|
textsize = section[TEXT_NSCN].s_size; |
215 |
|
datasize = section[DATA_NSCN].s_size; |
216 |
|
if (strcmp(section[BSS_NSCN].s_name, ".bss") == 0) { |
217 |
|
bsssize=section[BSS_NSCN].s_size; |
218 |
|
} else { |
219 |
|
bsssize=section[BSS_NSCN].s_size = 0; |
220 |
|
} |
221 |
#endif |
#endif |
222 |
|
|
223 |
#ifdef BSD |
#ifdef BSD |
224 |
textsize=fileheader.a_text; |
textsize=fileheader.a_text; |
225 |
datasize=fileheader.a_data; |
datasize=fileheader.a_data; |
226 |
bsssize=fileheader.a_bss; |
bsssize=fileheader.a_bss; |
227 |
#endif |
#endif |
228 |
symbol_table = |
dprintf ( "fasload: %s, ", filename ); |
229 |
(struct syment *) OUR_ALLOCA(sizeof(struct syment)* |
dprintf ( "number of symbols: %d\n", nsyms ); |
230 |
(unsigned int)nsyms); |
|
231 |
fseek(fp,(int)( N_SYMOFF(fileheader)), 0); |
/* Allocate space for the symbol table */ |
232 |
{ |
symbol_table = |
233 |
for (i = 0; i < nsyms; i++) |
(struct syment *) OUR_ALLOCA( sizeof(struct syment)* |
234 |
{ fread((char *)&symbol_table[i], SYMESZ, 1, fp); |
(unsigned int)nsyms); |
235 |
dprintf( symbol table %d , i); |
memset ( symbol_table, 0, sizeof(struct syment) * (unsigned int)nsyms ); |
236 |
if (debug) describe_sym(i); |
/* move the file pointer to the start of the symbol table */ |
237 |
dprintf( at %d , &symbol_table[i]); |
fseek(fp,(int)( N_SYMOFF(fileheader)), 0); |
238 |
|
|
239 |
|
/* Read the symbol table */ |
240 |
|
for (i = 0; i < nsyms; i++) { |
241 |
|
fread((char *)&symbol_table[i], SYMESZ, 1, fp); |
242 |
#ifdef HPUX |
#ifdef HPUX |
243 |
symbol_table[i].n_un.n_strx = string_size; |
symbol_table[i].n_un.n_strx = string_size; |
244 |
dprintf(string_size %d, string_size); |
dprintf("string_size %d\n", string_size); |
245 |
string_size += symbol_table[i].n_length + 1; |
string_size += symbol_table[i].n_length + 1; |
246 |
fseek(fp,(int)symbol_table[i].n_length,1); |
fseek(fp,(int)symbol_table[i].n_length,1); |
247 |
#endif |
#endif |
248 |
} |
} |
249 |
} |
/* |
250 |
/* |
on MP386 |
251 |
on MP386 |
The sizeof(struct syment) = 20, while only SYMESZ =18. So we had to read |
252 |
The sizeof(struct syment) = 20, while only SYMESZ =18. So we had to read |
one at a time. |
253 |
one at a time. |
fread((char *)symbol_table, SYMESZ*fileheader.f_nsyms,1,fp); |
254 |
fread((char *)symbol_table, SYMESZ*fileheader.f_nsyms,1,fp); |
*/ |
|
*/ |
|
255 |
|
|
256 |
#ifdef READ_IN_STRING_TABLE |
#ifdef READ_IN_STRING_TABLE |
257 |
|
my_string_table=READ_IN_STRING_TABLE(fp,string_size); |
|
my_string_table=READ_IN_STRING_TABLE(fp,string_size); |
|
|
|
|
258 |
#else |
#else |
259 |
#ifdef MUST_SEEK_TO_STROFF |
# ifdef MUST_SEEK_TO_STROFF |
260 |
fseek(fp,N_STROFF(fileheader),0); |
fseek(fp,N_STROFF(fileheader),0); |
261 |
#endif |
# endif |
262 |
{int ii=0; |
{ |
263 |
if (!fread((char *)&ii,sizeof(int),1,fp)) |
int ii=0; |
264 |
{FEerror("The string table of this file did not have any length",0, |
if ( !fread ( (char *) &ii, sizeof(int), 1, fp ) ) { |
265 |
0);} |
FEerror ( "The string table of this file did not have any length", |
266 |
fseek(fp,-4,1); |
0, 0 ); |
267 |
/* at present the string table is located just after the symbols */ |
} |
268 |
my_string_table=OUR_ALLOCA((unsigned int)ii); |
fseek(fp,-4,1); |
269 |
dprintf( string table leng = %d, ii); |
/* at present the string table is located just after the symbols */ |
270 |
|
my_string_table = OUR_ALLOCA ( (unsigned int) ii ); |
271 |
if(ii!=fread(my_string_table,1,ii,fp)) |
memset ( my_string_table, 0, ii ); |
272 |
FEerror("Could not read whole string table",0,0) ; |
dprintf( " string table length = %d \n", ii); |
273 |
|
if ( ii != fread ( my_string_table, 1, ii, fp ) ) { |
274 |
|
FEerror ( "Could not read whole string table", 0, 0 ); |
275 |
} |
} |
276 |
#endif |
#endif |
277 |
|
#ifdef DEBUG |
278 |
|
/* Output the symbol table for debugging. |
279 |
|
* |
280 |
|
* Must do this after the string table has been read, |
281 |
|
* rather than while reading in the symbol table as |
282 |
|
* done previously. */ |
283 |
|
aux_to_go = 0; |
284 |
|
for (i = 0; i < nsyms; i++) { |
285 |
|
if ( aux_to_go <= 0 ) { |
286 |
|
aux_to_go = symbol_table[i].n_numaux; |
287 |
|
} |
288 |
|
if ( debug ) { |
289 |
|
describe_sym ( i, aux_to_go ); |
290 |
|
} |
291 |
|
if ( aux_to_go > 0 ) { |
292 |
|
aux_to_go--; |
293 |
|
} |
294 |
|
} |
295 |
|
#endif |
296 |
|
|
297 |
#ifdef SEEK_TO_END_OFILE |
#ifdef SEEK_TO_END_OFILE |
298 |
SEEK_TO_END_OFILE(fp); |
SEEK_TO_END_OFILE(fp); |
299 |
#else |
#else |
300 |
while ((i = getc(fp)) == 0) |
/* go past any zeroes */ |
301 |
; |
while ( ( i = getc ( fp ) ) == 0 ); |
302 |
ungetc(i, fp); |
ungetc(i, fp); |
303 |
#endif |
#endif |
304 |
|
/* point at the GCL fasl data */ |
305 |
fasl_vector_start=ftell(fp); |
fasl_vector_start=ftell(fp); |
306 |
|
|
307 |
if (!((c_table.ptable) && *(c_table.ptable))) |
if ( ! ( (c_table.ptable) && *(c_table.ptable) ) ) { |
308 |
build_symbol_table(); |
build_symbol_table(); |
309 |
|
} |
310 |
/* figure out if there is more bss space needed */ |
|
311 |
extra_bss=get_extra_bss(symbol_table,nsyms,datasize+textsize+bsssize, |
/* figure out if there is more bss space needed */ |
312 |
&init_address,bsssize); |
extra_bss = get_extra_bss ( symbol_table, |
313 |
|
nsyms, |
314 |
|
datasize+textsize+bsssize, |
315 |
|
&init_address, |
316 |
|
bsssize ); |
317 |
|
|
318 |
/* allocate some memory */ |
/* allocate some memory */ |
319 |
#ifndef STAND |
#ifndef STAND |
320 |
{BEGIN_NO_INTERRUPT; |
{ |
321 |
memory = alloc_object(t_cfdata); |
BEGIN_NO_INTERRUPT; |
322 |
memory->cfd.cfd_self = 0; |
memory = alloc_object ( t_cfdata ); |
323 |
memory->cfd.cfd_start = 0; |
memory->cfd.cfd_self = 0; |
324 |
memory->cfd.cfd_size = datasize+textsize+bsssize + extra_bss; |
memory->cfd.cfd_start = 0; |
325 |
vs_push(memory); |
memory->cfd.cfd_size = datasize + textsize + bsssize + extra_bss; |
326 |
the_start=start_address= |
vs_push(memory); |
327 |
memory->cfd.cfd_start = |
the_start = start_address = |
328 |
alloc_contblock(memory->cfd.cfd_size); |
memory->cfd.cfd_start = |
329 |
sfaslp->s_start_data = start_address + textsize; |
alloc_contblock ( memory->cfd.cfd_size ); |
330 |
END_NO_INTERRUPT; |
sfaslp->s_start_data = start_address + textsize; |
331 |
} |
END_NO_INTERRUPT; |
332 |
|
} |
333 |
#else |
#else |
334 |
the_start=start_address |
/* What does this mean? */ |
335 |
= malloc(datasize+textsize+bsssize + extra_bss + 0x80000); |
the_start = start_address |
336 |
the_start=start_address= (char *)( |
= malloc ( datasize + textsize + bsssize + extra_bss + 0x80000 ); |
337 |
0x1000* ((((int)the_start + 0x70000) + 0x1000)/0x1000)); |
the_start = start_address = (char *) ( 0x1000 * ( ( ( (int) the_start + 0x70000) + 0x1000) / 0x1000 ) ); |
338 |
sfaslp->s_start_data = start_address + textsize; |
sfaslp->s_start_data = start_address + textsize; |
|
|
|
339 |
#endif |
#endif |
340 |
|
dprintf(" Code size %d, ", datasize+textsize+bsssize + extra_bss); |
341 |
|
if ( fseek ( fp, N_TXTOFF(fileheader), 0) < 0 ) { |
342 |
|
FEerror("file seek error",0,0); |
343 |
|
} |
344 |
|
fread ( the_start, textsize + datasize, 1, fp ); |
345 |
|
dprintf("read %d bytes of text + data into memory at ", textsize + datasize ); |
346 |
|
/* relocate the actual loaded text */ |
347 |
|
|
348 |
dprintf( code size %d , datasize+textsize+bsssize + extra_bss); |
dprintf(" the_start (%x)\n", the_start); |
|
if (fseek(fp,N_TXTOFF(fileheader) ,0) < 0) |
|
|
FEerror("file seek error",0,0); |
|
|
fread(the_start, textsize + datasize, 1, fp); |
|
|
dprintf(read into memory text +data %d bytes, textsize + datasize); |
|
|
/* relocate the actual loaded text */ |
|
|
|
|
|
dprintf( the_start %x, the_start); |
|
349 |
|
|
350 |
/* record which symbols are used */ |
/* record which symbols are used */ |
351 |
|
|
352 |
#ifdef SYM_USED |
#ifdef SYM_USED |
353 |
{int j=0; |
{ |
354 |
for(j=1; j< BSS_NSCN ; j++) |
int j=0; |
355 |
{ dprintf( relocating section %d \n,j); |
for(j=1; j< BSS_NSCN ; j++) { |
356 |
if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0); |
dprintf(" relocating section %d \n",j); |
357 |
for(i=0; i < section[j].s_nreloc; i++) |
if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0); |
358 |
{ struct syment *sym; |
for(i=0; i < section[j].s_nreloc; i++) { |
359 |
fread(&relocation_info, RELSZ, 1, fp); |
struct syment *sym; |
360 |
sym = & symbol_table[relocation_info.r_symndx]; |
fread(&relocation_info, RELSZ, 1, fp); |
361 |
if (TC_SYMBOL_P(sym)) |
sym = & symbol_table[relocation_info.r_symndx]; |
362 |
SYM_USED(sym) = 1; |
if (TC_SYMBOL_P(sym)) { |
363 |
}}} |
SYM_USED(sym) = 1; |
364 |
|
} |
365 |
|
} |
366 |
|
} |
367 |
|
} |
368 |
#endif |
#endif |
|
|
|
|
|
|
369 |
/* this looks up symbols in c.ptable and also adds new externals to |
/* this looks up symbols in c.ptable and also adds new externals to |
370 |
that c.table */ |
that c.table */ |
371 |
relocate_symbols(NSYMS(fileheader)); |
relocate_symbols(NSYMS(fileheader)); |
372 |
|
|
373 |
#ifdef COFF |
#ifdef COFF |
374 |
{int j=0; |
{ |
375 |
for(j=1; j< BSS_NSCN ; j++) |
int j = 0; |
376 |
{ dprintf( relocating section %d \n,j); |
for ( j = 1; j < BSS_NSCN ; j++) { |
377 |
if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0); |
dprintf("relocating section %d \n",j); |
378 |
#ifdef ADJUST_RELOC_START |
if (section[j].s_nreloc) fseek(fp,section[j].s_relptr,0); |
379 |
ADJUST_RELOC_START(j) |
# ifdef ADJUST_RELOC_START |
380 |
#endif |
ADJUST_RELOC_START(j); |
381 |
for(i=0; i < section[j].s_nreloc; i++) |
# endif |
382 |
/* RELSZ = sizeof(relocation_info) */ |
for ( i=0; i < section[j].s_nreloc; i++ ) { |
383 |
{fread(&relocation_info, RELSZ, 1, fp); |
/* RELSZ = sizeof(relocation_info) */ |
384 |
dprintf(relocating %d,i); |
fread ( &relocation_info, RELSZ, 1, fp); |
385 |
relocate();}; |
dprintf ( " item %3d: ", i ); |
386 |
}}; |
relocate() ; |
387 |
|
} |
388 |
|
} |
389 |
|
} |
390 |
#endif |
#endif |
391 |
#ifdef BSD |
#ifdef BSD |
392 |
fseek(fp,N_RELOFF(fileheader),0); |
fseek(fp,N_RELOFF(fileheader),0); |
393 |
{int nrel = (fileheader.a_trsize/sizeof(struct reloc)); |
{ |
394 |
for (i=0; i < nrel; i++) |
int nrel = fileheader.a_trsize/sizeof(struct reloc); |
395 |
{fread((char *)&relocation_info, sizeof(struct reloc), |
for ( i=0; i < nrel; i++ ) { |
396 |
|
fread ( (char *)&relocation_info, sizeof(struct reloc), |
397 |
1, fp); |
1, fp); |
398 |
dprintf(relocating %d,i); |
dprintf("relocating %d\n",i); |
399 |
relocate(); |
relocate(); |
400 |
} |
} |
401 |
} |
} |
402 |
#ifdef N_DRELOFF |
# ifdef N_DRELOFF |
403 |
fseek (fp, N_DRELOFF(fileheader), 0); |
fseek (fp, N_DRELOFF(fileheader), 0); |
404 |
#endif |
# endif |
405 |
{int nrel = (fileheader.a_drsize/sizeof(struct reloc)); |
{ |
406 |
the_start += fileheader.a_text; |
int nrel = fileheader.a_drsize/sizeof(struct reloc); |
407 |
for (i=0; i < nrel; i++) |
the_start += fileheader.a_text; |
408 |
|
for (i=0; i < nrel; i++) { |
409 |
{fread((char *)&relocation_info, sizeof(struct reloc), |
fread ( (char *) &relocation_info, sizeof(struct reloc), |
410 |
1, fp); |
1, fp); |
411 |
dprintf(relocating %d,i); |
dprintf("relocating %d\n",i); |
412 |
relocate(); |
relocate(); |
413 |
} |
} |
414 |
} |
} |
415 |
#endif |
#endif |
416 |
|
|
417 |
/* end of relocation */ |
/* end of relocation */ |
418 |
dprintf( END OF RELOCATION \n,0); |
dprintf(" END OF RELOCATION \n",0); |
419 |
dprintf( invoking init function at %x, start_address) |
dprintf(" invoking init function at %x", start_address); |
420 |
dprintf( textsize is %x,textsize); |
dprintf(" textsize is %x",textsize); |
421 |
dprintf( datasize is %x,datasize); |
dprintf(" datasize is %x\n",datasize); |
422 |
|
|
423 |
/* read in the fasl vector */ |
/* read in the fasl vector */ |
424 |
fseek(fp,fasl_vector_start,0); |
fseek(fp,fasl_vector_start,0); |
425 |
if (feof(fp)) |
if ( feof ( fp ) ) { |
426 |
{data=0;} |
data=0; |
427 |
else{ |
} else { |
428 |
data = read_fasl_vector(faslfile); |
data = read_fasl_vector(faslfile); |
429 |
vs_push(data); |
vs_push(data); |
430 |
#ifdef COFF |
#ifdef COFF |
431 |
dprintf( read fasl now symbols %d , fileheader.f_nsyms); |
dprintf(" read fasl now symbols %d \n", fileheader.f_nsyms); |
432 |
#endif |
#endif |
433 |
} |
} |
434 |
close_stream(faslfile); |
close_stream(faslfile); |
435 |
|
|
|
/* |
|
|
{ |
|
|
int fd; |
|
|
|
|
|
fd = creat ("xsgcl.bits", 0777); |
|
|
write (fd, memory->cfd.cfd_start, textsize + datasize); |
|
|
close (fd); |
|
|
|
|
|
fd = open ("xsl2.bits", 0); |
|
|
read (fd, memory->cfd.cfd_start, memory->cfd.cfd_size); |
|
|
close (fd); |
|
|
} |
|
|
*/ |
|
|
|
|
436 |
#ifndef STAND |
#ifndef STAND |
437 |
ALLOCA_FREE(my_string_table); |
ALLOCA_FREE(my_string_table); |
438 |
ALLOCA_FREE(symbol_table); |
ALLOCA_FREE(symbol_table); |
439 |
|
# ifdef CLEAR_CACHE |
|
|
|
|
#ifdef CLEAR_CACHE |
|
440 |
CLEAR_CACHE; |
CLEAR_CACHE; |
441 |
#endif |
# endif |
442 |
call_init(init_address,memory,data,0); |
dprintf ( "About to call_init %x \n", init_address ); |
443 |
|
call_init ( init_address, memory, data, 0); |
444 |
|
dprintf ( "Finished call_init %x \n", memory ); |
445 |
|
|
446 |
vs_base = old_vs_base; |
vs_base = old_vs_base; |
447 |
vs_top = old_vs_top; |
vs_top = old_vs_top; |
448 |
if(symbol_value(sLAload_verboseA)!=Cnil) |
dprintf ( "About to symbol_value %x \n", data ); |
449 |
|
|
450 |
|
if ( symbol_value(sLAload_verboseA) != Cnil ) { |
451 |
printf("start address -T %x ", memory->cfd.cfd_start); |
printf("start address -T %x ", memory->cfd.cfd_start); |
452 |
return(memory->cfd.cfd_size); |
} |
453 |
|
return ( memory->cfd.cfd_size ); |
454 |
#endif |
#endif |
455 |
{FILE *out; |
{ |
456 |
out=fopen("/tmp/sfasltest","w"); |
FILE *out; |
457 |
fwrite((char *)&fileheader, sizeof(struct filehdr), 1, out); |
out=fopen("/tmp/sfasltest","w"); |
458 |
fwrite(start_address,sizeof(char),datasize+textsize,out); |
fwrite((char *)&fileheader, sizeof(struct filehdr), 1, out); |
459 |
fclose(out);} |
fwrite(start_address,sizeof(char),datasize+textsize,out); |
460 |
printf("\n(start %x)\n",start_address); |
fclose(out); |
461 |
|
} |
462 |
|
printf("\n(start %x)\n",start_address); |
463 |
|
} |
464 |
} |
} |
465 |
|
|
466 |
int get_extra_bss(sym_table,length,start,ptr,bsssize) |
int get_extra_bss(sym_table,length,start,ptr,bsssize) |
467 |
int length,bsssize; |
int length,bsssize; |
468 |
struct syment *sym_table; |
struct syment *sym_table; |
469 |
int *ptr; /* store init address offset here */ |
int *ptr; /* store init address offset here */ |
470 |
{ |
{ |
471 |
int result = start; |
int result = start; |
472 |
|
|
473 |
#ifdef AIX3 |
#ifdef AIX3 |
474 |
int next_bss = start - bsssize; |
int next_bss = start - bsssize; |
475 |
#endif |
#endif |
476 |
|
|
477 |
struct syment *end,*sym; |
struct syment *end,*sym; |
478 |
|
|
479 |
#ifdef BSD |
#ifdef BSD |
480 |
char tem[SYMNMLEN +1]; |
char tem[SYMNMLEN +1]; |
481 |
#endif |
#endif |
482 |
|
|
483 |
end =sym_table + length; |
end =sym_table + length; |
484 |
for(sym=sym_table; sym < end; sym++) |
for(sym=sym_table; sym < end; sym++) |
485 |
{ |
{ |
486 |
|
|
487 |
#ifdef FIND_INIT |
#ifdef FIND_INIT |
488 |
FIND_INIT |
FIND_INIT |
489 |
#endif |
#endif |
490 |
|
|
491 |
#ifdef AIX3 |
#ifdef AIX3 |
492 |
/* we later go through the relocation entries making this 1 |
/* we later go through the relocation entries making this 1 |
493 |
for symbols used */ |
for symbols used */ |
494 |
#ifdef SYM_USED |
#ifdef SYM_USED |
495 |
if(TC_SYMBOL_P(sym)) |
if(TC_SYMBOL_P(sym)) |
496 |
{SYM_USED(sym) = 0;} |
{SYM_USED(sym) = 0;} |
497 |
#endif |
#endif |
498 |
|
|
499 |
/* fix up the external refer to _ptrgl to be local ref */ |
/* fix up the external refer to _ptrgl to be local ref */ |
500 |
if (sym->n_scnum == 0 && |
if (sym->n_scnum == 0 && |
501 |
strcmp(sym->n_name,"_ptrgl")==0) |
strcmp(sym->n_name,"_ptrgl")==0) |
502 |
{struct syment* s = |
{struct syment* s = |
503 |
get_symbol("._ptrgl",TEXT_NSCN,sym_table,length); |
get_symbol("._ptrgl",TEXT_NSCN,sym_table,length); |
504 |
if (s ==0) FEerror("bad glue",0,0); |
if (s ==0) FEerror("bad glue",0,0); |
505 |
sym->n_value = next_bss ; |
sym->n_value = next_bss ; |
506 |
ptrgl_offset = next_bss; |
ptrgl_offset = next_bss; |
507 |
ptrgl_text = s->n_value; |
ptrgl_text = s->n_value; |
508 |
next_bss += 0xc; |
next_bss += 0xc; |
509 |
sym->n_scnum = DATA_NSCN; |
sym->n_scnum = DATA_NSCN; |
510 |
((union auxent *)(sym+1))->x_csect.x_scnlen = 0xc; |
((union auxent *)(sym+1))->x_csect.x_scnlen = 0xc; |
511 |
|
|
512 |
} |
} |
513 |
|
|
514 |
if(sym->n_scnum != BSS_NSCN) goto NEXT; |
if(sym->n_scnum != BSS_NSCN) goto NEXT; |
515 |
if(SYM_EXTERNAL_P(sym)) |
if(SYM_EXTERNAL_P(sym)) |
516 |
{int val=sym->n_value; |
{int val=sym->n_value; |
517 |
struct node joe; |
struct node joe; |
518 |
if (val && c_table.ptable) |
if (val && c_table.ptable) |
519 |
{struct node *answ; |
{struct node *answ; |
520 |
answ= find_sym(sym,0); |
answ= find_sym(sym,0); |
521 |
if(answ) |
if(answ) |
522 |
{sym->n_value = answ->address ; |
{sym->n_value = answ->address ; |
523 |
sym->n_scnum = N_UNDEF; |
sym->n_scnum = N_UNDEF; |
524 |
val= ((union auxent *)(sym+1))->x_csect.x_scnlen; |
val= ((union auxent *)(sym+1))->x_csect.x_scnlen; |
525 |
result -= val; |
result -= val; |
526 |
goto NEXT; |
goto NEXT; |
527 |
}} |
}} |
528 |
} |
} |
529 |
/* reallocate the bss space */ |
/* reallocate the bss space */ |
530 |
if (sym->n_value == 0) |
if (sym->n_value == 0) |
531 |
{result += ((union auxent *)(sym+1))->x_csect.x_scnlen;} |
{result += ((union auxent *)(sym+1))->x_csect.x_scnlen;} |
532 |
sym->n_value = next_bss; |
sym->n_value = next_bss; |
533 |
next_bss += ((union auxent *)(sym+1))->x_csect.x_scnlen; |
next_bss += ((union auxent *)(sym+1))->x_csect.x_scnlen; |
534 |
NEXT: |
NEXT: |
535 |
; |
; |
536 |
/* end aix3 */ |
/* end aix3 */ |
537 |
#endif |
#endif |
538 |
|
|
539 |
|
|
540 |
|
|
541 |
#ifdef BSD |
#ifdef BSD |
542 |
tem; /* ignored */ |
tem; /* ignored */ |
543 |
if(SYM_EXTERNAL_P(sym) && SYM_UNDEF_P(sym)) |
if(SYM_EXTERNAL_P(sym) && SYM_UNDEF_P(sym)) |
544 |
#endif |
#endif |
545 |
#ifdef COFF |
#ifdef COFF |
546 |
if(0) |
if(0) |
547 |
/* what we really want is |
/* what we really want is |
548 |
if (sym->n_scnum==0 && sym->n_sclass == C_EXT |
if (sym->n_scnum==0 && sym->n_sclass == C_EXT |
549 |
&& !(bsearch(..in ptable for this symbol))) |
&& !(bsearch(..in ptable for this symbol))) |
550 |
Since this won't allow loading in of a new external array |
Since this won't allow loading in of a new external array |
551 |
char foo[10] not ok |
char foo[10] not ok |
552 |
static foo[10] ok. |
static foo[10] ok. |
553 |
for the moment we give undefined symbol warning.. |
for the moment we give undefined symbol warning.. |
554 |
Should really go through the symbols, recording the external addr |
Should really go through the symbols, recording the external addr |
555 |
for ones found in ptable, and for the ones not in ptable |
for ones found in ptable, and for the ones not in ptable |
556 |
set some flag, and add up the extra_bss required. Then |
set some flag, and add up the extra_bss required. Then |
557 |
when you have the new memory chunk in hand, |
when you have the new memory chunk in hand, |
558 |
you could make the pass setting the relative addresses. |
you could make the pass setting the relative addresses. |
559 |
for the ones you flagged last time. |
for the ones you flagged last time. |
560 |
*/ |
*/ |
561 |
#endif |
#endif |
562 |
/* external bss so not included in size of bss for file */ |
/* external bss so not included in size of bss for file */ |
563 |
{int val=sym->n_value; |
{int val=sym->n_value; |
564 |
if (val && c_table.ptable |
if (val && c_table.ptable |
565 |
&& (0== find_sym(sym,0))) |
&& (0== find_sym(sym,0))) |
566 |
{ sym->n_value=result; |
{ sym->n_value=result; |
567 |
result += val;}} |
result += val;}} |
568 |
|
|
569 |
sym += NUM_AUX(sym); |
sym += NUM_AUX(sym); |
570 |
|
|
571 |
} |
} |
572 |
return (result-start); |
return (result-start); |
573 |
} |
} |
574 |
|
|
575 |
|
|
576 |
|
|
577 |
/* go through the symbol table changing the addresses of the symbols |
/* go through the symbol table changing the addresses of the symbols |
578 |
to reflect the current cfd_start */ |
to reflect the current cfd_start */ |
579 |
|
|
580 |
|
|
581 |
void |
void relocate_symbols ( unsigned int length ) |
582 |
relocate_symbols(length) |
{ |
583 |
unsigned int length; |
struct syment *end,*sym; |
584 |
{struct syment *end,*sym; |
unsigned int typ; |
585 |
unsigned int typ; |
char *str; |
586 |
char *str; |
char tem[SYMNMLEN +1]; |
587 |
char tem[SYMNMLEN +1]; |
tem[SYMNMLEN]=0; |
588 |
tem[SYMNMLEN]=0; |
end =symbol_table + length; |
589 |
end =symbol_table + length; |
for(sym=symbol_table; sym < end; sym++) { |
590 |
for(sym=symbol_table; sym < end; sym++) { |
typ=NTYPE(sym); |
|
typ=NTYPE(sym); |
|
591 |
#ifdef BSD |
#ifdef BSD |
592 |
#ifdef N_STAB |
# ifdef N_STAB |
593 |
if (N_STAB & sym->n_type) continue;/* skip: It is for dbx only */ |
if (N_STAB & sym->n_type) continue; /* skip: It is for dbx only */ |
594 |
#endif |
# endif |
595 |
typ=N_SECTION(sym); |
typ=N_SECTION(sym); |
596 |
/* if(sym->n_type & N_EXT) should add the symbol name, |
/* if(sym->n_type & N_EXT) should add the symbol name, |
597 |
so it would be accessible by future loads */ |
so it would be accessible by future loads */ |
598 |
#endif |
#endif |
599 |
switch (typ) { |
switch (typ) { |
600 |
#ifdef BSD |
#ifdef BSD |
601 |
case N_ABS : case N_TEXT: case N_DATA: case N_BSS: |
case N_ABS : case N_TEXT: case N_DATA: case N_BSS: |
602 |
#endif |
#endif |
603 |
#ifdef COFF |
#ifdef COFF |
604 |
#ifdef _WIN32 |
# ifdef _WIN32 |
605 |
case TEXT_NSCN: |
case TEXT_NSCN: |
606 |
sym->n_value = (int)start_address; |
sym->n_value = (int)start_address; |
607 |
break; |
break; |
608 |
case DATA_NSCN: |
case DATA_NSCN: |
609 |
sym->n_value = (int)sfaslp->s_start_data; |
sym->n_value = (int)sfaslp->s_start_data; |
610 |
break; |
break; |
611 |
case BSS_NSCN: |
case BSS_NSCN: |
612 |
#else /* _WIN32 */ |
# else /* _WIN32 */ |
613 |
case TEXT_NSCN : case DATA_NSCN: case BSS_NSCN : |
case TEXT_NSCN : case DATA_NSCN: case BSS_NSCN : |
614 |
#endif /* _WIN32 */ |
#endif /* _WIN32 */ |
615 |
#endif /* COFF */ |
#endif /* COFF */ |
616 |
str=SYM_NAME(sym); |
str=SYM_NAME(sym); |
617 |
dprintf( for sym %s ,str) |
dprintf(" for sym %s \n",str); |
618 |
dprintf( new value will be start %x, start_address); |
dprintf(" new value will be start %x\n", start_address); |
|
|
|
619 |
#ifdef AIX3 |
#ifdef AIX3 |
620 |
if(N_SECTION(sym) == DATA_NSCN |
if ( N_SECTION(sym) == DATA_NSCN |
621 |
&& NUM_AUX(sym) |
&& NUM_AUX(sym) |
622 |
&& allocate_toc(sym)) |
&& allocate_toc(sym) ) |
623 |
break; |
break; |
624 |
#endif |
#endif |
625 |
sym->n_value = (int)start_address; |
sym->n_value = (int)start_address; |
626 |
break; |
break; |
627 |
case N_UNDEF: |
case N_UNDEF: |
628 |
str=SYM_NAME(sym); |
str=SYM_NAME(sym); |
629 |
dprintf( undef symbol %s ,str); |
dprintf(" undef symbol %s \n",str); |
630 |
dprintf( symbol diff %d , sym - symbol_table); |
dprintf(" symbol diff %d \n", sym - symbol_table); |
631 |
describe_sym(sym-symbol_table); |
describe_sym ( sym-symbol_table, 0 ); |
632 |
set_symbol_address(sym,str); |
set_symbol_address(sym,str); |
633 |
describe_sym(sym-symbol_table); |
describe_sym ( sym-symbol_table, 0 ); |
634 |
break; |
break; |
635 |
default: |
default: |
636 |
#ifdef COFF |
#ifdef COFF |
637 |
dprintf(am ignoring a scnum %d,(sym->n_scnum)); |
dprintf("am ignoring a scnum %d\n",(sym->n_scnum)); |
638 |
#endif |
#endif |
639 |
break; |
break; |
640 |
} |
} |
641 |
sym += NUM_AUX(sym); |
sym += NUM_AUX(sym); |
642 |
} |
} |
643 |
} |
} |
644 |
|
|
645 |
/* |
/* |
646 |
STEPS: |
STEPS: |
647 |
1) read in the symbol table from the file, |
1) read in the symbol table from the file, |
648 |
2) go through the symbol table, relocating external entries. |
2) go through the symbol table, relocating external entries. |
649 |
3) for i <=2 go thru the relocation information for this section |
3) for i <=2 go thru the relocation information for this section |
650 |
relocating the text. |
relocating the text. |
651 |
4) done. |
4) done. |
652 |
*/ |
*/ |
653 |
|
|
654 |
struct node * |
struct node *find_sym ( struct syment *sym, char *name ) |
655 |
find_sym(sym,name) |
{ |
656 |
struct syment *sym; |
char tem[SYMNMLEN +1]; |
657 |
char *name; |
tem [SYMNMLEN] = 0; |
658 |
{ char tem[SYMNMLEN +1]; |
if (name==0) name = SYM_NAME(sym); |
659 |
tem [SYMNMLEN] = 0; |
return find_sym_ptable(name); |
660 |
if (name==0) name = SYM_NAME(sym); |
} |
661 |
return find_sym_ptable(name);} |
|
662 |
|
void set_symbol_address ( struct syment *sym, char *string ) |
663 |
void |
{ |
664 |
set_symbol_address(sym,string) |
struct node *answ; |
665 |
struct syment *sym; |
if ( c_table.ptable ) { |
666 |
char *string; |
dprintf("string %s\n", string); |
667 |
{struct node *answ; |
answ = find_sym(sym,string); |
668 |
if (c_table.ptable) |
dprintf("answ %d \n", (answ ? answ->address : -1) ); |
669 |
{ |
if ( answ ) { |
|
dprintf(string %s, string); |
|
|
answ = find_sym(sym,string); |
|
|
dprintf(answ %d , (answ ? answ->address : -1)); |
|
|
if(answ) |
|
|
{ |
|
670 |
#ifdef COFF |
#ifdef COFF |
671 |
#ifdef _AIX370 |
#ifdef _AIX370 |
672 |
if (NTYPE(sym) == N_UNDEF) |
if ( NTYPE(sym) == N_UNDEF ) |
673 |
sym->n_value = answ->address; |
sym->n_value = answ->address; |
674 |
else |
else |
675 |
#endif |
#endif |
676 |
sym->n_value = answ->address -sym->n_value; |
sym->n_value = answ->address -sym->n_value; |
677 |
/* for symbols in the local data,text and bss this gets added |
/* for symbols in the local data,text and bss this gets added |
678 |
on when we add the current value */ |
on when we add the current value */ |
679 |
#endif |
#endif |
680 |
#ifdef BSD |
#ifdef BSD |
681 |
/* the old value of sym->n_value is the length of the common area |
/* the old value of sym->n_value is the length of the common area |
682 |
starting at this address */ |
starting at this address */ |
683 |
sym->n_value = answ->address; |
sym->n_value = answ->address; |
684 |
#endif |
#endif |
685 |
#ifdef AIX3 |
#ifdef AIX3 |
686 |
fix_undef_toc_address(answ,sym,string); |
fix_undef_toc_address(answ,sym,string); |
687 |
#endif |
#endif |
688 |
|
|
689 |
} |
} else { |
690 |
else |
fprintf ( stdout,"undefined %s symbol", string ); |
691 |
{ |
fflush(stdout); |
692 |
/* |
} |
693 |
#ifdef BSD |
} else { |
694 |
{char *name; |
FEerror("symbol table not loaded",0,0); |
695 |
name=malloc(1+strlen(string)); |
} |
696 |
strcpy(name,string); |
} |
|
sym->n_value = sym->n_value + (unsigned int) the_start; |
|
|
add_symbol(name,sym->n_value,NULL); |
|
|
} |
|
|
#endif |
|
|
*/ |
|
|
fprintf(stdout,"undefined %s symbol",string) |
|
|
;fflush(stdout); |
|
|
|
|
|
}} |
|
|
|
|
|
else{FEerror("symbol table not loaded",0,0);}} |
|
697 |
|
|
698 |
/* include the machine independent stuff */ |
/* include the machine independent stuff */ |
699 |
#include "sfasli.c" |
#include "sfasli.c" |
700 |
|
|
|
|
|
701 |
#ifdef DEBUG |
#ifdef DEBUG |
702 |
print_name(p) |
void print_name ( struct syment *p ) |
703 |
struct syment *p; |
{ |
704 |
{char tem[10],*name; |
char tem[10], *name; |
705 |
name=SYM_NAME(p); |
name = SYM_NAME(p); |
706 |
name= (((p)->_n._n_n._n_zeroes == 0) ? |
name = (((p)->n_zeroes == 0) ? |
707 |
&my_string_table[(p)->_n._n_n._n_offset] : |
&my_string_table[(p)->n_offset] : |
708 |
((p)->_n._n_name[SYMNMLEN -1] ? |
((p)->n_name[SYMNMLEN -1] ? |
709 |
(strncpy(tem,(p)->_n._n_name, |
(strncpy(tem,(p)->n_name, |
710 |
SYMNMLEN), |
SYMNMLEN), |
711 |
(char *)tem) : |
(char *)tem) : |
712 |
(p)->_n._n_name )); |
(p)->n_name )); |
713 |
|
|
714 |
printf("(name:|%s|)",name); |
printf("(name:|%s|)",name); |
715 |
printf("(sclass 0x%x)",p->n_sclass); |
printf("(sclass 0x%x)",p->n_sclass); |
716 |
printf("(external_p 0x%x)",SYM_EXTERNAL_P(p)); |
#ifndef __MINGW32__ |
717 |
printf("(n_type 0x%x)",p->n_type); |
printf("(external_p 0x%x)",SYM_EXTERNAL_P(p)); |
718 |
printf("(n_value 0x%x)",p->n_value); |
#endif |
719 |
printf("(numaux 0x%x)\n",NUM_AUX(p)); |
printf("(n_type 0x%x)",p->n_type); |
720 |
fflush(stdout); |
printf("(n_value 0x%x)",p->n_value); |
721 |
|
printf("(numaux 0x%x)\n",NUM_AUX(p)); |
722 |
|
fflush(stdout); |
723 |
} |
} |
724 |
#endif |
#endif |
725 |
|
|