Subversion Repositories shark

Rev

Rev 1618 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
1051 tullio 1
////////////////////////////////////////////////////////////////////////
2
//      elf.c
3
//
4
//  DynaLink for S.H.A.R.K
5
//  Dynamic ELF object linker.
6
//  
7
//  Original code written by Luca Abeni.
8
//  Adapted by Lex Nahumury 19-7-2006.
9
//  
10
//  This is free software; see GPL.txt
11
//////////////////////////////////////////////////////////////////////// 
12
#include "kernel/kern.h"
13
#include <kernel/func.h>
14
#include <stdlib.h>
15
#include <stdio.h>
16
#include <string.h>
17
#include <math.h>
18
 
19
#include <ll/i386/hw-data.h>
20
#include <ll/i386/mem.h>
21
#include <ll/i386/hw-instr.h>
22
#include <ll/i386/cons.h>
23
#include <ll/i386/error.h>
24
#include <ll/i386/mem.h>
1621 fabio 25
#include <arch/ctype.h>
1051 tullio 26
#include <ll/i386/x-bios.h>
27
 
28
#include "format.h"
29
#include "elf.h"
30
 
31
 
32
//#define __ELF_DEBUG__
33
 
34
char elf_signature[] = "\177ELF";
35
 
36
DWORD ELF_read_headers( struct file_ops *kf,
37
                                                struct table_info *tables)
38
{
39
        //printk("ELF_read_headers\n");
40
  int res;
41
 
42
  DWORD entry;
43
  struct elf_header header;
44
  struct elf_section_header h;
45
 
46
  kf->file_seek(kf->file_offset + 0, kf->seek_set);
47
  kf->file_read(&header, sizeof(struct elf_header));
48
 
49
  if (memcmp(header.e_ident, elf_signature, 4)) {
50
    printk("Not an ELF file\n");
51
    printk("Wrong signature: 0x%lx)!!!\n",
52
        *(DWORD *)header.e_ident);
53
    return 0;
54
  }    
55
        //printk("ELF signature OK\n");
56
 
57
  tables->flags = 0;
58
  if (header.e_ident[4] != ELFCLASS32) {
59
    printk("Wrong ELF class\n");
60
    printk("Class: 0x%x!!!\n", header.e_ident[4]);
61
    return 0;
62
  }
63
        //printk("ELF Class OK\n");
64
 
65
  if (header.e_ident[5] != ELFDATA2LSB) {
66
    printk("Wrong data ordering (not LSB)\n");
67
    printk("Ordering: 0x%x!!!\n", header.e_ident[5]);
68
    return 0;
69
  }
70
        //printk("ELF data ordering OK\n");
71
 
72
#ifdef __ELF_DEBUG__
73
  if(header.e_machine != EM_386)
74
  {
75
    printk("Warning: machine = 0x%x!!!\n", header.e_machine);
76
  }  
77
#endif
78
        //printk("ELF Type: 0x%x\n", header.e_type);
79
 
80
  if(header.e_shoff != 0)
81
  {
82
#ifdef __ELF_DEBUG__
83
    printk("Section headers @ %ld\n", header.e_shoff);
84
    printk("Number of sections: %d\n", header.e_shnum);
85
    printk("Section header size: %d (0x%x)\n",
86
                header.e_shentsize, header.e_shentsize);
87
#endif
88
    tables->section_header = header.e_shoff;
89
    tables->section_header_size = header.e_shentsize;
90
    tables->num_sections = header.e_shnum;
91
  }
92
 
93
#ifdef __ELF_DEBUG__
94
  if (header.e_phoff != 0) {
95
    printk("Program header table @ %ld\n", header.e_phoff);
96
    printk("Number of segments: %d\n", header.e_phnum);
97
    printk("Segment header size: %d (0x%x)\n",
98
                header.e_phentsize, header.e_phentsize);
99
  }
100
 
101
 
102
#ifdef __ELF_DEBUG__
103
  /* Flags... */
104
  /* RELOCATION */
105
  if (header.f_flags & F_RELFLG) {
106
    printk("No relocation info!\n");
107
  }
108
 
109
  if (header.f_flags & F_EXEC) {
110
    printk("Executable file (no unresolved symbols)\n");
111
  }
112
 
113
  if (header.f_flags & F_LNNO) {
114
    printk("No line numbers!\n");
115
  }
116
 
117
  if (header.f_flags & F_LSYMS) {
118
    printk("No local symbols!\n");
119
  }
120
 
121
  if (header.f_flags & F_AR32WR) {
122
    printk("32-bit little endian!\n");
123
  } else {
124
    printk("File type?\n");
125
  }
126
#endif
127
 
128
  printk("Section Name String Table is section number %d\n",
129
                header.e_shstrndx);
130
#endif
131
  if (header.e_shstrndx > tables->num_sections)
132
  {
133
    printk("Error: SNST number > section number...\n");
134
    return 0;
135
  }
136
 
137
  res = kf->file_seek( kf->file_offset + tables->section_header +
138
                  header.e_shstrndx * tables->section_header_size,
139
                  kf->seek_set);
140
  if (res < 0) {
141
    printk("Cannot seek");
142
    return 0;
143
  }
144
        //printk("ELF file seek OK\n");
145
 
146
  res = kf->file_read( &h, sizeof(struct elf_section_header));
147
  if (res < 0) {
148
    printk("Cannot read");
149
    return 0;
150
  }
151
        //printk("ELF file read OK\n");
152
 
153
  tables->section_names = 0;
154
  if(h.sh_size != 0)
155
  {
156
    //printk("ELF Loading Section Names...\n");
157
 
158
        tables->section_names = (void *)malloc(h.sh_size);
159
    if (tables->section_names == NULL)
160
        {
161
      printk("Failed to allocate space for section names...\n");
162
      return 0;
163
    }
164
 
165
    res = kf->file_seek( kf->file_offset + h.sh_offset, kf->seek_set);
166
    if (res < 0) {
167
      printk("Cannot seek");
168
      return 0;
169
    }
170
    res = kf->file_read( tables->section_names, h.sh_size);
171
    if (res < 0) {
172
      printk("Cannot read");
173
      return 0;
174
    }
175
    tables->section_names_size = h.sh_size;
176
  }
177
  else
178
  {
179
    printk("0 size?\n");
180
    tables->section_names_size = 0;
181
  }
182
 
183
  entry = header.e_entry;
184
  if (entry == 0) {
185
    tables->flags |= NO_ENTRY;
186
    tables->flags |= NEED_LOAD_RELOCATABLE;
187
    tables->flags |= NEED_SECTION_RELOCATION;
188
  }
189
        //printk("ELF Read headers Done!\n");
190
  return entry;
191
};
192
 
