OSDN Git Service

when debugging a flat loader problem involving relocs, i found it very
[uclinux-h8/elf2flt.git] / elf2flt.c
index 0afe124..546305f 100644 (file)
--- a/elf2flt.c
+++ b/elf2flt.c
@@ -6,6 +6,8 @@
  * ELF format file handling. Extended relocation support for all of
  * text and data.
  *
+ * (c) 2006  Support the -a (use_resolved) option for TARGET_arm.
+ *           Shaun Jackman <sjackman@gmail.com>
  * (c) 2004, Nios II support, Wentao Xu <wentao@microtronix.com>
  * (c) 2003, H8 support, ktrace <davidm@snapgear.com>
  * (c) 2003-2004, MicroBlaze support, John Williams <jwilliams@itee.uq.edu.au>
@@ -52,6 +54,7 @@
 
 /* from $(INSTALLDIR)/include       */
 #include <bfd.h>      /* Main header file for the BFD library                */
+#include <libiberty.h>
 
 #if defined(TARGET_h8300)
 #include <elf/h8.h>      /* TARGET_* ELF support for the BFD library            */
@@ -71,6 +74,7 @@
 
 /* from uClinux-x.x.x/include/linux */
 #include "flat.h"     /* Binary flat header description                      */
+#include "compress.h"
 
 #ifdef TARGET_e1
 #include <e1.h>
@@ -140,7 +144,7 @@ int verbose = 0;      /* extra output when running */
 int pic_with_got = 0; /* do elf/got processing with PIC code */
 int load_to_ram = 0;  /* instruct loader to allocate everything into RAM */
 int ktrace = 0;       /* instruct loader output kernel trace on load */
-int compress = 0;     /* 1 = compress everything, 2 = compress data only */
+int docompress = 0;   /* 1 = compress everything, 2 = compress data only */
 int use_resolved = 0; /* If true, get the value of symbol references from */
                      /* the program contents, not from the relocation table. */
                      /* In this case, the input ELF file must be already */
@@ -233,7 +237,7 @@ get_symbols (bfd *abfd, long *num)
   if (storage_needed == 0)
     return NULL;
 
-  symbol_table = (asymbol **) malloc (storage_needed);
+  symbol_table = xmalloc (storage_needed);
 
   number_of_symbols = bfd_canonicalize_symtab (abfd, symbol_table);
   
@@ -308,119 +312,6 @@ add_com_to_bss(asymbol **symbol_table, long number_of_symbols, long bss_len)
 }  
 
 #ifdef TARGET_bfin
-/* stack to handle "arithmetic" relocations */
-#define RELOC_STACK_SIZE 100
-static bfd_vma reloc_stack[RELOC_STACK_SIZE];
-static unsigned int reloc_stack_tos = 0;
-static char sym_section_name[80];
-static asection *stack_sym_section = 0;
-
-static void
-reloc_stack_set_section(asection *section, const char *sym_section_name_in)
-{
-    /* TODO : we can add checks to make sure we do not
-       add different section names to the same arithmetic
-       expression.  */
-    strcpy(sym_section_name, sym_section_name_in);
-    stack_sym_section = section;
-}
-
-static const char *
-reloc_stack_get_section_name()
-{
-    return sym_section_name;
-}
-static asection *reloc_stack_get_section()
-{
-    return stack_sym_section;
-}
-
-#define is_reloc_stack_empty() ((reloc_stack_tos > 0)?0:1)
-
-static void
-reloc_stack_push(bfd_vma value)
-{
-  reloc_stack[reloc_stack_tos++] = value;
-}
-
-static bfd_vma
-reloc_stack_pop()
-{
-  return reloc_stack[--reloc_stack_tos];
-}
-
-static bfd_vma
-reloc_stack_operate(unsigned int oper)
-{
-    bfd_vma value;
-    switch(oper){
-    case 0xE2 :
-       value = reloc_stack[reloc_stack_tos - 2] + reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE3 :
-       value = reloc_stack[reloc_stack_tos - 2] - reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE4 :
-       value = reloc_stack[reloc_stack_tos - 2] * reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE5 :
-       value = reloc_stack[reloc_stack_tos - 2] / reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE6 :
-       value = reloc_stack[reloc_stack_tos - 2] % reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE7 :
-       value = reloc_stack[reloc_stack_tos - 2] << reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE8 :
-       value = reloc_stack[reloc_stack_tos - 2] >> reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xE9 :
-       value = reloc_stack[reloc_stack_tos - 2] & reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEA :
-       value = reloc_stack[reloc_stack_tos - 2] | reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEB :
-       value = reloc_stack[reloc_stack_tos - 2] ^ reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEC :
-       value = reloc_stack[reloc_stack_tos - 2] && reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xED :
-       value = reloc_stack[reloc_stack_tos - 2] || reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 2;
-       break;
-    case 0xEF :
-       value = -reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos --;
-       break;
-    case 0xF0 :
-       value = ~reloc_stack[reloc_stack_tos - 1];
-       reloc_stack_tos -= 1;
-       break;
-    default :
-       fprintf(stderr, "bfin relocation : Internal bug\n");
-       return 0;
-    }
-
-    // now push the new value back on stack
-    reloc_stack_push(value);
-
-    return value;
-}
-
 /* FUNCTION : weak_und_symbol
    ABSTRACT : return true if symbol is weak and undefined.
 */
