fix comment in test/lnxhello.asm
[nasm.git] / rdoff / rdoff.c
blob43e3d65275039b93f9bd6e94680967adff7f9a8e
1 /* rdoff.c library of routines for manipulating rdoff files
3 * The Netwide Assembler is copyright (C) 1996 Simon Tatham and
4 * Julian Hall. All rights reserved. The software is
5 * redistributable under the licence given in the file "Licence"
6 * distributed in the NASM archive.
8 * Permission to use this file in your own projects is granted, as long
9 * as acknowledgement is given in an appropriate manner to its authors,
10 * with instructions of how to obtain a copy via ftp.
13 /* TODO: The functions in this module assume they are running
14 * on a little-endian machine. This should be fixed to
15 * make it portable.
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <errno.h>
22 #include "rdoff.h"
24 #define newstr(str) strcpy(malloc(strlen(str) + 1),str)
25 #define newstrcat(s1,s2) strcat(strcpy(malloc(strlen(s1) + strlen(s2) + 1), \
26 s1),s2)
29 * Comment this out to allow the module to read & write header record types
30 * that it isn't aware of. With this defined, unrecognised header records
31 * will generate error number 8, reported as 'unknown extended header record'.
34 #define STRICT_ERRORS
36 /* ========================================================================
37 * Code for memory buffers (for delayed writing of header until we know
38 * how long it is).
39 * ======================================================================== */
42 memorybuffer * newmembuf()
44 memorybuffer * t;
46 t = malloc(sizeof(memorybuffer));
47 if (!t) return NULL;
49 t->length = 0;
50 t->next = NULL;
51 return t;
54 void membufwrite(memorybuffer *const b, void *data, int bytes)
56 int16 w;
57 long l;
59 if (b->next) { /* memory buffer full - use next buffer */
60 membufwrite(b->next,data,bytes);
61 return;
64 if ((bytes < 0 && b->length - bytes > BUF_BLOCK_LEN)
65 || (bytes > 0 && b->length + bytes > BUF_BLOCK_LEN))
68 /* buffer full and no next allocated... allocate and initialise next
69 * buffer */
70 b->next = newmembuf();
71 membufwrite(b->next,data,bytes);
72 return;
75 switch(bytes) {
76 case -4: /* convert to little-endian */
77 l = * (long *) data ;
78 b->buffer[b->length++] = l & 0xFF;
79 l >>= 8 ;
80 b->buffer[b->length++] = l & 0xFF;
81 l >>= 8 ;
82 b->buffer[b->length++] = l & 0xFF;
83 l >>= 8 ;
84 b->buffer[b->length++] = l & 0xFF;
85 break;
87 case -2:
88 w = * (int16 *) data ;
89 b->buffer[b->length++] = w & 0xFF;
90 w >>= 8 ;
91 b->buffer[b->length++] = w & 0xFF;
92 break;
94 default:
95 while(bytes--) {
96 b->buffer[b->length++] = *(* (unsigned char **) &data);
98 (* (unsigned char **) &data)++ ;
100 break;
104 void membufdump(memorybuffer *b,FILE *fp)
106 if (!b) return;
108 fwrite (b->buffer, 1, b->length, fp);
110 membufdump(b->next,fp);
113 int membuflength(memorybuffer *b)
115 if (!b) return 0;
116 return b->length + membuflength(b->next);
119 void freemembuf(memorybuffer *b)
121 if (!b) return;
122 freemembuf(b->next);
123 free(b);
126 /* =========================================================================
127 General purpose routines and variables used by the library functions
128 ========================================================================= */
131 * translatelong() and translateshort()
133 * translate from little endian to local representation
135 long translatelong(long in)
137 long r;
138 unsigned char *i;
140 i = (unsigned char *)&in;
141 r = i[3];
142 r = (r << 8) + i[2];
143 r = (r << 8) + i[1];
144 r = (r << 8) + *i;
146 return r;
149 int16 translateshort(int16 in)
151 int16 r;
152 unsigned char * i;
154 i = (unsigned char *)&in;
155 r = (i[1] << 8) + i[0];
157 return r;
160 const char *RDOFFId = "RDOFF2"; /* written to the start of RDOFF files */
162 const char *rdf_errors[11] = {
163 "no error occurred","could not open file","invalid file format",
164 "error reading file","unknown error","header not read",
165 "out of memory", "RDOFF v1 not supported",
166 "unknown extended header record",
167 "header record of known type but unknown length",
168 "no such segment"};
170 int rdf_errno = 0;
172 /* ========================================================================
173 The library functions
174 ======================================================================== */
176 int rdfopen(rdffile *f, const char *name)
178 FILE * fp;
180 fp = fopen(name,"rb");
181 if (!fp) return rdf_errno = 1; /* error 1: file open error */
183 return rdfopenhere(f,fp,NULL,name);
186 int rdfopenhere(rdffile *f, FILE *fp, int *refcount, const char *name)
188 char buf[8];
189 long initpos;
190 long l;
191 int16 s;
193 if (translatelong(0x01020304) != 0x01020304)
194 { /* fix this to be portable! */
195 fputs("*** this program requires a little endian machine\n",stderr);
196 fprintf(stderr,"01020304h = %08lxh\n",translatelong(0x01020304));
197 exit(3);
200 f->fp = fp;
201 initpos = ftell(fp);
203 fread(buf,6,1,f->fp); /* read header */
204 buf[6] = 0;
206 if (strcmp(buf,RDOFFId)) {
207 fclose(f->fp);
208 if (!strcmp(buf,"RDOFF1"))
209 return rdf_errno = 7; /* error 7: RDOFF 1 not supported */
210 return rdf_errno = 2; /* error 2: invalid file format */
213 if (fread(&l,1,4,f->fp) != 4 ||
214 fread(&f->header_len,1,4,f->fp) != 4) {
215 fclose(f->fp);
216 return rdf_errno = 3; /* error 3: file read error */
219 f->header_ofs = ftell(f->fp);
220 f->eof_offset = f->header_ofs + translatelong(l) - 4;
222 if (fseek(f->fp,f->header_len,SEEK_CUR)) {
223 fclose(f->fp);
224 return rdf_errno = 2; /* seek past end of file...? */
227 if (fread(&s,1,2,f->fp) != 2) {
228 fclose(f->fp);
229 return rdf_errno = 3;
232 f->nsegs = 0;
234 while (s != 0)
236 f->seg[f->nsegs].type = s;
237 if (fread(&f->seg[f->nsegs].number,1,2,f->fp) != 2 ||
238 fread(&f->seg[f->nsegs].reserved,1,2,f->fp) != 2 ||
239 fread(&f->seg[f->nsegs].length,1,4,f->fp) != 4)
241 fclose(f->fp);
242 return rdf_errno = 3;
245 f->seg[f->nsegs].offset = ftell(f->fp);
246 if (fseek(f->fp,f->seg[f->nsegs].length,SEEK_CUR)) {
247 fclose(f->fp);
248 return rdf_errno = 2;
250 f->nsegs++;
252 if (fread(&s,1,2,f->fp) != 2) {
253 fclose(f->fp);
254 return rdf_errno = 3;
258 if (f->eof_offset != ftell(f->fp) + 8) /* +8 = skip null segment header */
260 fprintf(stderr, "warning: eof_offset [%ld] and actual eof offset "
261 "[%ld] don't match\n", f->eof_offset, ftell(f->fp) + 8);
263 fseek(f->fp,initpos,SEEK_SET);
264 f->header_loc = NULL;
266 f->name = newstr(name);
267 f->refcount = refcount;
268 if (refcount) (*refcount)++;
269 return 0;
272 int rdfclose(rdffile *f)
274 if (! f->refcount || ! --(*f->refcount))
276 fclose(f->fp);
277 f->fp = NULL;
279 free(f->name);
281 return 0;
284 void rdfperror(const char *app,const char *name)
286 fprintf(stderr,"%s:%s: %s\n",app,name,rdf_errors[rdf_errno]);
287 if (rdf_errno == 1 || rdf_errno == 3)
289 perror(app);
294 int rdffindsegment(rdffile * f, int segno)
296 int i;
297 for (i = 0; i < f->nsegs; i++)
298 if (f->seg[i].number == segno) return i;
299 return -1;
302 int rdfloadseg(rdffile *f,int segment,void *buffer)
304 long fpos;
305 long slen;
307 switch(segment) {
308 case RDOFF_HEADER:
309 fpos = f->header_ofs;
310 slen = f->header_len;
311 f->header_loc = (byte *)buffer;
312 f->header_fp = 0;
313 break;
314 default:
315 if (segment < f->nsegs) {
316 fpos = f->seg[segment].offset;
317 slen = f->seg[segment].length;
318 f->seg[segment].data = (byte *)buffer;
320 else {
321 return rdf_errno = 10; /* no such segment */
325 if (fseek(f->fp,fpos,SEEK_SET))
326 return rdf_errno = 4;
328 if (fread(buffer,1,slen,f->fp) != slen)
329 return rdf_errno = 3;
331 return 0;
334 /* Macros for reading integers from header in memory */
336 #define RI8(v) v = f->header_loc[f->header_fp++]
337 #define RI16(v) { v = (f->header_loc[f->header_fp] + \
338 (f->header_loc[f->header_fp+1] << 8)); \
339 f->header_fp += 2; }
341 #define RI32(v) { v = (f->header_loc[f->header_fp] + \
342 (f->header_loc[f->header_fp+1] << 8) + \
343 (f->header_loc[f->header_fp+2] << 16) + \
344 (f->header_loc[f->header_fp+3] << 24)); \
345 f->header_fp += 4; }
347 #define RS(str,max) { for(i=0;i<max;i++){\
348 RI8(str[i]); if (!str[i]) break;} str[i]=0; }
350 rdfheaderrec *rdfgetheaderrec(rdffile *f)
352 static rdfheaderrec r;
353 int i;
355 if (!f->header_loc) {
356 rdf_errno = 5;
357 return NULL;
360 if (f->header_fp >= f->header_len) return 0;
362 RI8(r.type);
363 RI8(r.g.reclen);
365 switch(r.type) {
366 case RDFREC_RELOC: /* Relocation record */
367 case RDFREC_SEGRELOC:
368 if (r.r.reclen != 8) {
369 rdf_errno = 9;
370 return NULL;
372 RI8(r.r.segment);
373 RI32(r.r.offset);
374 RI8(r.r.length);
375 RI16(r.r.refseg);
376 break;
378 case RDFREC_IMPORT: /* Imported symbol record */
379 case RDFREC_FARIMPORT:
380 RI16(r.i.segment);
381 RS(r.i.label,32);
382 break;
384 case RDFREC_GLOBAL: /* Exported symbol record */
385 RI8(r.e.flags);
386 RI8(r.e.segment);
387 RI32(r.e.offset);
388 RS(r.e.label,32);
389 break;
391 case RDFREC_DLL: /* DLL record */
392 RS(r.d.libname,127);
393 break;
395 case RDFREC_BSS: /* BSS reservation record */
396 if (r.r.reclen != 4) {
397 rdf_errno = 9;
398 return NULL;
400 RI32(r.b.amount);
401 break;
403 case RDFREC_MODNAME: /* Module name record */
404 RS(r.m.modname,127);
405 break;
407 case RDFREC_COMMON: /* Common variable */
408 RI16(r.c.segment);
409 RI32(r.c.size);
410 RI16(r.c.align);
411 RS(r.c.label,32);
412 break;
414 default:
415 #ifdef STRICT_ERRORS
416 rdf_errno = 8; /* unknown header record */
417 return NULL;
418 #else
419 for (i = 0; i < r.g.reclen; i++)
420 RI8(r.g.data[i]);
421 #endif
423 return &r;
426 void rdfheaderrewind(rdffile *f)
428 f->header_fp = 0;
432 rdf_headerbuf * rdfnewheader(void)
434 rdf_headerbuf * hb = malloc(sizeof(rdf_headerbuf));
435 if (hb == NULL) return NULL;
437 hb->buf = newmembuf();
438 hb->nsegments = 0;
439 hb->seglength = 0;
441 return hb;
444 int rdfaddheader(rdf_headerbuf * h, rdfheaderrec * r)
446 #ifndef STRICT_ERRORS
447 int i;
448 #endif
449 membufwrite(h->buf,&r->type,1);
450 membufwrite(h->buf,&r->g.reclen,1);
452 switch (r->type)
454 case RDFREC_GENERIC: /* generic */
455 membufwrite(h->buf, &r->g.data, r->g.reclen);
456 break;
457 case RDFREC_RELOC:
458 case RDFREC_SEGRELOC:
459 membufwrite(h->buf,&r->r.segment,1);
460 membufwrite(h->buf,&r->r.offset,-4);
461 membufwrite(h->buf,&r->r.length,1);
462 membufwrite(h->buf,&r->r.refseg,-2); /* 9 bytes written */
463 break;
465 case RDFREC_IMPORT: /* import */
466 case RDFREC_FARIMPORT:
467 membufwrite(h->buf,&r->i.segment,-2);
468 membufwrite(h->buf,&r->i.label,strlen(r->i.label) + 1);
469 break ;
471 case RDFREC_GLOBAL: /* export */
472 membufwrite(h->buf,&r->e.flags,1);
473 membufwrite(h->buf,&r->e.segment,1);
474 membufwrite(h->buf,&r->e.offset,-4);
475 membufwrite(h->buf,&r->e.label,strlen(r->e.label) + 1);
476 break ;
478 case RDFREC_DLL: /* DLL */
479 membufwrite(h->buf,&r->d.libname,strlen(r->d.libname) + 1);
480 break ;
482 case RDFREC_BSS: /* BSS */
483 membufwrite(h->buf,&r->b.amount,-4);
484 break ;
486 case RDFREC_MODNAME: /* Module name */
487 membufwrite(h->buf,&r->m.modname,strlen(r->m.modname) + 1);
488 break ;
490 default:
491 #ifdef STRICT_ERRORS
492 return (rdf_errno = 8);
493 #else
494 for (i = 0; i < r->g.reclen; i++)
495 membufwrite(h->buf, r->g.data[i], 1);
496 #endif
498 return 0;
501 int rdfaddsegment(rdf_headerbuf *h, long seglength)
503 h->nsegments ++;
504 h->seglength += seglength;
505 return 0;
508 int rdfwriteheader(FILE * fp, rdf_headerbuf * h)
510 long l, l2;
512 fwrite (RDOFFId, 1, strlen(RDOFFId), fp) ;
514 l = membuflength (h->buf);
515 l2 = l + 14 + 10*h->nsegments + h->seglength;
516 l = translatelong(l);
517 l2 = translatelong(l2);
518 fwrite (&l2, 4, 1, fp); /* object length */
519 fwrite (&l, 4, 1, fp); /* header length */
521 membufdump(h->buf, fp);
523 return 0; /* no error handling in here... CHANGE THIS! */
526 void rdfdoneheader(rdf_headerbuf * h)
528 freemembuf(h->buf);
529 free(h);