193
 
194
int ELF_read_section_headers(struct file_ops *kf,
195
                                                        struct table_info *tables,
196
                                                        struct section_info *scndata)
197
{
198
 
199
  int bss = -1;
200
  int i, j;
201
  struct elf_section_header h;
202
  int header_size;
203
  int stringtable = -1;
204
  struct elf_rel_info r;
205
 
206
  header_size = tables->section_header_size;
207
  if(header_size > sizeof(struct elf_section_header))
208
  {
209
    printk("Section header size (%d) > sizeof(struct section_header) (%d)\n",
210
                header_size, (int)(sizeof(struct elf_section_header))  );
211
 
212
    header_size = sizeof(struct elf_section_header);
213
  }
214
 
215
  for (i = 0; i < tables->num_sections; i++)
216
  {
217
    kf->file_seek( kf->file_offset + tables->section_header +
218
                                        i * tables->section_header_size, kf->seek_set);
219
    kf->file_read( &h, sizeof(struct elf_section_header));
220
 
221
#ifdef __ELF_DEBUG__
222
    printk("Section %d: ", i);
223
    printk("Flags 0x%x: \n", h.sh_flags);
224
#endif
225
    /*
226
       Set this stuff to 0...
227
       If size == 0 the section must not be loaded
228
     */
229
    scndata[i].num_reloc = 0;
230
    scndata[i].base = 0;
231
    scndata[i].size = 0;
232
    scndata[i].fileptr = 0;
233
    scndata[i].filesize = 0;
234
 
235
    /* If this is a NULL section, skip it!!! */
236
    if (h.sh_type != SHT_NULL) {
237
      if (tables->section_names != 0) {
238
#ifdef __ELF_DEBUG__
239
        printk("[%s]", tables->section_names + h.sh_name);
240
#endif
241
        if (strcmp(tables->section_names + h.sh_name, ".bss") == 0) {
242
          bss = i;
243
        }
244
      }
245
#ifdef __ELF_DEBUG__
246
      printk("    <0x%lx:0x%lx> (0x%lx)\n",
247
          h.sh_addr,
248
          h.sh_addr + h.sh_size,
249
          h.sh_offset);
250
#endif
251
 
252
      if (h.sh_type == SHT_REL) {
253
#ifdef __ELF_DEBUG__
254
        printk("\t\tSection %d: relocation info!!!\n", i);
255
        printk("\t\tSymbol table: section number %lu\n", h.sh_link);
256
        printk("\t\tSection to modify: %lu\n", h.sh_info);
257
        printk("\t\tNumber of relocation entries: %lu\n",
258
                        h.sh_size / h.sh_entsize);
259
#endif
260
        if (scndata[h.sh_info].num_reloc != 0) {
261
          printk("Double relocation for section\n");
262
          printk("%lu?\n", h.sh_info);
263
          return 0;
264
        }
265
        /* So, ...let's load it!!! */
266
        scndata[h.sh_info].num_reloc = h.sh_size / h.sh_entsize;
267
        //scndata[h.sh_info].reloc = (void *)kf->mem_alloc((h.sh_size / h.sh_entsize) * sizeof(struct reloc_info));
268
                scndata[h.sh_info].reloc = (void *)malloc((h.sh_size / h.sh_entsize) * sizeof(struct reloc_info));
269
        if (scndata[h.sh_info].reloc == NULL) {
270
          printk("Failed to allocate space for relocation info...\n");
271
          return 0;
272
        }
273
                        //printk("ELF Allocate space for relocation info OK!\n");
274
 
275
        for (j = 0; j < h.sh_size / h.sh_entsize; j++) {
276
          kf->file_seek( kf->file_offset + h.sh_offset + j * h.sh_entsize,
277
                          kf->seek_set);
278
          kf->file_read( &r, sizeof(struct elf_rel_info));
279
          scndata[h.sh_info].reloc[j].offset = r.r_offset;
280
          scndata[h.sh_info].reloc[j].symbol = r.r_info >> 8;
281
/* HACKME!!! Unify the relocation types... */
282
          scndata[h.sh_info].reloc[j].type = (BYTE)r.r_info;
283
          if ((BYTE)r.r_info == R_386_32){
284
            scndata[h.sh_info].reloc[j].type = REL_TYPE_ELF_ABSOLUTE;
285
          } else if ((BYTE)r.r_info == R_386_PC32) {
286
            scndata[h.sh_info].reloc[j].type = REL_TYPE_RELATIVE;
287
          }
288
        }
289
      } else if (h.sh_type == SHT_RELA) {
290
        printk("Error: unsupported relocation section!!!\n");
291
 
292
        return 0;
293
      } else if ((h.sh_type == SHT_SYMTAB) || (h.sh_type == SHT_DYNSYM)) {
294
#ifdef __ELF_DEBUG__
295
        printk("\t\tSection %d: symbol table!!!\n", i);
296
        printk("\t\tString table: section number %lu\n", h.sh_link);
297
        printk("\t\tLast local Symbol + 1: %lu\n", h.sh_info);
298
#endif
299
        tables->symbol = h.sh_offset;
300
        tables->num_symbols = h.sh_size / h.sh_entsize;
301
        tables->symbol_size = h.sh_size;
302
        if (stringtable != -1) {
303
          printk("Error: double string table!!!\n");
304
          return 0;
305
        }
306
        stringtable = h.sh_link;
307
        if (stringtable < i) {
308
          printk("Strange... ");
309
          printk("String table (%d) < Symbol Table\n", stringtable);
310
          return 0;
311
        }
312
      } else if (i == stringtable) {
313
#ifdef __ELF_DEBUG__
314
        printk("\t\t Section %d: string table!!!\n", i);
315
#endif
316
        tables->string = h.sh_offset;
317
        tables->string_size = h.sh_size;
318
        stringtable = -1;
319
      } else {
320
        scndata[i].base = h.sh_addr;
321
        scndata[i].size = h.sh_size;
322
        scndata[i].fileptr = h.sh_offset;
323
        if (h.sh_type != SHT_NOBITS) {
324
#ifdef __ELF_DEBUG__
325
          printk("BSS?\n");
326
#endif
327
          scndata[i].filesize = h.sh_size;
328
        }
329
      }
330
    } else {
331
#ifdef __ELF_DEBUG__
332
      printk("NULL Section\n");
333
#endif
334
    }
335
 
336
#if 0
337
    if (h.s_flags & SECT_TEXT) {
338
      printk("Executable section\n");
339
    }
340
    if (h.s_flags & SECT_INIT_DATA) {
341
      printk("Data section\n");
342
    }
343
    if (h.s_flags & SECT_UNINIT_DATA) {
344
      printk("BSS section\n");
345
      scndata[i].filesize = 0;
346
    }
347
#endif
348
  }
349
  tables->image_base = scndata[0].base;
350
  return bss;
351
};
352
 
