Pristine Ack-5.5
[Ack-5.5.git] / util / led / relocate.c
1 /*
2  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
3  * See the copyright notice in the ACK home directory, in the file "Copyright".
4  */
5 #ifndef lint
6 static char rcsid[] = "$Id: relocate.c,v 3.5 1994/06/24 10:35:11 ceriel Exp $";
7 #endif
8
9 #include <out.h>
10 #include "const.h"
11 #include "debug.h"
12 #include "defs.h"
13 #include "orig.h"
14
15 #define UBYTE(x)        ((x) & BYTEMASK)
16
17 /*
18  * The bits in type indicate how many bytes the value occupies and what
19  * significance should be attributed to each byte.
20  */
21 static long
22 getvalu(addr, type)
23         char    addr[];
24         char    type;
25 {
26         unsigned short  word0, word1;
27
28         switch (type & RELSZ) {
29         case RELO1:
30                 return UBYTE(addr[0]);
31         case RELO2:
32                 if (type & RELBR)
33                         return (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
34                 else
35                         return (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
36         case RELO4:
37                 if (type & RELBR) {
38                         word0 = (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
39                         word1 = (UBYTE(addr[2]) << WIDTH) + UBYTE(addr[3]);
40                 } else {
41                         word0 = (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
42                         word1 = (UBYTE(addr[3]) << WIDTH) + UBYTE(addr[2]);
43                 }
44                 if (type & RELWR)
45                         return ((long)word0 << (2 * WIDTH)) + word1;
46                 else
47                         return ((long)word1 << (2 * WIDTH)) + word0;
48         default:
49                 fatal("bad relocation size");
50         }
51         /* NOTREACHED */
52 }
53
54 /*
55  * The bits in type indicate how many bytes the value occupies and what
56  * significance should be attributed to each byte.
57  * We do not check for overflow.
58  */
59 static
60 putvalu(valu, addr, type)
61         long    valu;
62         char    addr[];
63         char    type;
64 {
65         unsigned short  word0, word1;
66
67         switch (type & RELSZ) {
68         case RELO1:
69                 addr[0] = valu;
70                 break;
71         case RELO2:
72                 if (type & RELBR) {
73                         addr[0] = valu >> WIDTH;
74                         addr[1] = valu;
75                 } else {
76                         addr[0] = valu;
77                         addr[1] = valu >> WIDTH;
78                 }
79                 break;
80         case RELO4:
81                 if (type & RELWR) {
82                         word0 = valu >> (2 * WIDTH);
83                         word1 = valu;
84                 } else {
85                         word0 = valu;
86                         word1 = valu >> (2 * WIDTH);
87                 }
88                 if (type & RELBR) {
89                         addr[0] = word0 >> WIDTH;
90                         addr[1] = word0;
91                         addr[2] = word1 >> WIDTH;
92                         addr[3] = word1;
93                 } else {
94                         addr[0] = word0;
95                         addr[1] = word0 >> WIDTH;
96                         addr[2] = word1;
97                         addr[3] = word1 >> WIDTH;
98                 }
99                 break;
100         default:
101                 fatal("bad relocation size");
102         }
103 }
104
105 extern unsigned short   NLocals, NGlobals;
106 extern struct outsect   outsect[];
107 extern struct orig      relorig[];
108
109 /*
110  * There are two cases: `local' is an undefined external or common name,
111  * or `local' is a section name.
112  * First case: if the name has been defined in another module,
113  * its value is known and can be added. Or_nami will be the
114  * index of the name of the section in which this name was
115  * defined. Otherwise we must change or_nami to the index of
116  * this name in the name table of the output file and leave
117  * its value unchanged.
118  * Second case: we must update the value by the change
119  * in position of the section of local.
120  */
121 static unsigned
122 addrelo(relo, names, valu_out)
123         struct outrelo          *relo;
124         struct outname          *names;
125         long                    *valu_out;      /* Out variable. */
126 {
127         register struct outname *local = &names[relo->or_nami];
128         register unsigned short         index = NLocals;
129         register long           valu = *valu_out;
130
131         if ((local->on_type & S_SCT)) {
132                 register int    sectindex = (local->on_type & S_TYP) - S_MIN;
133
134                 valu += relorig[sectindex].org_size;
135                 valu += outsect[sectindex].os_base;
136                 index += NGlobals + sectindex;
137         } else {
138                 register struct outname *name;
139                 extern int              hash();
140                 extern struct outname   *searchname();
141                 extern unsigned         indexof();
142                 extern struct outhead   outhead; 
143
144                 name = searchname(local->on_mptr, hash(local->on_mptr));
145                 if (name == (struct outname *)0)
146                         fatal("name %s not found in pass 2", local->on_mptr);
147                 if (ISCOMMON(name) || ISUNDEFINED(name)) {
148                         debug("can't relocate from %s\n",local->on_mptr,0,0,0);
149                         index += indexof(name);
150                 } else {
151                         valu += name->on_valu;
152                         if ((name->on_type & S_TYP) == S_ABS) {
153                                 index += NGlobals + outhead.oh_nsect;
154                         }
155                         else    index += NGlobals +
156                                         (name->on_type & S_TYP) - S_MIN;
157                 }
158         }
159         *valu_out = valu;
160         return index;
161 }
162
163 /*
164  * This routine relocates a value in a section pointed to by `emit', of
165  * which the header is pointed to by `head'. Relocation is relative to the
166  * names in `names'; `relo' tells how to relocate.
167  */
168 relocate(head, emit, names, relo, off)
169         struct outhead  *head;
170         char            *emit;
171         struct outname  names[];
172         struct outrelo  *relo;
173         long            off;
174 {
175         long            valu;
176         int             sectindex = relo->or_sect - S_MIN;
177         extern struct outhead   outhead;
178
179         /*
180          * Pick up previous value at location to be relocated.
181          */
182         valu = getvalu(emit + (relo->or_addr - off), relo->or_type);
183         /*
184          * Or_nami is an index in the name table of the considered module.
185          * The name of which it is an index can be:
186          *      - an undefined external or a common name
187          *      - a section name
188          *      - the first name outside! the name table (argh)
189          */
190         if (relo->or_nami < head->oh_nname) {
191                 /* First two cases. */
192                 relo->or_nami = addrelo(relo, names, &valu);
193         } else {
194                 /*
195                  * Third case: it is absolute. The relocation of absolute
196                  * names is always 0. We only need to change the index.
197                  */
198                 relo->or_nami = NLocals + NGlobals + outhead.oh_nsect;
199         }
200
201         /*
202          * If relocation is pc-relative, we had to update the value by
203          * the change in distance between the referencING and referencED
204          * section. We already added the origin of the referencED section;
205          * now we subtract the origin of the referencING section.
206          */
207         if (relo->or_type & RELPC)
208                 valu -= relorig[sectindex].org_size+outsect[sectindex].os_base;
209
210         /*
211          * Now put the value back.
212          */
213         putvalu(valu, emit + (relo->or_addr - off), relo->or_type);
214
215         /*
216          * We must change the offset within the section of the value to be
217          * relocated to its offset in the new section. `Or_addr' must again be
218          * in the normal part, of course.
219          */
220         relo->or_addr += relorig[sectindex].org_size;
221 }