dynld.c 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. #include "lib9.h"
  2. #include <a.out.h>
  3. #include <dynld.h>
  4. static ulong
  5. get2(uchar *b)
  6. {
  7. return (b[0] << 8) | b[1];
  8. }
  9. static ulong
  10. get4(uchar *b)
  11. {
  12. return (b[0] << 24) | (b[1] << 16) | (b[2] << 8) | b[3];
  13. }
  14. static ulong
  15. lgetbe(ulong l)
  16. {
  17. union {
  18. ulong l;
  19. uchar c[4];
  20. } u;
  21. u.l = l;
  22. return get4(u.c);
  23. }
  24. Dynsym*
  25. dynfindsym(char *s, Dynsym *tab, int ntab)
  26. {
  27. int n, n2, d;
  28. Dynsym *t, *m;
  29. t = tab;
  30. n = ntab;
  31. while(n > 0){
  32. n2 = n>>1;
  33. m = t+n2;
  34. d = strcmp(s, m->name);
  35. if(d < 0){
  36. n = n2;
  37. continue;
  38. }
  39. if(d > 0){
  40. t = m+1;
  41. n -= n2+1;
  42. continue;
  43. }
  44. return m;
  45. }
  46. return nil;
  47. }
  48. void*
  49. dynimport(Dynobj *o, char *name, ulong sig)
  50. {
  51. Dynsym *t;
  52. t = dynfindsym(name, o->export, o->nexport);
  53. if(t == nil || sig != 0 && t->sig != 0 && t->sig != sig)
  54. return nil;
  55. return (void*)t->addr;
  56. }
  57. int
  58. dyntabsize(Dynsym *t)
  59. {
  60. int n;
  61. for(n = 0; t->name != nil; t++)
  62. n++;
  63. return n;
  64. }
  65. void
  66. dynobjfree(Dynobj *o)
  67. {
  68. if(o != nil){
  69. free(o->base);
  70. free(o->import);
  71. free(o);
  72. }
  73. }
  74. void
  75. dynfreeimport(Dynobj *o)
  76. {
  77. free(o->import);
  78. o->import = nil;
  79. o->nimport = 0;
  80. }
  81. static char Ereloc[] = "error reading object file";
  82. Dynobj*
  83. dynloadgen(void *file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int), void (*werr)(char*), Dynsym *tab, int ntab, ulong maxsize)
  84. {
  85. int i, m, n, ni, nr, relsize;
  86. ulong syms, entry, sig, p, a;
  87. uchar *base;
  88. Exec e;
  89. Dynsym *t;
  90. Dynobj *l;
  91. char *s, *err, buf[64];
  92. uchar *reldata, *rp, *ep;
  93. vlong off;
  94. err = Ereloc; /* default */
  95. off = (*sk)(file, 0, 1);
  96. l = mallocz(sizeof(Dynobj), 1);
  97. if(l == nil){
  98. err = "can't allocate Dynobj";
  99. goto Error;
  100. }
  101. if((*rd)(file, &e, sizeof(Exec)) != sizeof(Exec))
  102. goto Error;
  103. if(lgetbe(e.magic) != dynmagic()){
  104. err = "not dynamic object file or wrong platform";
  105. goto Error;
  106. }
  107. l->text = lgetbe(e.text);
  108. l->data = lgetbe(e.data);
  109. l->bss = lgetbe(e.bss);
  110. syms = lgetbe(e.syms)+lgetbe(e.spsz)+lgetbe(e.pcsz);
  111. entry = lgetbe(e.entry);
  112. l->size = l->text + l->data + l->bss;
  113. if(entry < 0 || entry >= l->size || entry & 3){
  114. err = "invalid export table pointer (entry point)";
  115. goto Error;
  116. }
  117. if(maxsize && l->size >= maxsize){
  118. snprint(buf, sizeof(buf), "%lud: object too big", l->size);
  119. err = buf;
  120. goto Error;
  121. }
  122. l->base = base = malloc(l->size);
  123. if(base == nil){
  124. err = "out of memory: loading object file";
  125. goto Error;
  126. }
  127. l->export = (Dynsym*)(base+entry);
  128. if((*rd)(file, base, l->text+l->data) != l->text+l->data)
  129. goto Error;
  130. memset(base+l->text+l->data, 0, l->bss);
  131. if((*sk)(file, syms, 1) < 0)
  132. goto Error;
  133. if((*rd)(file, buf, 4) != 4)
  134. goto Error;
  135. relsize = get4((uchar*)buf); /* always contains at least an import count (might be zero) */
  136. if(relsize < 4)
  137. goto Error;
  138. reldata = malloc(relsize);
  139. if(reldata == nil){
  140. err = "out of memory: relocation data";
  141. goto Error;
  142. }
  143. if((*rd)(file, reldata, relsize) != relsize)
  144. goto Error;
  145. rp = reldata;
  146. ep = reldata+relsize;
  147. ni = get4(rp);
  148. rp += 4;
  149. if(ni < 0 || ni > 8000)
  150. goto Error; /* implausible size */
  151. l->nimport = ni;
  152. l->import = malloc(ni*sizeof(Dynsym*));
  153. if(l->import == nil){
  154. err = "out of memory: symbol table";
  155. goto Error;
  156. }
  157. for(i = 0; i < ni; i++){
  158. if(rp+5 > ep)
  159. goto Error;
  160. sig = get4(rp);
  161. rp += 4;
  162. s = (char*)rp;
  163. while(*rp++)
  164. if(rp >= ep)
  165. goto Error;
  166. t = dynfindsym(s, tab, ntab);
  167. if(t == nil){
  168. snprint(buf, sizeof(buf), "undefined symbol: %s", s);
  169. err = buf;
  170. goto Error;
  171. }
  172. if(sig != 0 && t->sig != 0 && t->sig != sig){
  173. snprint(buf, sizeof(buf), "signature mismatch: %s (%lux != %lux)", s, sig, t->sig);
  174. err = buf;
  175. goto Error;
  176. }
  177. l->import[i] = t;
  178. }
  179. a = 0;
  180. if(rp+4 > ep)
  181. goto Error;
  182. nr = get4(rp);
  183. rp += 4;
  184. for(i = 0; i < nr; i++){
  185. if(rp >= ep)
  186. goto Error;
  187. m = *rp++;
  188. n = m>>6;
  189. if(rp+(1<<n) > ep)
  190. goto Error;
  191. switch(n){
  192. case 0:
  193. p = *rp++;
  194. break;
  195. case 1:
  196. p = get2(rp);
  197. rp += 2;
  198. break;
  199. case 2:
  200. p = get4(rp);
  201. rp += 4;
  202. break;
  203. default:
  204. goto Error;
  205. }
  206. a += p;
  207. err = dynreloc(base, a, m&0xf, l->import, ni);
  208. if(err != nil){
  209. snprint(buf, sizeof(buf), "dynamic object: %s", err);
  210. err = buf;
  211. goto Error;
  212. }
  213. }
  214. free(reldata);
  215. /* could check relocated export table here */
  216. l->nexport = dyntabsize(l->export);
  217. segflush(base, l->text);
  218. return l;
  219. Error:
  220. if(off >= 0)
  221. (*sk)(file, off, 0); /* restore original file offset */
  222. (*werr)(err);
  223. dynobjfree(l);
  224. return nil;
  225. }
  226. int
  227. dynloadable(void* file, long (*rd)(void*,void*,long), vlong (*sk)(void*,vlong,int))
  228. {
  229. long magic;
  230. if((*rd)(file, &magic, sizeof(magic)) != sizeof(magic)){
  231. (*sk)(file, -(signed int)sizeof(magic), 1);
  232. return 0;
  233. }
  234. (*sk)(file, -(signed int)sizeof(magic), 1);
  235. return lgetbe(magic) == dynmagic();
  236. }