-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathgrpmgr.c
288 lines (275 loc) · 10.2 KB
/
grpmgr.c
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
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
/*
grpmgr.c - Part of llf, a cross linker. Part of the macxx tool chain.
Copyright (C) 2008 David Shepperd
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h> /* get standard I/O definitions */
#include "token.h" /* define compile time constants */
#include "structs.h" /* define structures */
#include "header.h" /* get our standard stuff */
struct ss_struct *group_list_default=0; /* pointer to default group name */
struct grp_struct *group_list_top=0; /* pointer to top of group list */
struct grp_struct *group_list_next=0; /* pointer to next free space */
long group_list_free; /* number of free spaces left */
long grp_pool_used;
/********************************************************************
* Group lists. There are 2 seperate lists involved in group lists:
* A list of groups and a list of segments in each group.
* The group list is initialised to a contigious set of 8 grp_struct's.
* The group_list_top variable always points to the first grp_struct of the
* first contigious set. The group_list_next variable points to the
* next available grp_struct in a set and group_list_free contains the
* number of free grp_structs left in a set. If more than 8 groups
* are specified, then another contigious set of 8 grp_struct's are
* obtained from the free pool and the last grp_struct of the previous
* set points to the first grp_struct in the new set. To indicate that
* the grp_struct points to another group struct instead of the segment
* list, the first item in the grp_struct (grp_top) is set to -1.
* The grp_structs are organized thus:
*
* group_list_top ------> grp_struct
* group_list_next --- grp_struct
* | ...
* | grp_struct = grp_top = -1
* | grp_next ---
* | |
* | -----------------------------
* | |
* | --> grp_struct
* | ...
* ----> grp_struct (grp_top = 0)
*
* group_list_free = number of items left in the current free pool
*
* The grp_struct has 3 elements: grp_top, grp_next and grp_free. These
* are used to manage a segment list similarly to the way the group list
* is managed.
*
* The segment list is an array of pointers to ss_structs (presumably
* segment structures). The blank array is drawn from the free pool
* and if more segments are needed than there are elements in the array then
* another array is taken from the free pool, the second to last element in
* the previous array is set to -1 and the last element (and grp_next) is
* made to point to the first element in the new array.
*
* grp_top ----------> ss_struct *
* grp_next ---- ss_struct *
* | ... (a value of -2 implies segment deleted)
* | -1
* | ss_struct ** ----
* | |
* | -----------------------
* | |
* | ----> ss_struct *
* | ss_struct *
* | ...
* ------> 0
* grp_free contains the number of free elements left in the array.
*
* The group name is held in an ss_struct. Its ->seg_spec->seg_group
* element points to the group list element defining the segment list.
* That element in each of the segments in the group points back to the
* group name ss_struct. This completes a closed loop so that given any
* random segment pointer, we can find out what group it's in and what's
* in that group.
*
********************************************************************/
/********************************************************************
* Group list manager.
*/
void insert_intogroup(
GRP_struct *grp_ptr,
SS_struct *sym_ptr,
SS_struct *grp_nam
)
/*
* Inserts the sym_ptr into the specified group.
* At entry:
* grp_ptr - pointer to group struct into which to stuff segment.
* sym_ptr - pointer to segment struct to insert.
* grp_nam - pointer to ss_struct containing group name
*/
{
struct ss_struct **sp;
if (grp_ptr->grp_free <= 2)
{
int t = 32*sizeof(struct ss_struct **);
sp = (struct ss_struct **)MEM_alloc(t);
grp_pool_used += t;
if (grp_ptr->grp_free)
{
*(long *)grp_ptr->grp_next++ = -1;
*(struct ss_struct ***)grp_ptr->grp_next = sp;
}
else
{
grp_ptr->grp_top = sp;
}
grp_ptr->grp_next = sp;
grp_ptr->grp_free = 8;
}
*grp_ptr->grp_next++ = sym_ptr;
grp_ptr->grp_free -= 1;
sym_ptr->seg_spec->seg_group = grp_nam;
sym_ptr->flg_member = 1;
return;
}
/*******************************************************************
* get_grp_ptr - get a pointer to group struct
*/
GRP_struct *get_grp_ptr(
SS_struct *grp_nam,
long align,
long maxlen
)
/*
* At entry:
* grp_nam - pointer to group name ss_struct
* align - group alignment factor
* maxlen - maxlen for group
* At exit:
* returns pointer to grp_struct
*/
{
struct grp_struct *grp_ptr;
struct seg_spec_struct *seg_ptr;
if (!grp_nam->flg_group)
{
grp_nam->flg_group = grp_nam->flg_defined = 1;
seg_ptr = get_seg_spec_mem(grp_nam); /* get the special section */
grp_nam->flg_segment = 0; /* reset the segment flag */
seg_ptr->seg_salign = (unsigned short)align; /* pass the segment alignment factor */
seg_ptr->seg_maxlen = maxlen; /* pass the maximum length */
if (group_list_free <= 1)
{
int t = 10*sizeof(struct grp_struct);
grp_ptr = (struct grp_struct *)MEM_alloc(t);
grp_pool_used += t;
group_list_next->grp_top = (struct ss_struct **)-1l;
group_list_next->grp_next = (struct ss_struct **)grp_ptr;
group_list_next = grp_ptr;
group_list_free = 10;
}
grp_ptr = group_list_next++;
seg_ptr->seg_group = (struct ss_struct *)grp_ptr;
group_list_free -= 1;
}
else
{
grp_ptr = (struct grp_struct *)(seg_ptr = grp_nam->seg_spec)->seg_group;
if (seg_ptr->seg_maxlen != maxlen)
{
if (grp_ptr != group_list_top)
{
sprintf(emsg,"Group {%s} maxlen is %lu in file: %s\n\t%s%lu%s%s",
grp_nam->ss_string,seg_ptr->seg_maxlen,
grp_nam->ss_fnd->fn_buff,
"and is ",maxlen,
" in file: ",current_fnd->fn_buff);
err_msg(MSG_WARN,emsg);
}
else
{
seg_ptr->seg_maxlen = maxlen;
}
}
if (seg_ptr->seg_salign != (unsigned short)align)
{
if (grp_ptr != group_list_top)
{
sprintf(emsg,"Group {%s}'s align is %u in file: %s\n\t%s%lu%s%s",
grp_nam->ss_string,seg_ptr->seg_salign,
grp_nam->ss_fnd->fn_buff,
"and is ",align,
" in file: ",current_fnd->fn_buff);
err_msg(MSG_WARN,emsg);
}
else
{
seg_ptr->seg_salign = (unsigned short)align;
}
}
}
return grp_ptr;
}
/*******************************************************************
* find_seg_in_group - looks through the default group list for
* the segment.
*/
SS_struct **find_seg_in_group(
SS_struct *sym_ptr, /* pointer to segment which to look for */
SS_struct **grp_list) /* pointer to group list to search */
{
while (*grp_list)
{ /* 0 means end of list */
if (*(long *)grp_list == -1) /* -1 means next entry is new pointer */
{
++grp_list;
grp_list = *(SS_struct ***)grp_list; /* link to next list */
continue;
}
if (*grp_list == sym_ptr) return grp_list;
grp_list++; /* up to next entry */
}
return 0;
}
/*******************************************************************
* add_to_group list
*/
int add_to_group(
struct ss_struct *sym_ptr,
struct ss_struct *grp_nam,
struct grp_struct *grp_ptr
)
/*
* Adds a segment to a group list
* At entry:
* sym_ptr - points to symbol to add to list
* grp_nam - points to group name ss_struct
* grp_ptr - points to group list
* returns FLASE if mem alloc error, else always returns
* TRUE.
*/
{
struct ss_struct **sym_list;
struct seg_spec_struct *seg_ptr;
if (!chk_mdf(0,sym_ptr,0))
{
return TRUE; /* exit if multiple definitions */
}
if ((seg_ptr=sym_ptr->seg_spec) == 0)
{
if ((seg_ptr=get_seg_spec_mem(sym_ptr)) == 0) return FALSE;
}
if (sym_ptr->flg_member)
{
if (seg_ptr->seg_group == grp_nam) return TRUE; /* already in the group */
if (seg_ptr->seg_group != group_list_default)
{
sprintf(emsg,
"Segment {%s} declared in group {%s} in file %s\n\t%s%s%s%s",
sym_ptr->ss_string,grp_nam->ss_string,current_fnd->fn_buff,
"and declared in group {",seg_ptr->seg_group->ss_string,
"} in file ",seg_ptr->seg_group->ss_fnd->fn_buff);
err_msg(MSG_WARN,emsg);
return TRUE;
}
}
insert_intogroup(grp_ptr,sym_ptr,grp_nam); /* stick seg into group */
/* Next scan the default group list and remove the segment from it if present */
sym_list = find_seg_in_group(sym_ptr, group_list_top->grp_top);
if (sym_list)
{
*(long *)sym_list = -2; /* -2 means skip it */
}
return TRUE; /* done */
}