@@ -536,7 +427,7 @@ dump_symbols(symbols, number_of_symbols);
    * Also note that both the relocatable and absolute versions have this
    * terminator even though the relocatable one doesn't have the GOT!
    */
-  if (pic_with_got) {
+  if (pic_with_got && !use_resolved) {
     unsigned long *lp = (unsigned long *)data;
     /* Should call ntohl(*lp) here but is isn't going to matter */
     while (*lp != 0xffffffff) lp++;
@@ -603,7 +494,8 @@ dump_symbols(symbols, number_of_symbols);
        }
 
        symb = get_symbols(rel_bfd, &nsymb);
-       relpp = (arelent **) xmalloc(relsize);
+       relpp = xmalloc(relsize);
+
        relcount = bfd_canonicalize_reloc(rel_bfd, r, relpp, symb);
        if (relcount <= 0) {
                if (verbose)
@@ -684,16 +576,6 @@ dump_symbols(symbols, number_of_symbols);
 #endif /* USE_V850_RELOCS */
 
                        q = *p;
-#ifdef TARGET_bfin
-                       if ((q->sym_ptr_ptr && *q->sym_ptr_ptr) &&
-                            (!is_reloc_stack_empty() && strstr((*(q->sym_ptr_ptr))->name, "operator"))){
-                               /* must be an arith reloc ... get the value from the stack */
-                               sym_name = (*(q->sym_ptr_ptr))->name;
-                               sym_section = reloc_stack_get_section();
-                               section_name = reloc_stack_get_section_name();
-                       }
-                       else
-#endif
                        if (q->sym_ptr_ptr && *q->sym_ptr_ptr) {
                                sym_name = (*(q->sym_ptr_ptr))->name;
                                sym_section = (*(q->sym_ptr_ptr))->section;
@@ -707,7 +589,7 @@ dump_symbols(symbols, number_of_symbols);
                        /* Adjust the address to account for the GOT table which wasn't
                         * present in the relative file link.
                         */
-                       if (pic_with_got)
+                       if (pic_with_got && !use_resolved)
                          q->address += got_size;
 #endif
 
@@ -795,7 +677,7 @@ dump_symbols(symbols, number_of_symbols);
                                                                + lo;
                                                }
                                        } else
-                                               goto bad_v850_reloc_err;
+                                               goto bad_resolved_reloc;
                                        break;
 
                                case R_V850_LO16:
@@ -809,16 +691,37 @@ dump_symbols(symbols, number_of_symbols);
                                            && (p[-1]->addend == p[0]->addend))
                                                break; /* not an error */
                                        else
-                                               goto bad_v850_reloc_err;
+                                               goto bad_resolved_reloc;
 
                                case R_V850_HI16:
-                               bad_v850_reloc_err:
-                                       printf("ERROR: reloc type %s unsupported in this context\n",
-                                              q->howto->name);
-                                       bad_relocs++;
+                                       goto bad_resolved_reloc;
+                               default:
+                                       goto good_32bit_resolved_reloc;
+#elif defined(TARGET_arm)
+                               case R_ARM_ABS32:
+                                       relocation_needed = 1;
                                        break;