353
 
354
int ELF_read_symbols(struct file_ops *kf,
355
                                        struct table_info *tables,
356
                                        struct symbol_info *syms)                                                      
357
{
358
        //printk("ELF read_symbols\n");
359
 
360
  int i;
361
  int entsize;
362
  struct elf_symbol_info symbol;
363
  char *s;
364
 
365
  s = (void *)malloc(tables->string_size);
366
  if(s == NULL)
367
  {
368
    printk("Failed to allocate space for string table...\n");
369
    return 0;
370
  }
371
 
372
  tables->string_buffer = (DWORD)s;
373
  kf->file_seek( kf->file_offset + tables->string, kf->seek_set);
374
  kf->file_read( s, tables->string_size);
375
 
376
  entsize = tables->symbol_size / tables->num_symbols;
377
 
378
  for (i = 0; i < tables->num_symbols; i++)
379
  {
380
    kf->file_seek( kf->file_offset + tables->symbol + i * entsize,
381
                                                kf->seek_set);
382
    kf->file_read( &symbol, sizeof(struct elf_symbol_info));
383
    syms[i].name = s + symbol.st_name;
384
    syms[i].section = symbol.st_shndx;
385
    syms[i].offset = symbol.st_value;
386
 
387
    if (syms[i].section == SHN_UNDEF) {
388
      /* extern symbol */
389
      if (symbol.st_name != 0)
390
        syms[i].section = EXTERN_SYMBOL;
391
      else /* Mark the empty entry, external symbol with no name is not used :-) */
392
        syms[i].section = NULL_SYMBOL;
393
    }
394
    if (syms[i].section == SHN_COMMON) {
395
      /* extern symbol */
396
      syms[i].section = COMMON_SYMBOL;
397
      syms[i].offset = symbol.st_size;
398
      /* calculate the local_bss_size */
399
      tables->local_bss_size += syms[i].offset;
400
    }
401
  }
402
 
403
  return 1;
404
};
405
 
