compact_rel.c
3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
/*==============================================================================
Module: compact_rel.c
$Revision: 1.1.1.2 $
$Date: 2002/10/29 08:07:15 $
$Author: blythe $
$Source: /root/leakn64/depot/rf/sw/n64os20l/tools/gcord/com/compact_rel.c,v $
Procedures pulled out from libmld and modified.
These procedures are clean of obj structure.
==============================================================================*/
#include <compact_reloc.h>
#include <string.h>
#include <malloc.h>
#include "global.h"
static unsigned alloc_cm_rel_sz = 2048;
static char *cm_rel_head;
static unsigned cm_rel_size;
static unsigned cm_rel_count;
void new_cr_header(char *start, size_t size)
{
cm_rel_head = (char *) malloc(alloc_cm_rel_sz);
memcpy(cm_rel_head, start, size);
cm_rel_size = size;
}
char *cr_head(void)
{
return cm_rel_head;
}
unsigned cr_size(void)
{
return cm_rel_size;
}
void add_cr(int type,
unsigned long offset,
unsigned long dist2lo,
unsigned long vaddr)
{
union cm_rlc *cr;
char *p;
long delta;
static unsigned long prev_vaddr = 0;
if (cm_rel_head == (char *) NULL)
{
cm_rel_head = (char *) malloc(alloc_cm_rel_sz);
}
else if((cm_rel_size + sizeof(union cm_rlc)) > alloc_cm_rel_sz)
{
alloc_cm_rel_sz *=2;
cm_rel_head = (char *) realloc(cm_rel_head, alloc_cm_rel_sz);
}
if (cm_rel_head == (char *) NULL)
error("Out of Memory doing compact relocation\n");
cr = (union cm_rlc *)(cm_rel_head + cm_rel_size);
cr->r.type = type;
delta = (vaddr-prev_vaddr) >> 2;
if (VADDR_OVFL(delta))
{
delta = 0;
cr->r.addend |= ADDEND_BASE;
}
cr->r.del_vaddr = VADDR_DELTA(delta);
cr->r.del_lo = dist2lo >> 2;
if (offset)
{
cr->r.addend |= ADDEND_CONST;
cr->c.addend_const = offset;
if (cr->r.addend & ADDEND_BASE)
cr->cb.base = vaddr;
}
else
{
cr->r.addend |= ADDEND_NOCONST;
if (cr->r.addend & ADDEND_BASE)
cr->b.base = vaddr;
}
cm_rel_count++;
cm_rel_size += sizeof(struct COMPACT_RELOC);
cm_rel_size += ((cr->r.addend & ADDEND_BASE)!=0) * sizeof(unsigned);
cm_rel_size += ((cr->r.addend & ADDEND_CONST)!=0) * sizeof(unsigned);
prev_vaddr = vaddr;
}
void cm_rlc_reset(cm_struct *cm)
{
ASSERT(cm);
ASSERT(cm->rlc_ptr);
cm->cur_rlc_ptr = cm->rlc_ptr;
cm->cur_rlc_no = 0;
cm->last_base = 0;
}
int cm_rlc_get(cm_struct *cm)
{
union cm_rlc *p_cm_rlc;
unsigned size = 0;
ASSERT(cm);
ASSERT(cm->cur_rlc_ptr);
if (cm->cur_rlc_no == cm->rlc_no)
{
cm->cur_rlc_ptr = (char *)0;
return 0;
}
p_cm_rlc = (union cm_rlc *)cm->cur_rlc_ptr;
cm->rlc_entry.type = p_cm_rlc->r.type;
cm->rlc_entry.dist2lo = (unsigned)(p_cm_rlc->r.del_lo << 2);
cm->rlc_entry.vaddr = (unsigned)(p_cm_rlc->r.del_vaddr << 2);
if (p_cm_rlc->r.addend & ADDEND_CONST)
{
cm->rlc_entry.konst = p_cm_rlc->c.addend_const;
size += sizeof(unsigned);
if (p_cm_rlc->r.addend & ADDEND_BASE)
{
cm->rlc_entry.vaddr = p_cm_rlc->cb.base;
size += sizeof(unsigned);
}
else
cm->rlc_entry.vaddr += cm->last_base;
}
else
{
if (p_cm_rlc->r.addend & ADDEND_BASE)
{
size +=sizeof(unsigned);
cm->rlc_entry.vaddr += p_cm_rlc->b.base;
}
else
cm->rlc_entry.vaddr += cm->last_base;
}
cm->cur_rlc_ptr += (unsigned)(size + sizeof(struct COMPACT_RELOC));
cm->last_base = cm->rlc_entry.vaddr;
cm->cur_rlc_no++;
ASSERT(cm->cur_rlc_no <= cm->rlc_no);
return 1;
}