relocate.c 5.7 KB

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