406
int Elf_check(struct file_ops *kf)
407
{
408
  char signature[4];
409
 
410
  kf->file_offset = kf->file_seek( 0, kf->seek_cur);
411
  kf->file_read(signature, 4);
412
  kf->file_seek( kf->file_offset + 0, kf->seek_set);
413
 
414
  if(memcmp(signature, elf_signature, 4))
415
  {
416
    return 0;
417
  }
418
 
419
  return 1;
420
};
421
 
422
int ELF_relocate_section(struct file_ops *kf,
423
                                                        DWORD base,
424
                                                        struct table_info *tables,
425
                                                        int n,
426
                                                        struct section_info *s,
427
                                                        int sect,
428
                                                        struct symbol_info *syms,
429
                                                        struct symbol *import)
430
{
431
 
432
        int i, idx;
433
        DWORD address, destination;
434
        int j, done;
435
        DWORD local_bss = tables->local_bss;
436
        struct reloc_info *rel = s[sect].reloc;
437
 
438
        /* Setup the common space-uninitialized symbols at the first section relocation
439
        * Pre-calculate the local BSS size (in read_symbols)
440
        * then allocate for each symbol (in load_relocatable)
441
        */
442
 
443
  if(sect == 0)
444
  {
445
    for(i=0; i<tables->num_symbols; i++)
446
        {
447
      if(syms[i].section == COMMON_SYMBOL)
448
          {
449
        j = syms[i].offset;
450
        syms[i].offset = local_bss;
451
        local_bss += j;
452
      }
453
          else if(syms[i].section == EXTERN_SYMBOL)
454
          {
455
                #ifdef __ELF_DEBUG__
456
        printk("Searching for symbol %s\n", syms[i].name);
457
                #endif
458
        /* Pre-set the external symbol at the same time */
459
        for(j=0, done=0; import[j].name != 0; j++)
460
                {
461
          if(strcmp(import[j].name, syms[i].name) == 0)
462
                  {
463
            syms[i].offset = import[j].address;
464
            done = 1;
465
            break;
466
          }
467
                }
468
        if(done == 0)
469
                {
470
            printk("Symbol %s not found\n", syms[i].name);
471
            return -1;
472
        }
473
 
474
      }
475
    }
476
  }
477
 
478
  //printk("[COMMON] s[sect].num_reloc = %d\n", s[sect].num_reloc);
479
 
480
  for(i=0; i < s[sect].num_reloc; i++)
481
  {
482
        #ifdef __COFF_DEBUG__
483
    printk("Relocate 0x%lx (index 0x%x): mode %d ",
484
                        rel[i].offset, rel[i].symbol, rel[i].type);
485
        #endif
486
    idx = rel[i].symbol;
487
 
488
        #ifdef __COFF_DEBUG__
489
    printk("%s --> 0x%lx (section %d)\n", syms[idx].name,
490
                        syms[idx].offset, syms[idx].section);
491
        #endif
492
 
493
    switch (rel[i].type)
494
    {
495
      case REL_TYPE_ELF_ABSOLUTE:
496
        destination = s[sect].base + rel[i].offset + base;
497
        // Initial address
498
        address = *((DWORD*)destination);
499
        break;
500
      case REL_TYPE_RELATIVE:
501
        destination = s[sect].base + rel[i].offset + base;
502
        address = 0;
503
        break;
504
      default:
505
        // (Non-)external symbols: only REL32 is supported
506
        printk("Unsupported relocation!\n");
507
        printk("Relocation Type: %d\n", rel[i].type);
508
        return -1;
509
    }
510
 
511
        if(syms[idx].section == COMMON_SYMBOL || syms[idx].section == EXTERN_SYMBOL)
512
        {
513
                if(rel[i].type == REL_TYPE_ELF_ABSOLUTE)
514
                        address += syms[idx].offset;
515
 
516
                else if(rel[i].type == REL_TYPE_RELATIVE)
517
                        address = syms[idx].offset - destination - 4;
518
        }
519
        else if(syms[idx].section >= n)
520
        {
521
                // Check if the section exists ... 
522
                printk("Unsupported relocation section\n");
523
                printk("Section %d > %d\n", syms[idx].section, n);
524
                printk("Value 0x%lx\n", syms[idx].offset);
525
                return -1;
526
        }
527
        else
528
        {
529
                if(rel[i].type == REL_TYPE_ELF_ABSOLUTE)
530
                {
531
                        address += base + s[syms[idx].section].base + syms[idx].offset;
532
                }
533
                else if(rel[i].type == REL_TYPE_RELATIVE)
534
                {
535
                        address = (s[syms[idx].section].base + syms[idx].offset) - (s[sect].base + rel[i].offset) - 4;
536
                        #ifdef __COFF_DEBUG__
537
                        printk("Reloc: 0x%lx + 0x%lx - 0x%lx = 0x%lx   ",
538
                                syms[idx].offset,
539
                                s[syms[idx].section].base,
540
                                rel[i].offset , address);
541
                        #endif
542
                }
543
        }
544
 
545
        #ifdef __COFF_DEBUG__
546
    printk("0x%lx <--- 0x%lx\n", destination, address);
547
        #endif
548
    *((DWORD*)destination) = address;
549
  }
550
 
551
  return 1;
552
};
553
 