-#endif /* TARGET_V850 */
-
+                               case R_ARM_REL32:
+                               case R_ARM_THM_PC11:
+                               case R_ARM_THM_PC22:
+                                       relocation_needed = 0;
+                                       break;
+                               default:
+                                       goto bad_resolved_reloc;
+#elif defined(TARGET_m68k)
+                               case R_68K_32:
+                                       goto good_32bit_resolved_reloc;
+                               case R_68K_PC32:
+                               case R_68K_PC16:
+                                       /* The linker has already resolved
+                                          PC relocs for us.  In PIC links,
+                                          the symbol must be in the data
+                                          segment.  */
+                               case R_68K_NONE:
+                                       continue;
+                               default:
+                                       goto bad_resolved_reloc;
+#else
                                default:
                                        /* The default is to assume that the
                                           relocation is relative and has
@@ -827,6 +730,9 @@ dump_symbols(symbols, number_of_symbols);
                                           give an error by default, and
                                           require `safe' relocations to be
                                           enumberated explicitly?).  */
+                                       goto good_32bit_resolved_reloc;
+#endif
+                               good_32bit_resolved_reloc:
                                        if (bfd_big_endian (abs_bfd))
                                                sym_addr =
                                                        (r_mem[0] << 24)
@@ -840,6 +746,13 @@ dump_symbols(symbols, number_of_symbols);
                                                        + (r_mem[2] << 16)
                                                        + (r_mem[3] << 24);
                                        relocation_needed = 1;
