home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / binutils-2.7-src.tgz / tar.out / fsf / binutils / bfd / amigaoslink.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  31KB  |  1,101 lines

  1. /* BFD back-end for Commodore-Amiga AmigaOS binaries. Linker routines.
  2.    Copyright (C) 1990-1994 Free Software Foundation, Inc.
  3.    Contributed by Stephan Thesing
  4.  
  5. This file is part of BFD, the Binary File Descriptor library.
  6.  
  7. This program is free software; you can redistribute it and/or modify
  8. it under the terms of the GNU General Public License as published by
  9. the Free Software Foundation; either version 2 of the License, or
  10. (at your option) any later version.
  11.  
  12. This program is distributed in the hope that it will be useful,
  13. but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. GNU General Public License for more details.
  16.  
  17. You should have received a copy of the GNU General Public License
  18. along with this program; if not, write to the Free Software
  19. Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.  */
  20.  
  21. /*
  22. INODE
  23. amigalink, , implementation, amiga
  24. SECTION
  25.     amigalink
  26.  
  27. This is the description of the linker routines for the amiga.
  28. In fact, this includes a description of the changes made to the
  29. a.out code, in order to build a working linker for the Amiga.
  30. @menu
  31. @* alterations::
  32. @end menu
  33.  
  34. INODE 
  35. alterations, , , amigalink
  36. SUBSECTION
  37.     alterations
  38.  
  39. The file @file{aout-amiga.c} defines the amiga a.out backend. It differs from
  40. the sun3 backend only in these details:
  41.     o The @code{final_link} routine is @code{amiga_final_link}.
  42.     o The routine to get the relocated section contents is
  43.            @code{aout_bfd_get_relocated_section_contents}.
  44.  
  45. This ensures that the link is performed properly, but has the side effect of loosing
  46. performance.
  47.  
  48.  
  49. The amiga bfd code uses the same @code{amiga_final_link} routine, but with a 
  50. different <<get_relocated_section_contents>> entry: <<amiga_bfd_get_relocated_section_contents>>.
  51. The latter  differs from the routine of the a.out backend only in the application of relocs
  52.  to the section contents.
  53. @@*
  54.  
  55. The usage of a special linker code has one reason:
  56. The bfd library assumes that a program is always loaded at a known memory
  57. address. This is not a case on an Amiga. So the Amiga format has to take over
  58. some relocs to an executable output file. 
  59. This is not the case with a.out formats, so there relocations can be applied at link time,
  60. not at run time, like on the Amiga.
  61. The special routines compensate this: instead of applying the relocations, they are
  62. copied to the output file, if neccessary.
  63. As as consequence, the @code{final_link} and @code{get_relocated_section_contents} are nearly identical to
  64. the original routines from @file{linker.c} and @file{reloc.c}.
  65. */
  66.  
  67. #include "bfd.h"
  68. #include "bfdlink.h"
  69. #include <sys/types.h>
  70. #include "genlink.h"
  71. #include "sysdep.h"
  72. #include "libbfd.h"
  73.  
  74. #include "libamiga.h"
  75. #undef GET_SWORD
  76. #define aadata ((bfd)->tdata.amiga_data->a)
  77. #undef adata
  78. #include "libaout.h"
  79.  
  80.  
  81. #define max(x,y) (((x)<=(y))?(y):(x))
  82.  
  83. #define DEBUG_AMIGA 10000
  84.  
  85. #if DEBUG_AMIGA
  86. #include <varargs.h>
  87. static void error_print(va_alist)
  88. va_dcl
  89. {
  90. va_list args;
  91. char *fmt;
  92.  
  93. va_start(args);
  94. fmt=va_arg(args,char *);
  95.  
  96. (void)vfprintf(stderr,fmt,args);
  97. va_end(args);
  98. }
  99.  
  100. #define DPRINT(L,x) if (L>=DEBUG_AMIGA) error_print x
  101. #else
  102. #define DPRINT(L,x) 
  103. #endif
  104.  
  105. /* This one is used to indicate base-relative linking */
  106. int amiga_base_relative=0;
  107.  
  108. /* This one is used to indicate -resident linking */
  109. int amiga_resident=0;
  110.  
  111. extern boolean default_indirect_link_order
  112.   PARAMS ((bfd *, struct bfd_link_info *, asection *,
  113.        struct bfd_link_order *, boolean));
  114.  
  115.  
  116.  
  117. bfd_byte *
  118. get_relocated_section_contents(bfd *, struct bfd_link_info *,
  119.                    struct bfd_link_order *, bfd_byte *,
  120.                    boolean , asymbol **);
  121. static bfd_reloc_status_type 
  122. amiga_perform_reloc(bfd *, arelent *, PTR, asection *, bfd *, char **);
  123. static bfd_reloc_status_type 
  124. aout_perform_reloc(bfd *, arelent *, PTR, asection *, bfd *, char **);
  125. static boolean
  126. amiga_reloc_link_order (bfd *, struct bfd_link_info *,asection *,
  127.             struct bfd_link_order *);
  128.  
  129.  
  130. /* This one is nearly identical to bfd_generic_get_relocated_section_contents
  131.    from reloc.c */
  132. bfd_byte *
  133. get_relocated_section_contents (abfd, link_info, link_order, data,
  134.                         relocateable, symbols)
  135.      bfd *abfd;
  136.      struct bfd_link_info *link_info;
  137.      struct bfd_link_order *link_order;
  138.      bfd_byte *data;
  139.      boolean relocateable;
  140.      asymbol **symbols;
  141. {
  142.   bfd *input_bfd = link_order->u.indirect.section->owner;
  143.   asection *input_section = link_order->u.indirect.section;
  144.  
  145.   long reloc_size = bfd_get_reloc_upper_bound (input_bfd, input_section);
  146.   arelent **reloc_vector = NULL;
  147.   long reloc_count;
  148.   bfd_reloc_status_type (*reloc_func)(bfd *, arelent *, PTR, asection *,
  149.                       bfd *, char **);
  150.  
  151.   DPRINT(5,("Entering get_rel_sec_cont\n"));
  152.  
  153.   if (reloc_size < 0)
  154.     goto error_return;
  155.  
  156.   if (input_bfd->xvec->flavour==bfd_target_amiga_flavour)
  157.     reloc_func=amiga_perform_reloc;
  158.   else if (input_bfd->xvec->flavour==bfd_target_aout_flavour)
  159.     reloc_func=aout_perform_reloc;
  160.   else
  161.     {
  162.       bfd_set_error(bfd_error_bad_value);
  163.       goto error_return;
  164.     }
  165.  
  166.   reloc_vector = (arelent **) malloc (reloc_size);
  167.  
  168.   if (reloc_vector == NULL && reloc_size != 0)
  169.     {
  170.       bfd_set_error (bfd_error_no_memory);
  171.       goto error_return;
  172.     }
  173.  
  174.   DPRINT(5,("GRSC: GetSecCont()\n"));
  175.   /* read in the section */
  176.   if (!bfd_get_section_contents (input_bfd,
  177.                  input_section,
  178.                  (PTR) data,
  179.                  0,
  180.                  input_section->_raw_size))
  181.     goto error_return;
  182.  
  183.   /* We're not relaxing the section, so just copy the size info */
  184.   input_section->_cooked_size = input_section->_raw_size;
  185.   input_section->reloc_done = true;
  186.  
  187.   DPRINT(5,("GRSC: CanReloc\n"));
  188.   reloc_count = bfd_canonicalize_reloc (input_bfd,
  189.                     input_section,
  190.                     reloc_vector,
  191.                     symbols);
  192.   if (reloc_count < 0)
  193.     goto error_return;
  194.  
  195.   if (reloc_count > 0)
  196.     {
  197.       arelent **parent;
  198.  
  199.       DPRINT(5,("reloc_count=%d\n",reloc_count));
  200.  
  201.       for (parent = reloc_vector; *parent != (arelent *) NULL;
  202.        parent++)
  203.     {
  204.       char *error_message = (char *) NULL;
  205.       bfd_reloc_status_type r ;
  206.  
  207.       DPRINT(5,("Applying a reloc\nparent=%lx, reloc_vector=%lx,"
  208.             "*parent=%lx\n",parent,reloc_vector,*parent));
  209.       r=(*reloc_func) (input_bfd,
  210.                *parent,
  211.                (PTR) data,
  212.                input_section,
  213.                relocateable ? abfd : (bfd *) NULL,
  214.                &error_message);
  215.       if (relocateable)
  216.         {
  217.           asection *os = input_section->output_section;
  218.  
  219.           DPRINT(5,("Keeping reloc\n"));
  220.           /* A partial link, so keep the relocs */
  221.           os->orelocation[os->reloc_count] = *parent;
  222.           os->reloc_count++;
  223.         }
  224.  
  225.       if (r != bfd_reloc_ok)
  226.         {
  227.           switch (r)
  228.         {
  229.         case bfd_reloc_undefined:
  230.           if (!((*link_info->callbacks->undefined_symbol)
  231.             (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
  232.              input_bfd, input_section, (*parent)->address)))
  233.             goto error_return;
  234.           break;
  235.         case bfd_reloc_dangerous:
  236.           BFD_ASSERT (error_message != (char *) NULL);
  237.           if (!((*link_info->callbacks->reloc_dangerous)
  238.             (link_info, error_message, input_bfd, input_section,
  239.              (*parent)->address)))
  240.             goto error_return;
  241.           break;
  242.         case bfd_reloc_overflow:
  243.           if (!((*link_info->callbacks->reloc_overflow)
  244.             (link_info, bfd_asymbol_name (*(*parent)->sym_ptr_ptr),
  245.              (*parent)->howto->name, (*parent)->addend,
  246.              input_bfd, input_section, (*parent)->address)))
  247.             goto error_return;
  248.           break;
  249.         case bfd_reloc_outofrange:
  250.         default:
  251.           DPRINT(10,("get_rel_sec_cont fails, perform reloc "
  252.                  "returned $%x\n",r));
  253.           abort ();
  254.           break;
  255.         }
  256.  
  257.         }
  258.     }
  259.     }
  260.   if (reloc_vector != NULL)
  261.     free (reloc_vector);
  262.   DPRINT(5,("GRSC: Returning ok\n"));
  263.   return data;
  264.  
  265. error_return:
  266.   DPRINT(5,("GRSC: Error_return\n"));
  267.   if (reloc_vector != NULL)
  268.     free (reloc_vector);
  269.   return NULL;
  270. }
  271.  
  272.  
  273. /* Add a value to a location */
  274. static bfd_reloc_status_type
  275. my_add_to(PTR data, int offset, int size, int add)
  276. {
  277.   signed char *p;
  278.   int val;
  279.   bfd_reloc_status_type ret;
  280.  
  281.   DPRINT(5,("Entering add_value\n"));
  282.  
  283.   ret=bfd_reloc_ok;
  284.   p=((signed char*)data)+offset;
  285.  
  286.   switch (size)
  287.     {
  288.     case 0: /* byte size */
  289.       val=(int)(p[0]);
  290.       val+=add;
  291.       if ((val&0xffffff00)!=0 && (val&0xffffff00)!=0xffffff00) /* Overflow */
  292.     {
  293.       ret=bfd_reloc_overflow;
  294.     }
  295.       p[0]=val&0xff;
  296.       break;
  297.  
  298.     case 1: /* word size */
  299.       val=(int)((p[1]&0xff)|(p[0]<<8));
  300.       val+=add;
  301.       if ((val&0xffff0000)!=0 && (val&0xffff0000)!=0xffff0000) /* Overflow */
  302.     {
  303.       ret=bfd_reloc_overflow;
  304.     }
  305.       p[1]=val&0xff;
  306.       p[0]=((val&0xff00)>>8)&0xff;
  307.       break;
  308.  
  309.     case 2: /* long word */
  310.       /* dgv -- FIXME: there is obviously something wrong with the double assignment
  311.      below. Turning val=+add into val+=add does no good. Needs further
  312.      investigation ! */     
  313.       val = p[3] | ((int)(p[2]<<8)) | ((int)(p[1]<<16)) | ((int)(p[0]<<24));
  314.       val += add;
  315.       p[3] = val & 0xff;
  316.       p[2] = (val >> 8) & 0xff;
  317.       p[1] = (val >> 16) & 0xff;
  318.       p[0] = (val >> 24) & 0xff;
  319.       break;
  320.       
  321.     default: /* Error */
  322.       ret=bfd_reloc_notsupported;
  323.       break;
  324.     }/* Of switch */
  325.  
  326.   DPRINT(5,("Leaving add_value\n"));
  327.   return (ret);
  328. }
  329.  
  330. /* Set a value to a location */
  331. static bfd_reloc_status_type
  332. my_set_to(PTR data, int offset, int size, int val)
  333. {
  334.   signed char *p;
  335.   bfd_reloc_status_type ret;
  336.  
  337.   DPRINT(5,("Entering add_value\n"));
  338.  
  339.   ret=bfd_reloc_ok;
  340.   p=((signed char*)data)+offset;
  341.  
  342.   switch (size)
  343.     {
  344.     case 0: /* byte size */
  345.       if ((val&0xffffff00)!=0 && (val&0xffffff00)!=0xffffff00) /* Overflow */
  346.     {
  347.       ret=bfd_reloc_overflow;
  348.     }
  349.       p[0]=val&0xff;
  350.       break;
  351.  
  352.     case 1: /* word size */
  353.       if ((val&0xffff0000)!=0 && (val&0xffff0000)!=0xffff0000) /* Overflow */
  354.     {
  355.       ret=bfd_reloc_overflow;
  356.     }
  357.       p[1]=val&0xff;
  358.       p[0]=((val&0xff00)>>8)&0xff;
  359.       break;
  360.  
  361.     case 2: /* long word */
  362.       p[3] = val & 0xff;
  363.       p[2] = (val >> 8) & 0xff;
  364.       p[1] = (val >> 16) & 0xff;
  365.       p[0] = (val >> 24) & 0xff;
  366.       break;
  367.       
  368.     default: /* Error */
  369.       ret=bfd_reloc_notsupported;
  370.       break;
  371.     }/* Of switch */
  372.  
  373.   DPRINT(5,("Leaving set_value\n"));
  374.   return (ret);
  375. }
  376.  
  377. /* Perform an Amiga relocation */
  378. static bfd_reloc_status_type 
  379. amiga_perform_reloc(bfd *abfd, arelent *r, PTR data, asection *sec, bfd *obfd,
  380.             char **error_message)
  381. {
  382.   asymbol *sym; /* Reloc is relative to sym */
  383.   asection *target_section; /* reloc is relative to this section */
  384.   int relocation;
  385.   boolean copy;
  386.   bfd_reloc_status_type ret;
  387.   int size = 2;
  388.  
  389.   DPRINT(5,("Entering APR\nflavour is %d (aflavour=%d, aout_flavour=%d)\n",
  390.         sec->owner->xvec->flavour, bfd_target_amiga_flavour,
  391.         bfd_target_aout_flavour));
  392.  
  393.   /* If obfd==NULL: Apply the reloc, if possible. */
  394.   /* Else: Modify it and return */
  395.  
  396.   if (obfd!=NULL) /* Only modify the reloc */
  397.     {
  398.       r->address+=sec->output_offset;
  399.       sec->output_section->flags|=SEC_RELOC;
  400.       DPRINT(5,("Leaving APR, modified case \n"));
  401.       return bfd_reloc_ok;
  402.     }
  403.  
  404.   /* Try to apply the reloc */
  405.  
  406.   sym=*(r->sym_ptr_ptr);
  407.   target_section=sym->section;
  408.  
  409.   if (target_section==bfd_und_section_ptr) /* Error */
  410.     {
  411.       DPRINT(10,("perform_reloc: Target is undefined section\n"));
  412.       return bfd_reloc_undefined;
  413.     }
  414.   
  415.   relocation=0; copy=false; ret=bfd_reloc_ok;
  416.  
  417.   switch(r->howto->type)
  418.     {
  419.     case HUNK_RELOC32: /* 32 bit reloc */
  420.       DPRINT(5,("RELOC32\n"));
  421.       size=2;
  422.       if (target_section==bfd_abs_section_ptr) /* Ref to absolute hunk */
  423.     relocation=sym->value;
  424.       else if (target_section==bfd_com_section_ptr) /* ref to common */
  425.     {
  426.       relocation=0;
  427.       copy=true;
  428.     }
  429.       else
  430.     {
  431.       /* If we access a symbol in the .bss section, we have to convert
  432.          this to an access to .data section */
  433.       /* This is done through a change to the symbol... */
  434.       if (amiga_base_relative && (strcmp(sym->section->output_section->name,
  435.                          ".bss")==0))
  436.         {
  437.           /* get value for .data section */
  438.           bfd *ibfd;
  439.           asection *s;
  440.  
  441.           ibfd=target_section->output_section->owner;
  442.           for (s=ibfd->sections;s!=NULL;s=s->next)
  443.         if (strcmp(s->name,".data")==0)
  444.           {
  445.             sym->section->output_offset=s->_raw_size;
  446.             sym->section->output_section=s;
  447.           }
  448.         }
  449.  
  450.       relocation=0;
  451.       copy=true;
  452.     }
  453.       break;
  454.  
  455.     case HUNK_RELOC8:
  456.     case HUNK_RELOC16:
  457.       DPRINT(5,("RELOC16/8\n"));
  458.       size=(r->howto->type==HUNK_RELOC8)?0:1;
  459.       if (target_section==bfd_abs_section_ptr) /* Ref to absolute hunk */
  460.     relocation=sym->value;
  461.       if (target_section==bfd_com_section_ptr) /* Error.. */
  462.     {
  463.       relocation=0;
  464.       copy=false;
  465.       ret=bfd_reloc_undefined;
  466.     }
  467.       else
  468.     {
  469.       DPRINT(5,("PC relative\n"));
  470.       /* This is a pc relative hunk... */
  471.       if (sec->output_section!=target_section->output_section) /* Error */
  472.         {
  473.           DPRINT(10,("pc relative, but out of range I\n"));
  474.           relocation=0;
  475.           copy =false;
  476.           ret=bfd_reloc_outofrange;
  477.         }
  478.       else
  479.         { /* Same section */
  480.           relocation=-(r->address+sec->output_offset);
  481.           copy=false;
  482.         }
  483.     }
  484.       break;
  485.       
  486.     case HUNK_DREL32: /* baserel relocs */
  487.     case HUNK_DREL16:
  488.     case HUNK_DREL8:
  489.       DPRINT(5,("HUNK_BASEREL relocs\n"));
  490.  
  491.       /* Relocs are always relative to the symbol ___a4_init */
  492.       /* Relocs to .bss section are converted to a reloc to .data section, since
  493.      .bss section contains only COMMON sections...... and should be
  494.      following .data section.. */
  495.  
  496.       size=(r->howto->type==HUNK_DREL32)?2:((r->howto->type==HUNK_DREL16)?1:0);
  497.       
  498.       if (target_section==bfd_abs_section_ptr)
  499.     {
  500.       relocation=sym->value;
  501.     }
  502.       else 
  503.     {
  504.       if (! (AMIGA_DATA (target_section->output_section->owner)->baserel))
  505.         {
  506.           fprintf(stderr,"Base symbol for base relative reloc not defined,"
  507.               "section %s, reloc to symbol %s\n", sec->name, sym->name);
  508.           copy=false;
  509.           ret=bfd_reloc_notsupported;
  510.           break;
  511.         }
  512.  
  513.       /* If target->out is .bss, add the value of the .data section to sym->value and
  514.          set output_section new to .data section.... */
  515.       if (strcmp(target_section->output_section->name,".bss")==0)
  516.         {
  517.           bfd *ibfd;
  518.           asection *s;
  519.  
  520.           ibfd=target_section->output_section->owner;
  521.           for (s=ibfd->sections;s!=NULL;s=s->next)
  522.         if (strcmp(s->name,".data")==0)
  523.           {
  524.             sym->section->output_section=s;
  525.             sym->section->output_offset=s->_raw_size;
  526.           }
  527.         }
  528.  
  529.       relocation = sym->value + sym->section->output_offset
  530.         - (AMIGA_DATA (target_section->output_section->owner))->a4init
  531.         + r->addend;
  532.       copy=false; 
  533.     }
  534.       break;
  535.       
  536.     default:
  537.       fprintf(stderr,"Error:Not supported reloc type:%d\n",r->howto->type);
  538.       copy=false;
  539.       relocation=0;
  540.       ret=bfd_reloc_notsupported;
  541.       break;
  542.     } /* Of switch */
  543.   
  544.   /* Add in relocation */
  545.   if (relocation!=0)
  546.     ret=my_add_to(data,r->address,size,relocation);
  547.   
  548.   if (copy)/* Copy reloc to output section */
  549.     {
  550.       DPRINT(5,("Copying reloc\n"));
  551.       target_section=sec->output_section;
  552.       r->address+=sec->output_offset;
  553.       target_section->orelocation[target_section->reloc_count++]=r;
  554.       sec->output_section->flags|=SEC_RELOC;
  555.     }
  556.   DPRINT(5,("Leaving a_perform_reloc\n"));
  557.   return ret;
  558. }
  559.  
  560.  
  561. /* Perform an a.out reloc */
  562. static bfd_reloc_status_type 
  563. aout_perform_reloc(bfd *abfd, arelent *r, PTR data, asection *sec, bfd *obfd,
  564.            char **error_message)
  565. {
  566.   asymbol *sym; /* Reloc is relative to this */
  567.   asection *target_section; /* reloc is relative to this section */
  568.   int relocation;
  569.   boolean copy, addval = true;
  570.   bfd_reloc_status_type ret;
  571.   int size = 2;
  572.  
  573.   /* If obfd==NULL: Apply the reloc, if possible. */
  574.   /* Else: Modify it and return */
  575.   DPRINT(5,("Entering aout_perf_reloc\n"));
  576.   if (obfd!=NULL) /* Only modify the reloc */
  577.     {
  578.       r->address+=sec->output_offset;
  579.       DPRINT(5,("Leaving aout_perf_reloc, modified\n"));
  580.       return bfd_reloc_ok;
  581.     }
  582.  
  583.   sym=*(r->sym_ptr_ptr);
  584.   target_section=sym->section;
  585.  
  586.   if (target_section==bfd_und_section_ptr) /* Error */
  587.     {
  588.       DPRINT(10,("target_sec=UND, aout_perf_rel\n"));
  589.       return bfd_reloc_undefined;
  590.     }
  591.   relocation=0; copy=false; ret=bfd_reloc_ok;
  592.  
  593.   switch (r->howto->type)
  594.     {
  595.     case 0: /* 8 bit reloc, pc relative or absolute */
  596.     case 1: /* 16 bit reloc */
  597.       DPRINT(10,("16/8 bit relative\n"));
  598.       size=r->howto->type;
  599.       if (target_section==bfd_abs_section_ptr) /* Ref to absolute hunk */
  600.     relocation=sym->value;
  601.       else if (target_section==bfd_com_section_ptr) /* Error.. */
  602.     {
  603.       relocation=0;
  604.       copy=false;
  605.       ret=bfd_reloc_undefined;
  606.       fprintf(stderr,"Pc relative relocation to  common symbol \"%s\" "
  607.           "in section %s\n", sym->name,sec->name);
  608.       DPRINT(10,("Ref to common symbol...aout_perf_reloc\n"));
  609.     }
  610.       else 
  611.     {
  612.       /* This is a pc relative hunk... or a baserel... */
  613.       if (sec->output_section!=target_section->output_section)
  614.         /* Error or baserel */
  615.         {
  616.           if (target_section->output_section->flags&SEC_DATA!=0)
  617.         /* Baserel reloc */
  618.         {
  619.           goto baserel; /* Dirty, but no code doubling.. */
  620.         }/* Of is baserel */
  621.  
  622.           relocation=0;
  623.           copy =false;
  624.           ret=bfd_reloc_outofrange;
  625.           fprintf(stderr,"pc relative relocation out of range in section"
  626.               "%s. Relocation was to symbol %s\n",sec->name,sym->name);
  627.  
  628.           DPRINT(10,("Section%s, target %s: Reloc out of range..."
  629.              "not same section, aout_perf\nsec->out=%s, target->out"
  630.              "=%s, offset=%lx\n",sec->name, target_section->name,
  631.              sec->output_section->name,
  632.              target_section->output_section->name,r->address));
  633.         }
  634.       else
  635.         { /* Same section */
  636.           relocation=-(r->address+sec->output_offset);
  637.           copy=false;
  638.           DPRINT(5,("Reloc to same section...\n"));
  639.         }
  640.     }
  641.       break;
  642.  
  643.     case 4: /* 8 bit displacement */
  644.     case 5: /* 16 bit displacement */
  645.     case 6: /* 32 bit displacement */
  646.       size=r->howto->type - 4;
  647.       if (target_section == bfd_abs_section_ptr) /* Ref to absolute hunk */
  648.       relocation = sym->value;
  649.        else
  650.          {
  651.            relocation = (sym->value + target_section->output_offset) -
  652.              (r->address + sec->output_offset);
  653.            if (size == 0)
  654.              relocation--;
  655.        addval = false;
  656.        copy = 0;
  657.          }
  658.       break;
  659.  
  660.     case 2: /* 32 bit reloc, abs. or relative */
  661.       DPRINT(10,("32 bit\n"));
  662.       size=2;
  663.       if (target_section==bfd_abs_section_ptr) /* Ref to absolute hunk */
  664.     relocation=sym->value;
  665.       else if (target_section==bfd_com_section_ptr) /* ref to common */
  666.     {
  667.       relocation=0;
  668.       copy=true;
  669.     }
  670.       else
  671.     {
  672.       /* If we access a symbol in the .bss section, we have to convert
  673.          this to an access to .data section*/
  674.       /* This is done through a change to the output section of
  675.          the symbol... */
  676.       if (amiga_base_relative && (strcmp(sym->section->output_section->name,
  677.                          ".bss")==0))
  678.         {
  679.           /* get value for .data section */
  680.           bfd *ibfd;
  681.           asection *s;
  682.  
  683.           ibfd=target_section->output_section->owner;
  684.           for (s=ibfd->sections;s!=NULL;s=s->next)
  685.         if (strcmp(s->name,".data")==0)
  686.           {
  687.             sym->section->output_section=s;
  688.             sym->section->output_offset+=s->_raw_size;
  689.           }
  690.         }
  691.       relocation=0;
  692.       copy=true;
  693.     }
  694.       DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
  695.          target_section->output_section->name,
  696.          target_section->output_section,sec->output_section->name,
  697.          sec->output_section,sym->name));
  698.       break;
  699.  
  700.     case 9: /* 16 bit base relative */
  701.     case 10: /* 32 bit base relative */
  702.       DPRINT(10,("32/16 bit baserel\n"));
  703.       /* We use the symbol ___a4_init as base */
  704.       size=r->howto->type-8;
  705.       
  706.     baserel: 
  707.       if (target_section==bfd_abs_section_ptr)
  708.     {
  709.       relocation=sym->value;
  710.     }
  711.       else if (target_section==bfd_com_section_ptr) /* Error.. */
  712.     {
  713.       relocation=0;
  714.       copy=false;
  715.       ret=bfd_reloc_undefined;
  716.       fprintf(stderr,"Baserelative relocation to common \"%s\"\n",
  717.           sym->name);
  718.  
  719.       DPRINT(10,("Ref to common symbol...aout_perf_reloc\n"));
  720.     }
  721.       else /* Target section and sec need not be the same... */
  722.     {
  723.       if (! (AMIGA_DATA (target_section->output_section->owner)->baserel))
  724.  
  725.         {
  726.           fprintf(stderr,"Base symbol for base relative reloc not defined,"
  727.               "section %s, reloc to symbol %s\n", sec->name, sym->name);
  728.           copy=false;
  729.           ret=bfd_reloc_notsupported;
  730.           DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
  731.              target_section->output_section->name,
  732.              target_section->output_section,
  733.              sec->output_section->name,
  734.              sec->output_section,sym->name));
  735.           
  736.           break;
  737.         }
  738.       
  739.       /* If target->out is .bss, add the value of the .data section....
  740.          to sym, set new output_section */
  741.       if (strcmp(target_section->output_section->name,".bss")==0)
  742.         {
  743.           bfd *ibfd;
  744.           asection *s;
  745.  
  746.           ibfd=target_section->output_section->owner;
  747.  
  748.           for (s=ibfd->sections;s!=NULL;s=s->next)
  749.         if (strcmp(s->name,".data")==0)
  750.           {
  751.             sym->section->output_offset+=s->_raw_size;
  752.             sym->section->output_section=s;
  753.           }
  754.         }
  755.  
  756.       relocation = sym->value+target_section->output_offset - 0x7ffe;
  757.  
  758.       /* if the symbol is in bss, subtract the offset that gas has put
  759.          into the opcode */
  760.       if (target_section->index == 2)
  761.         relocation -= abfd->tdata.aout_data->a.datasec->_raw_size;
  762.  
  763.       addval = true;
  764.       copy = false;
  765.  
  766.       DPRINT (20, ("symbol=%s (0x%lx)\nsection %s (0x%lx; %s; output=0x%lx)"
  767.                "\nrelocation @0x%lx\n\n", sym->name, sym->value,
  768.                sym->section->name, (unsigned long)sym->section,
  769.                sym->section->owner->filename, sym->section->output_offset,
  770.                r->address));
  771.     }
  772.       DPRINT(10,("target->out=%s(%lx), sec->out=%s(%lx), symbol=%s\n",
  773.          target_section->output_section->name,
  774.          target_section->output_section,sec->output_section->name,
  775.          sec->output_section,sym->name));
  776.       break;
  777.       
  778.     default:
  779.       copy=false;
  780.       relocation=0;
  781.       ret=bfd_reloc_notsupported;
  782.       fprintf(stderr,"Unsupported reloc: %d\n",r->howto->type);
  783.       break;
  784.  
  785.     }/* Of switch */
  786.  
  787.   /* Add in relocation */
  788.   if (relocation!=0)
  789.     if (addval)
  790.       ret=my_add_to(data,r->address,size,relocation);
  791.     else
  792.       ret=my_set_to(data,r->address,size,relocation);
  793.  
  794.   if (copy)/* Copy reloc to output section */
  795.     {
  796.       DPRINT(5,("Copying reloc\n"));
  797.       target_section=sec->output_section;
  798.       r->address+=sec->output_offset;
  799.       target_section->orelocation[target_section->reloc_count++]=r;
  800.     }
  801.   DPRINT(5,("Leaving aout_perf_reloc with %d (OK=%d)\n",ret,bfd_reloc_ok));
  802.   return ret;
  803. }
  804.  
  805.  
  806. /* The final link routine, used both by Amiga and a.out backend*/
  807. /* This is nearly a copy of _bfd_generic_final_link */
  808. boolean
  809. amiga_final_link (abfd, info)
  810.      bfd *abfd;
  811.      struct bfd_link_info *info;
  812. {
  813.   bfd *sub;
  814.   asection *o,*act_sec;
  815.   struct bfd_link_order *p;
  816.   size_t outsymalloc;
  817.   struct generic_write_global_symbol_info wginfo;
  818.   struct bfd_link_hash_entry *h =
  819.     bfd_link_hash_lookup (info->hash, "___a4_init", false, false, true);
  820.  
  821.   if (h && h->type == bfd_link_hash_defined) {
  822.     AMIGA_DATA (abfd)->baserel = true;
  823.     AMIGA_DATA (abfd)->a4init = h->u.def.value;
  824.   }
  825.   else
  826.     AMIGA_DATA (abfd)->baserel = false;
  827.  
  828.   DPRINT(5,("Entering final_link\n"));
  829.  
  830.   if (abfd->xvec->flavour == bfd_target_aout_flavour)
  831.     return amiga_aout_bfd_final_link(abfd, info);
  832.  
  833.   abfd->outsymbols = (asymbol **) NULL;
  834.   abfd->symcount = 0;
  835.   outsymalloc = 0;
  836.  
  837.   /* Build the output symbol table.  */
  838.   for (sub = info->input_bfds; sub != (bfd *) NULL; sub = sub->link_next)
  839.     if (! _bfd_generic_link_output_symbols (abfd, sub, info, &outsymalloc))
  840.       return false;
  841.  
  842.   DPRINT(10,("Did build output symbol table\n"));
  843.  
  844.   /* Accumulate the global symbols.  */
  845.   wginfo.info = info;
  846.   wginfo.output_bfd = abfd;
  847.   wginfo.psymalloc = &outsymalloc;
  848.   _bfd_generic_link_hash_traverse (_bfd_generic_hash_table (info),
  849.                                    _bfd_generic_link_write_global_symbol,
  850.                                    (PTR) &wginfo);
  851.  
  852.   DPRINT(10,("Accumulated global symbols\n"));
  853.  
  854.   DPRINT(10,("Output bfd is %s(%lx)\n",abfd->filename,abfd));
  855.  
  856.   /* Allocate space for the output relocs for each section.  */
  857.   /* We also handle base-relative linking special, by setting the .data
  858.      sections real length to it's length + .bss length */
  859.   /* This is different to bfd_generic_final_link: We ALWAYS alloc space for
  860.      the relocs, because we may need it anyway */
  861.   for (o = abfd->sections;
  862.        o != (asection *) NULL;
  863.        o = o->next)
  864.     {
  865.       /* If section is .data, find .bss and add that length */
  866.       if (!info->relocateable && amiga_base_relative &&
  867.       (strcmp(o->name,".data")==0))
  868.     {
  869.       if (abfd->xvec->flavour!=bfd_target_amiga_flavour) /* oops */
  870.         {
  871.           fprintf(stderr,"You can't use base relative linking with"
  872.               " partial links.\n");
  873.         }
  874.       else
  875.         {
  876.           for (act_sec=abfd->sections; act_sec!=NULL;act_sec=act_sec->next)
  877.         if (strcmp(act_sec->name,".bss")==0)
  878.           amiga_per_section(o)->real_length=o->_raw_size +
  879.             act_sec->_raw_size;
  880.         }
  881.     }/* Of base-relative linking */
  882.  
  883.       DPRINT(10,("Section in output bfd is %s (%lx)\n",o->name,o));
  884.  
  885.       o->reloc_count = 0;
  886.       for (p = o->link_order_head;
  887.        p != (struct bfd_link_order *) NULL;
  888.        p = p->next)
  889.     {
  890.       if (p->type == bfd_section_reloc_link_order
  891.           || p->type == bfd_symbol_reloc_link_order)
  892.         ++o->reloc_count;
  893.       else if (p->type == bfd_indirect_link_order)
  894.         {
  895.           asection *input_section;
  896.           bfd *input_bfd;
  897.           long relsize;
  898.           arelent **relocs;
  899.           asymbol **symbols;
  900.           long reloc_count;
  901.           
  902.           input_section = p->u.indirect.section;
  903.           input_bfd = input_section->owner;
  904.  
  905.           DPRINT(10,("\tIndirect section from bfd %s, section is %s(%lx)"
  906.              " (COM=%lx)\n",
  907.              input_bfd->filename,input_section->name,input_section,
  908.              bfd_com_section_ptr));
  909.  
  910.           relsize = bfd_get_reloc_upper_bound (input_bfd,
  911.                            input_section);
  912.           if (relsize < 0)
  913.         {
  914.           DPRINT(10,("Relsize<0.I..in bfd %s, sec %s\n",
  915.                  input_bfd->filename, input_section->name));
  916.           return false;
  917.         }
  918.  
  919.           relocs = (arelent **) malloc ((size_t) relsize);
  920.  
  921.           if (!relocs && relsize != 0)
  922.         {
  923.           bfd_set_error (bfd_error_no_memory);
  924.           return false;
  925.         }
  926.           symbols = _bfd_generic_link_get_symbols (input_bfd);
  927.           reloc_count = bfd_canonicalize_reloc (input_bfd,
  928.                             input_section,
  929.                             relocs,
  930.                             symbols);
  931.           if (reloc_count < 0)
  932.         {
  933.           DPRINT(10,("Relsize<0.II..in bfd %s, sec %s\n",
  934.                  input_bfd->filename, input_section->name));
  935.           return false;
  936.         }
  937.  
  938.           BFD_ASSERT (reloc_count == input_section->reloc_count);
  939.           o->reloc_count += reloc_count;
  940.           free (relocs);
  941.         }
  942.     }
  943.       if (o->reloc_count > 0)
  944.     {
  945.       o->orelocation = ((arelent **)
  946.                 bfd_alloc (abfd,
  947.                        (o->reloc_count
  948.                     * sizeof (arelent *))));
  949.  
  950.       if (!o->orelocation)
  951.         {
  952.           bfd_set_error (bfd_error_no_memory);
  953.           return false;
  954.         }
  955.       /* o->flags |= SEC_RELOC; There may be no relocs. This can be
  956.          determined only later */
  957.       /* Reset the count so that it can be used as an index
  958.          when putting in the output relocs.  */
  959.       o->reloc_count = 0;
  960.     }
  961.     }
  962.  
  963.   DPRINT(10,("Got all relocs\n"));
  964.  
  965.   /* Handle all the link order information for the sections.  */
  966.   for (o = abfd->sections;
  967.        o != (asection *) NULL;
  968.        o = o->next)
  969.     {
  970.       for (p = o->link_order_head;
  971.            p != (struct bfd_link_order *) NULL;
  972.            p = p->next)
  973.         {
  974.           switch (p->type)
  975.             {
  976.             case bfd_section_reloc_link_order:
  977.             case bfd_symbol_reloc_link_order:
  978.               if (! amiga_reloc_link_order (abfd, info, o, p)) /* We use an own routine */
  979.                 return false;
  980.               break;
  981.             case bfd_indirect_link_order:
  982.               if (! default_indirect_link_order (abfd, info, o, p, true)) 
  983.         /* Calls our get_relocated_section_contents*/
  984.                 return false;
  985.               break;
  986.             default:
  987.               if (! _bfd_default_link_order (abfd, info, o, p))
  988.                 return false;
  989.               break;
  990.             }
  991.         }
  992.     }
  993.   if (abfd->xvec->flavour==bfd_target_amiga_flavour&&!info->relocateable)
  994.     AMIGA_DATA(abfd)->IsLoadFile=true;
  995.  
  996.   DPRINT(10,("Leaving final_link\n"));
  997.   return true;
  998. }
  999.  
  1000.  
  1001. /* Handle reloc link order . This is nearly a copy from generic_reloc_link_order
  1002.    in linker.c*/
  1003. static boolean 
  1004. amiga_reloc_link_order(bfd *abfd,struct bfd_link_info *info  , asection *sec,
  1005.                struct bfd_link_order *link_order)
  1006. {
  1007.    amiga_reloc_type *r;
  1008.  
  1009.    DPRINT(5,("Entering amiga_reloc_link_order\n"));
  1010.  
  1011.    /* We generate a new AMIGA style reloc */
  1012.    BFD_ASSERT(sec->orelocation!=NULL);
  1013.  
  1014.    if (sec->orelocation == (arelent **) NULL)
  1015.      {
  1016.        DPRINT(10,("aborting, since orelocation==NULL\n"));
  1017.        abort ();
  1018.      }
  1019.  
  1020.    r = (amiga_reloc_type *) bfd_zalloc (abfd, sizeof (amiga_reloc_type));
  1021.    if (r ==  NULL)
  1022.      {
  1023.        bfd_set_error (bfd_error_no_memory);
  1024.        DPRINT(5,("Leaving amiga_reloc_link, no mem\n"));
  1025.        return false;
  1026.      }
  1027.    
  1028.    r->relent.address = link_order->offset;
  1029.    r->relent.howto = bfd_reloc_type_lookup (abfd, link_order->u.reloc.p->reloc);
  1030.    if (r->relent.howto ==  NULL)
  1031.      {
  1032.        bfd_set_error (bfd_error_bad_value);
  1033.        DPRINT(5,("Leaving amiga_reloc_link, bad value\n"));
  1034.        return false;
  1035.      }
  1036.    
  1037.    /* Get the symbol to use for the relocation.  */
  1038.    if (link_order->type == bfd_section_reloc_link_order)
  1039.      r->relent.sym_ptr_ptr = link_order->u.reloc.p->u.section->symbol_ptr_ptr;
  1040.    else
  1041.      {
  1042.        struct generic_link_hash_entry *h;
  1043.        
  1044.        h = _bfd_generic_link_hash_lookup (_bfd_generic_hash_table (info),
  1045.                       link_order->u.reloc.p->u.name,
  1046.                       false, false, true);
  1047.        if (h == (struct generic_link_hash_entry *) NULL
  1048.        || ! h->written)
  1049.      {
  1050.        if (! ((*info->callbacks->unattached_reloc)
  1051.           (info, link_order->u.reloc.p->u.name,
  1052.            (bfd *) NULL, (asection *) NULL, (bfd_vma) 0)))
  1053.          return false;
  1054.        bfd_set_error (bfd_error_bad_value);
  1055.        DPRINT(5,("Leaving amiga_reloc_link, bad value in hash lookup\n"));
  1056.        return false;
  1057.      }
  1058.        r->relent.sym_ptr_ptr = &h->sym;
  1059.      }
  1060.    DPRINT(5,("Got symbol for relocation\n"));
  1061.    /* Store the addend */
  1062.    r->relent.addend = link_order->u.reloc.p->addend;
  1063.  
  1064.  
  1065.    /* If we are generating relocateable output, just add the reloc */
  1066.    if (info->relocateable)
  1067.      {
  1068.        DPRINT(5,("Adding reloc\n"));
  1069.        sec->orelocation[sec->reloc_count] = (arelent *)r;
  1070.        ++sec->reloc_count; 
  1071.        sec->flags|=SEC_RELOC;
  1072.      }
  1073.    else
  1074.      { /* Try to apply the reloc */
  1075.        char *em="";
  1076.        PTR data;
  1077.        bfd_reloc_status_type ret;
  1078.  
  1079.        DPRINT(5,("Apply link_order_reloc\n"));
  1080.        /*FIXME: Maybe, we have to get the section contents, before we use them,
  1081.      if they have not been
  1082.      set by now.. */
  1083.  
  1084.        BFD_ASSERT(sec->contents!=NULL);
  1085.        data=(PTR)(sec->contents);
  1086.  
  1087.        if (bfd_get_flavour(abfd)==bfd_target_amiga_flavour)
  1088.      ret=amiga_perform_reloc(abfd,(arelent *)r,data,sec,NULL,&em);
  1089.        else
  1090.      ret=aout_perform_reloc(abfd,(arelent *)r,data,sec,NULL,&em);
  1091.  
  1092.        if (ret!=bfd_reloc_ok)
  1093.      {
  1094.        DPRINT(5,("Leaving amiga_reloc_link, value false\n"));
  1095.        return false;
  1096.      }
  1097.      }
  1098.    DPRINT(5,("Leaving amiga_reloc_link\n"));
  1099.    return true;
  1100. }
  1101.