554
 
555
/* Import symbol with suffix `name'
556
 * NOTE: Any symbol with prefix `_' won't be found and be regarded as internal and hidden
557
 */
558
DWORD ELF_import_symbol(struct file_ops *kf,
559
                                                        int n,
560
                                                        struct symbol_info *syms,
561
                                                        char *name,
562
                                                        int *sect)
563
{
564
        //printk("[COMMON] import_symbol...\n");
565
 
566
  int i;
567
  int len = strlen(name);
568
 
569
  for(i = 0; i < n ; i++)
570
  {
571
        #ifdef __COFF_DEBUG__
572
    printk("Checking symbol %d [%d] --- Sect %d\n", i, n, syms[i].section);
573
        #endif
574
    if ((syms[i].section != EXTERN_SYMBOL) && (syms[i].section != COMMON_SYMBOL) && (syms[i].section != NULL_SYMBOL))
575
        {
576
          #ifdef __COFF_DEBUG__
577
      printk("Compare %s, %s\n", syms[i].name, name);
578
          #endif
579
      if(syms[i].name[0] != '_')
580
          {
581
        int sym_len = strlen(syms[i].name);
582
        if(sym_len >= len && strcmp(syms[i].name+sym_len-len, name) == 0)
583
                {
584
                  #ifdef __COFF_DEBUG__
585
          printk("Found: %s --- 0x%x : 0x%lx\n",
586
                                syms[i].name, syms[i].section, syms[i].offset);
587
                  #endif
588
          break;
589
        }
590
                #ifdef __COFF_DEBUG__
591
        else
592
                {
593
          printk("Cmp failed --- Going to %d\n", i);
594
        }
595
                #endif
596
      }
597
    }
598
        #ifdef __COFF_DEBUG__
599
    else
600
        {
601
      printk("Skipped symbol --- Going to %d\n", i);
602
    }
603
        #endif
604
  }
605
 
606
  if(i < n)
607
  { /* Symbol found */
608
    *sect = syms[i].section;
609
    return syms[i].offset;
610
  }
611
  else
612
  {
613
    *sect = -1;
614
    printk("Symbol not found!!!\n");
615
    return 0;
616
  }
617
};
618
 