+                                       break;
+
+                               bad_resolved_reloc:
+                                       printf("ERROR: reloc type %s unsupported in this context\n",
+                                              q->howto->name);
+                                       bad_relocs++;
+                                       break;
                                }
                        } else {
                                /* Calculate the sym address ourselves.  */
@@ -1069,8 +982,6 @@ dump_symbols(symbols, number_of_symbols);
 #ifdef TARGET_nios2
 #define  htoniosl(x)   (x)
 #define  niostohl(x)   (x)
-                       switch ((*p)->howto->type) 
-                       {
                                case R_NIOS2_BFD_RELOC_32:
                                        relocation_needed = 1;
                                        pflags = (FLAT_NIOS2_R_32 << 28);
@@ -1223,7 +1134,6 @@ NIOS2_RELOC_ERR:
                                        printf("Err: unexpected reloc type %s(%d)\n", q->howto->name, q->howto->type);
                                        bad_relocs++;
                                        continue;
-                       }
 #endif /* TARGET_nios2 */
 
 #ifdef TARGET_sparc
@@ -1284,14 +1194,12 @@ NIOS2_RELOC_ERR:
                                  sym_addr -= q->address; // make it PC relative 
                                  // implicitly assumes code section and symbol section are same
                                  break;
-                               
+                               case R_got:
+                                   /* Ignore these.  */
+                                   break;
+
                                case R_rimm16:
-                                   if (is_reloc_stack_empty ())
-                                   {
-                                       sym_addr += q->addend;
-                                   } else {
-                                       sym_addr = reloc_stack_pop ();
-                                   }
+                                   sym_addr += q->addend;
                                    if(weak_und_symbol(sym_section->name, (*(q->sym_ptr_ptr))))
                                        continue;
                                    if(0xFFFF0000 & sym_addr){
@@ -1321,11 +1229,8 @@ NIOS2_RELOC_ERR:
                                    else
                                        hi_lo = FLAT_RELOC_PART_HI;
                                
-                                   if (is_reloc_stack_empty ())
-                                       sym_addr += q->addend;
-                                   else
-                                       sym_addr = reloc_stack_pop ();
-                                   
+                                   sym_addr += q->addend;
+
                                    flat_relocs = (uint32_t *)
                                        (realloc (flat_relocs, (flat_reloc_count + 2) * sizeof (uint32_t)));
                                    reloc_count_incr = 1;
@@ -1362,10 +1267,8 @@ NIOS2_RELOC_ERR:
                                    break;
                                }
                                case R_byte4_data:
-                                   if (is_reloc_stack_empty ())
-                                       sym_addr += q->addend;
-                                   else
-                                       sym_addr = reloc_stack_pop ();
+                                   sym_addr += q->addend;
+
                                    if (weak_und_symbol (sym_section->name, *q->sym_ptr_ptr))
                                        continue;
 
@@ -1381,22 +1284,6 @@ NIOS2_RELOC_ERR:
                                    flat_reloc_count++;
                                    break;
 
-                               case 0xE0: 
-                                  /* push */
-                                 sym_addr += q->addend;
-                                 reloc_stack_push(sym_addr);
-                                 reloc_stack_set_section(sym_section, section_name);
-                                 break;
-
-                               case 0xE1:
-                                 /* const */
-                                 reloc_stack_push(q->addend);
-                               break;
-
-                               case 0xE2 ... 0xF2:
-                                 reloc_stack_operate((*p)->howto->type);
-                                 break;
-
 #endif //TARGET_bfin
 
 #ifdef TARGET_sh
@@ -1628,17 +1515,20 @@ DIS29_RELOCATION:
 
                                tmp.l = *(unsigned long *)r_mem;
                                hl = tmp.c[i0] | (tmp.c[i1] << 8) | (tmp.c[i2] << 16);
-                               if (((*p)->howto->type != R_ARM_PC24) &&
-                                   ((*p)->howto->type != R_ARM_PLT32))
+                               if (use_resolved ||
+                                       (((*p)->howto->type != R_ARM_PC24) &&
+                                       ((*p)->howto->type != R_ARM_PLT32)))
                                        hl |= (tmp.c[i3] << 24);
                                else if (tmp.c[i2] & 0x80)
                                        hl |= 0xff000000; /* sign extend */
-                               hl += sym_addr;
+                               if (!use_resolved)
+                                       hl += sym_addr;
                                tmp.c[i0] = hl & 0xff;
                                tmp.c[i1] = (hl >> 8) & 0xff;
                                tmp.c[i2] = (hl >> 16) & 0xff;
-                               if (((*p)->howto->type != R_ARM_PC24) &&
-                                   ((*p)->howto->type != R_ARM_PLT32))
+                               if (use_resolved ||
+                                       (((*p)->howto->type != R_ARM_PC24) &&
+                                       ((*p)->howto->type != R_ARM_PLT32)))
                                        tmp.c[i3] = (hl >> 24) & 0xff;
                                if ((*p)->howto->type == R_ARM_ABS32)
                                        *(unsigned long *)r_mem = htonl(hl);
@@ -1879,19 +1769,19 @@ static void usage(void)
 
 
 /* Write NUM zeroes to STREAM.  */
-static void write_zeroes (unsigned long num, FILE *stream)
+static void write_zeroes (unsigned long num, stream *stream)
 {
   char zeroes[1024];
   if (num > 0) {
     /* It'd be nice if we could just use fseek, but that doesn't seem to
        work for stdio output files.  */
-    bzero(zeroes, 1024);
+    memset(zeroes, 0x00, 1024);
     while (num > sizeof(zeroes)) {
-      fwrite(zeroes, sizeof(zeroes), 1, stream);
+      fwrite_stream(zeroes, sizeof(zeroes), 1, stream);
       num -= sizeof(zeroes);
     }
     if (num > 0)
-      fwrite(zeroes, num, 1, stream);
+      fwrite_stream(zeroes, num, 1, stream);
   }
 }
 
@@ -1906,8 +1796,7 @@ int main(int argc, char *argv[])
   int opt;
   int i;
   int stack;
-  char  cmd[1024];
-  FILE *gf = NULL;
+  stream gf;
 
   asymbol **symbol_table;
   long number_of_symbols;
@@ -1929,10 +1818,9 @@ int main(int argc, char *argv[])
   
   struct flat_hdr hdr;
 
-  int gf_is_pipe = 0;
-
   program = argv[0];
   progname = argv[0];
+  xmalloc_set_program_name(program);
 
   if (argc < 2)
        usage();
@@ -1963,10 +1851,10 @@ int main(int argc, char *argv[])
       ktrace++;
       break;
     case 'z':
-      compress = 1;
+      docompress = 1;
       break;
     case 'd':
-      compress = 2;
+      docompress = 2;
       break;
     case 'p':
       pfile = optarg;
@@ -1978,7 +1866,10 @@ int main(int argc, char *argv[])
       use_resolved = 1;
       break;
     case 's':
-      stack = atoi(optarg);
+      if (sscanf(optarg, "%i", &stack) != 1) {
+        fprintf(stderr, "%s invalid stack size %s\n", argv[0], optarg);
+        usage();
+      }
       break;
     case 'R':
       rel_file = optarg;
@@ -2084,7 +1975,7 @@ int main(int argc, char *argv[])
     exit (2);
   }
 
