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".
6 static char rcsid[] = "$Id: relocate.c,v 3.5 1994/06/24 10:35:11 ceriel Exp $";
15 #define UBYTE(x) ((x) & BYTEMASK)
18 * The bits in type indicate how many bytes the value occupies and what
19 * significance should be attributed to each byte.
26 unsigned short word0, word1;
28 switch (type & RELSZ) {
30 return UBYTE(addr[0]);
33 return (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
35 return (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
38 word0 = (UBYTE(addr[0]) << WIDTH) + UBYTE(addr[1]);
39 word1 = (UBYTE(addr[2]) << WIDTH) + UBYTE(addr[3]);
41 word0 = (UBYTE(addr[1]) << WIDTH) + UBYTE(addr[0]);
42 word1 = (UBYTE(addr[3]) << WIDTH) + UBYTE(addr[2]);
45 return ((long)word0 << (2 * WIDTH)) + word1;
47 return ((long)word1 << (2 * WIDTH)) + word0;
49 fatal("bad relocation size");
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.
60 putvalu(valu, addr, type)
65 unsigned short word0, word1;
67 switch (type & RELSZ) {
73 addr[0] = valu >> WIDTH;
77 addr[1] = valu >> WIDTH;
82 word0 = valu >> (2 * WIDTH);
86 word1 = valu >> (2 * WIDTH);
89 addr[0] = word0 >> WIDTH;
91 addr[2] = word1 >> WIDTH;
95 addr[1] = word0 >> WIDTH;
97 addr[3] = word1 >> WIDTH;
101 fatal("bad relocation size");
105 extern unsigned short NLocals, NGlobals;
106 extern struct outsect outsect[];
107 extern struct orig relorig[];
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.
122 addrelo(relo, names, valu_out)
123 struct outrelo *relo;
124 struct outname *names;
125 long *valu_out; /* Out variable. */
127 register struct outname *local = &names[relo->or_nami];
128 register unsigned short index = NLocals;
129 register long valu = *valu_out;
131 if ((local->on_type & S_SCT)) {
132 register int sectindex = (local->on_type & S_TYP) - S_MIN;
134 valu += relorig[sectindex].org_size;
135 valu += outsect[sectindex].os_base;
136 index += NGlobals + sectindex;
138 register struct outname *name;
140 extern struct outname *searchname();
141 extern unsigned indexof();
142 extern struct outhead outhead;
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);
151 valu += name->on_valu;
152 if ((name->on_type & S_TYP) == S_ABS) {
153 index += NGlobals + outhead.oh_nsect;
155 else index += NGlobals +
156 (name->on_type & S_TYP) - S_MIN;
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.
168 relocate(head, emit, names, relo, off)
169 struct outhead *head;
171 struct outname names[];
172 struct outrelo *relo;
176 int sectindex = relo->or_sect - S_MIN;
177 extern struct outhead outhead;
180 * Pick up previous value at location to be relocated.
182 valu = getvalu(emit + (relo->or_addr - off), relo->or_type);
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
188 * - the first name outside! the name table (argh)
190 if (relo->or_nami < head->oh_nname) {
191 /* First two cases. */
192 relo->or_nami = addrelo(relo, names, &valu);
195 * Third case: it is absolute. The relocation of absolute
196 * names is always 0. We only need to change the index.
198 relo->or_nami = NLocals + NGlobals + outhead.oh_nsect;
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.
207 if (relo->or_type & RELPC)
208 valu -= relorig[sectindex].org_size+outsect[sectindex].os_base;
211 * Now put the value back.
213 putvalu(valu, emit + (relo->or_addr - off), relo->or_type);
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.
220 relo->or_addr += relorig[sectindex].org_size;