619
 
620
 
621
DWORD ELF_load_relocatable(     struct file_ops *kf,
622
                                                                struct table_info *tables,
623
                                                                int n,
624
                                                                struct section_info *s,
625
                                                                DWORD *size)                                                           
626
{
627
        int i;
628
        DWORD needed_mem = 0;
629
        DWORD local_offset = 0;
630
        BYTE *mem_space, *where_to_place;
631
 
632
        // Allocate for the local bss at the mean time 
633
        for(i=0; i<n; i++)
634
        {
635
                needed_mem += s[i].size;
636
        }
637
        needed_mem += tables->local_bss_size;
638
        mem_space = (BYTE *)malloc(needed_mem);
639
        if(mem_space == NULL)
640
        {
641
                printk("Unable to allocate memory for the program image\n");
642
                return 0;
643
        }
644
        memset(mem_space, 0, needed_mem);
645
 
646
        #ifdef __ELF_DEBUG__
647
        printk("Loading relocatable @%p; size 0x%lx\n", mem_space, needed_mem);
648
        #endif
649
 
650
 
651
        if(tables->local_bss_size != 0)
652
                tables->local_bss = (DWORD)mem_space + needed_mem - tables->local_bss_size;
653
        else
654
                tables->local_bss = 0;
655
 
656
 
657
        for(i=0; i<n; i++)
658
        {
659
                #ifdef __ELF_DEBUG__
660
                printk("Section %d\t", i);
661
                #endif
662
                if(s[i].size != 0)
663
                {
664
                        #ifdef __ELF_DEBUG__
665
                        printk("Loading @ 0x%lx (0x%lx + 0x%lx)...\n",
666
                                        (DWORD)mem_space + (DWORD)local_offset,
667
                                        (DWORD)mem_space, local_offset);
668
                        #endif
669
 
670
                        where_to_place = mem_space + local_offset;
671
                        s[i].base = local_offset;
672
                        local_offset += s[i].size;
673
                        kf->file_seek( kf->file_offset + s[i].fileptr, kf->seek_set);
674
                        if(s[i].filesize > 0)
675
                        {
676
                                kf->file_read( where_to_place, s[i].filesize);
677
                        }
678
                }
679
                else
680
                {
681
                        #ifdef __ELF_DEBUG__
682
                        printk("Not to be loaded\n");
683
                        #endif
684
                }
685
        }
686
 
687
        *size = needed_mem;
688
 return (DWORD)mem_space;
689
};
690
 
691
 
692
void ELF_free_tables(struct file_ops *kf,
693
                                                struct table_info *tables,
694
                                                struct symbol_info *syms,
695
                                                struct section_info *scndata)
696
{
697
  int i;
698
 
699
  for(i = 0; i < tables->num_sections; i++)
700
    if (scndata[i].num_reloc != 0)
701
          free( scndata[i].reloc);
702
 
703
  free(scndata);  
704
  if (syms != NULL)     free(syms);
705
  if (tables->string_size != 0)   free((DWORD*)tables->string_buffer);
706
  if (tables->section_names_size != 0)    free(tables->section_names);  
707
};
708