-  text = malloc(text_len);
+  text = xmalloc(text_len);
 
   if (verbose)
     printf("TEXT -> vma=0x%x len=0x%x\n", text_vma, text_len);
@@ -2104,7 +1995,7 @@ int main(int argc, char *argv[])
     fprintf (stderr, "%s: no .data section", abs_file);
     exit (2);
   }
-  data = malloc(data_len);
+  data = xmalloc(data_len);
 
   if (verbose)
     printf("DATA -> vma=0x%x len=0x%x\n", data_vma, data_len);
@@ -2172,10 +2063,10 @@ int main(int argc, char *argv[])
          | (load_to_ram ? FLAT_FLAG_RAM : 0)
          | (ktrace ? FLAT_FLAG_KTRACE : 0)
          | (pic_with_got ? FLAT_FLAG_GOTPIC : 0)
-         | (compress ? (compress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
+         | (docompress ? (docompress == 2 ? FLAT_FLAG_GZDATA : FLAT_FLAG_GZIP) : 0)
          );
   hdr.build_date = htonl((unsigned long)time(NULL));
-  bzero(hdr.filler, sizeof(hdr.filler));
+  memset(hdr.filler, 0x00, sizeof(hdr.filler));
 
   for (i=0; i<reloc_len; i++) reloc[i] = htonl(reloc[i]);
 
@@ -2188,7 +2079,7 @@ int main(int argc, char *argv[])
   }
   
   if (!ofile) {
-    ofile = malloc(strlen(fname) + 5 + 1); /* 5 to add suffix */
+    ofile = xmalloc(strlen(fname) + 5 + 1); /* 5 to add suffix */
     strcpy(ofile, fname);
     strcat(ofile, ".bflt");
   }
@@ -2201,54 +2092,32 @@ int main(int argc, char *argv[])
   write(fd, &hdr, sizeof(hdr));
   close(fd);
 
-  /*
-   * get the compression command ready
-   */
-  sprintf(cmd, "gzip -f -9 >> %s", ofile);
-
-#define        START_COMPRESSOR do { \
-               if (gf) \
-                       if (gf_is_pipe) \
-                               pclose(gf); \
-                       else \
-                               fclose(gf); \
-               if (!(gf = popen(cmd, "w" BINARY_FILE_OPTS))) { \
-                       fprintf(stderr, "Can't run cmd %s\n", cmd); \
-                       exit(4); \
-               } \
-               gf_is_pipe = 1; \
-       } while (0)
-
-  gf = fopen(ofile, "ab");     /* Add 'b' to support non-posix (ie windows) */
-  if (!gf) {
-       fprintf(stderr, "Can't open file %s for writing\n", ofile); \
-       exit(4);
+  if (fopen_stream_u(&gf, ofile, "a" BINARY_FILE_OPTS)) {
+    fprintf(stderr, "Can't open file %s for writing\n", ofile);
+    exit(4);
   }
 
-  if (compress == 1)
-       START_COMPRESSOR;
+  if (docompress == 1)
+    reopen_stream_compressed(&gf);
 
   /* Fill in any hole at the beginning of the text segment.  */
   if (verbose)
-         printf("ZERO before text len=0x%x\n", text_offs);
-  write_zeroes(text_offs, gf);
+    printf("ZERO before text len=0x%x\n", text_offs);
+  write_zeroes(text_offs, &gf);
 
   /* Write the text segment.  */
-  fwrite(text, text_len, 1, gf);
+  fwrite_stream(text, text_len, 1, &gf);
 
-  if (compress == 2)
-       START_COMPRESSOR;
+  if (docompress == 2)
+    reopen_stream_compressed(&gf);
 
   /* Write the data segment.  */
-  fwrite(data, data_len, 1, gf);
+  fwrite_stream(data, data_len, 1, &gf);
 
   if (reloc)
-    fwrite(reloc, reloc_len * 4, 1, gf);
+    fwrite_stream(reloc, reloc_len * 4, 1, &gf);
 
-  if(gf_is_pipe)
-    pclose(gf);
-  else
-  fclose(gf);
+  fclose_stream(&gf);
 
   exit(0);
 }