xref: /inferno-os/libdynld/dynld-power.c (revision 37da2899f40661e3e9631e497da8dc59b971cbd0)
1 #include "lib9.h"
2 #include <a.out.h>
3 #include <dynld.h>
4 
5 #define	CHK(i,ntab)	if((unsigned)(i)>=(ntab))return "bad relocation index"
6 
7 long
dynmagic(void)8 dynmagic(void)
9 {
10 	return DYN_MAGIC | Q_MAGIC;
11 }
12 
13 char*
dynreloc(uchar * b,ulong p,int m,Dynsym ** tab,int ntab)14 dynreloc(uchar *b, ulong p, int m, Dynsym **tab, int ntab)
15 {
16 	int i;
17 	ulong v, *pp0, *pp1;
18 
19 	p <<= 2;
20 	p += (ulong)b;
21 	pp0 = (ulong*)p;
22 	v = *pp0;
23 	switch(m){
24 	case 0:
25 		v += (ulong)b;
26 		break;
27 	case 1:
28 		i = v>>22;
29 		v &= 0x3fffff;
30 		CHK(i, ntab);
31 		v += tab[i]->addr;
32 		break;
33 	case 2:
34 		i = (v&0xffc)>>2;
35 		v &= ~0xffc;
36 		CHK(i, ntab);
37 		v |= (tab[i]->addr-p)&0x3fffffc;
38 		break;
39 	case 3:
40 	case 4:
41 	case 5:
42 	case 6:
43 		pp1 = (ulong*)(p+4);
44 		v = (v<<16)|(*pp1&0xffff);
45 		if(m&1)
46 			v += (ulong)b;
47 		else{
48 			i = v>>22;
49 			v &= 0x3fffff;
50 			CHK(i, ntab);
51 			v += tab[i]->addr;
52 		}
53 		if(m >= 5 && (v&0x8000))
54 			v += 0x10000;
55 		*pp0 &= ~0xffff;
56 		*pp0 |= v>>16;
57 		*pp1 &= ~0xffff;
58 		*pp1 |= v&0xffff;
59 		return nil;
60 	default:
61 		return "invalid relocation mode";
62 	}
63 	*pp0 = v;
64 	return nil;
65 }
66