|
|
| 3056 |
} |
3056 |
} |
| 3057 |
return TRUE; |
3057 |
return TRUE; |
| 3058 |
} |
3058 |
} |
|
|
3059 |
|
| 3060 |
/* Initialize COOKIE for input bfd ABFD. */ |
| 3061 |
|
| 3062 |
static bfd_boolean |
| 3063 |
init_reloc_cookie (struct coff_reloc_cookie *cookie, |
| 3064 |
struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd) |
| 3065 |
{ |
| 3066 |
const bfd_coff_backend_data *bed; |
| 3067 |
|
| 3068 |
bed = coff_backend_info (abfd); |
| 3069 |
|
| 3070 |
cookie->abfd = abfd; |
| 3071 |
cookie->sym_hashes = obj_coff_sym_hashes (abfd); |
| 3072 |
|
| 3073 |
/* FIXME: Sometimes the symbol table does not yet have been loaded here; |
| 3074 |
is this the correct way to handle it? */ |
| 3075 |
bfd_coff_slurp_symbol_table(abfd); |
| 3076 |
|
| 3077 |
cookie->symbols = obj_symbols(abfd); |
| 3078 |
|
| 3079 |
return TRUE; |
| 3080 |
} |
| 3081 |
|
| 3082 |
/* Free the memory allocated by init_reloc_cookie, if appropriate. */ |
| 3083 |
|
| 3084 |
static void |
| 3085 |
fini_reloc_cookie (struct coff_reloc_cookie *cookie ATTRIBUTE_UNUSED, bfd *abfd ATTRIBUTE_UNUSED) |
| 3086 |
{ |
| 3087 |
/* FIXME: Nothing to do for the COFF case it seems? */ |
| 3088 |
#if 0 |
| 3089 |
coff_Internal_Shdr *symtab_hdr; |
| 3090 |
|
| 3091 |
symtab_hdr = &coff_tdata (abfd)->symtab_hdr; |
| 3092 |
if (cookie->locsyms != NULL |
| 3093 |
&& symtab_hdr->contents != (unsigned char *) cookie->locsyms) |
| 3094 |
free (cookie->locsyms); |
| 3095 |
#endif |
| 3096 |
} |
| 3097 |
|
| 3098 |
|
| 3099 |
/* Initialize the relocation information in COOKIE for input section SEC |
| 3100 |
of input bfd ABFD. */ |
| 3101 |
|
| 3102 |
static bfd_boolean |
| 3103 |
init_reloc_cookie_rels (struct coff_reloc_cookie *cookie, |
| 3104 |
struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd, |
| 3105 |
asection *sec) |
| 3106 |
{ |
| 3107 |
const bfd_coff_backend_data *bed; |
| 3108 |
|
| 3109 |
if (sec->reloc_count == 0) |
| 3110 |
{ |
| 3111 |
cookie->rels = NULL; |
| 3112 |
cookie->relend = NULL; |
| 3113 |
} |
| 3114 |
else |
| 3115 |
{ |
| 3116 |
bed = coff_backend_info (abfd); |
| 3117 |
cookie->rels = _bfd_coff_read_internal_relocs (abfd, sec, FALSE, NULL, 0, NULL); |
| 3118 |
if (cookie->rels == NULL) |
| 3119 |
return FALSE; |
| 3120 |
cookie->rel = cookie->rels; |
| 3121 |
cookie->relend = (cookie->rels + sec->reloc_count); |
| 3122 |
} |
| 3123 |
cookie->rel = cookie->rels; |
| 3124 |
return TRUE; |
| 3125 |
} |
| 3126 |
|
| 3127 |
/* Free the memory allocated by init_reloc_cookie_rels, |
| 3128 |
if appropriate. */ |
| 3129 |
|
| 3130 |
static void |
| 3131 |
fini_reloc_cookie_rels (struct coff_reloc_cookie *cookie, |
| 3132 |
asection *sec) |
| 3133 |
{ |
| 3134 |
if (cookie->rels && coff_section_data (NULL, sec)->relocs != cookie->rels) |
| 3135 |
free (cookie->rels); |
| 3136 |
} |
| 3137 |
|
| 3138 |
/* Initialize the whole of COOKIE for input section SEC. */ |
| 3139 |
|
| 3140 |
static bfd_boolean |
| 3141 |
init_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, |
| 3142 |
struct bfd_link_info *info, |
| 3143 |
asection *sec) |
| 3144 |
{ |
| 3145 |
if (!init_reloc_cookie (cookie, info, sec->owner)) |
| 3146 |
goto error1; |
| 3147 |
if (!init_reloc_cookie_rels (cookie, info, sec->owner, sec)) |
| 3148 |
goto error2; |
| 3149 |
return TRUE; |
| 3150 |
|
| 3151 |
error2: |
| 3152 |
fini_reloc_cookie (cookie, sec->owner); |
| 3153 |
error1: |
| 3154 |
return FALSE; |
| 3155 |
} |
| 3156 |
|
| 3157 |
/* Free the memory allocated by init_reloc_cookie_for_section, |
| 3158 |
if appropriate. */ |
| 3159 |
|
| 3160 |
static void |
| 3161 |
fini_reloc_cookie_for_section (struct coff_reloc_cookie *cookie, |
| 3162 |
asection *sec) |
| 3163 |
{ |
| 3164 |
fini_reloc_cookie_rels (cookie, sec); |
| 3165 |
fini_reloc_cookie (cookie, sec->owner); |
| 3166 |
} |
| 3167 |
|
| 3168 |
static asection * |
| 3169 |
_bfd_coff_gc_mark_hook (asection *sec, |
| 3170 |
struct bfd_link_info *info ATTRIBUTE_UNUSED, |
| 3171 |
struct internal_reloc *rel ATTRIBUTE_UNUSED, |
| 3172 |
struct coff_link_hash_entry *h, |
| 3173 |
struct internal_syment *sym) |
| 3174 |
{ |
| 3175 |
if (h != NULL) |
| 3176 |
{ |
| 3177 |
switch (h->root.type) |
| 3178 |
{ |
| 3179 |
case bfd_link_hash_defined: |
| 3180 |
case bfd_link_hash_defweak: |
| 3181 |
return h->root.u.def.section; |
| 3182 |
|
| 3183 |
case bfd_link_hash_common: |
| 3184 |
return h->root.u.c.p->section; |
| 3185 |
|
| 3186 |
default: |
| 3187 |
break; |
| 3188 |
} |
| 3189 |
} |
| 3190 |
else |
| 3191 |
return coff_section_from_bfd_index (sec->owner, sym->n_scnum); |
| 3192 |
/* FIXME: is the above corrent? elflink.c has: |
| 3193 |
return bfd_section_from_elf_index (sec->owner, sym->st_shndx); */ |
| 3194 |
|
| 3195 |
return NULL; |
| 3196 |
} |
| 3197 |
|
| 3198 |
/* COOKIE->rel describes a relocation against section SEC, which is |
| 3199 |
a section we've decided to keep. Return the section that contains |
| 3200 |
the relocation symbol, or NULL if no section contains it. */ |
| 3201 |
static asection * |
| 3202 |
_bfd_coff_gc_mark_rsec (struct bfd_link_info *info, asection *sec, |
| 3203 |
coff_gc_mark_hook_fn gc_mark_hook, |
| 3204 |
struct coff_reloc_cookie *cookie) |
| 3205 |
{ |
| 3206 |
struct coff_link_hash_entry *h; |
| 3207 |
|
| 3208 |
h = cookie->sym_hashes[cookie->rel->r_symndx]; |
| 3209 |
if (h != NULL) { |
| 3210 |
while (h->root.type == bfd_link_hash_indirect |
| 3211 |
|| h->root.type == bfd_link_hash_warning) |
| 3212 |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
| 3213 |
|
| 3214 |
return (*gc_mark_hook) (sec, info, cookie->rel, h, NULL); |
| 3215 |
} |
| 3216 |
|
| 3217 |
return (*gc_mark_hook) (sec, info, cookie->rel, NULL, |
| 3218 |
&(cookie->symbols + obj_convert (sec->owner)[cookie->rel->r_symndx])->native->u.syment); |
| 3219 |
} |
| 3220 |
|
| 3221 |
static |
| 3222 |
bfd_boolean |
| 3223 |
_bfd_coff_gc_mark (struct bfd_link_info *info, |
| 3224 |
asection *sec, |
| 3225 |
coff_gc_mark_hook_fn gc_mark_hook); |
| 3226 |
|
| 3227 |
/* COOKIE->rel describes a relocation against section SEC, which is |
| 3228 |
a section we've decided to keep. Mark the section that contains |
| 3229 |
the relocation symbol. */ |
| 3230 |
static bfd_boolean |
| 3231 |
_bfd_coff_gc_mark_reloc (struct bfd_link_info *info, |
| 3232 |
asection *sec, |
| 3233 |
coff_gc_mark_hook_fn gc_mark_hook, |
| 3234 |
struct coff_reloc_cookie *cookie) |
| 3235 |
{ |
| 3236 |
asection *rsec; |
| 3237 |
|
| 3238 |
rsec = _bfd_coff_gc_mark_rsec (info, sec, gc_mark_hook, cookie); |
| 3239 |
if (rsec && !rsec->gc_mark) |
| 3240 |
{ |
| 3241 |
if (bfd_get_flavour (rsec->owner) != bfd_target_coff_flavour) |
| 3242 |
rsec->gc_mark = 1; |
| 3243 |
else if (!_bfd_coff_gc_mark (info, rsec, gc_mark_hook)) |
| 3244 |
return FALSE; |
| 3245 |
} |
| 3246 |
return TRUE; |
| 3247 |
} |
| 3248 |
|
| 3249 |
/* The mark phase of garbage collection. For a given section, mark |
| 3250 |
it and any sections in this section's group, and all the sections |
| 3251 |
which define symbols to which it refers. */ |
| 3252 |
|
| 3253 |
static |
| 3254 |
bfd_boolean |
| 3255 |
_bfd_coff_gc_mark (struct bfd_link_info *info, |
| 3256 |
asection *sec, |
| 3257 |
coff_gc_mark_hook_fn gc_mark_hook) |
| 3258 |
{ |
| 3259 |
bfd_boolean ret; |
| 3260 |
|
| 3261 |
sec->gc_mark = 1; |
| 3262 |
|
| 3263 |
/* FIXME: elflink.c has "Mark all the sections in the group." |
| 3264 |
functionality here - does COFF require something similar? */ |
| 3265 |
|
| 3266 |
/* FIXME: elflink.c has some eh_frame handling here - does COFF |
| 3267 |
require something similar? */ |
| 3268 |
|
| 3269 |
/* Look through the section relocs. */ |
| 3270 |
ret = TRUE; |
| 3271 |
if ((sec->flags & SEC_RELOC) != 0 |
| 3272 |
&& sec->reloc_count > 0) |
| 3273 |
{ |
| 3274 |
struct coff_reloc_cookie cookie; |
| 3275 |
|
| 3276 |
|
| 3277 |
if (!init_reloc_cookie_for_section (&cookie, info, sec)) |
| 3278 |
ret = FALSE; |
| 3279 |
else |
| 3280 |
{ |
| 3281 |
for (; cookie.rel < cookie.relend; cookie.rel++) { |
| 3282 |
if (!_bfd_coff_gc_mark_reloc (info, sec, gc_mark_hook, &cookie)) |
| 3283 |
{ |
| 3284 |
ret = FALSE; |
| 3285 |
break; |
| 3286 |
} |
| 3287 |
} |
| 3288 |
fini_reloc_cookie_for_section (&cookie, sec); |
| 3289 |
} |
| 3290 |
|
| 3291 |
} |
| 3292 |
|
| 3293 |
/* FIXME: elflink.c has some eh_frame handling here - does COFF |
| 3294 |
require something similar? */ |
| 3295 |
|
| 3296 |
return ret; |
| 3297 |
} |
| 3298 |
|
| 3299 |
/* Sweep symbols in swept sections. Called via coff_link_hash_traverse. */ |
| 3300 |
|
| 3301 |
struct coff_gc_sweep_symbol_info |
| 3302 |
{ |
| 3303 |
struct bfd_link_info *info; |
| 3304 |
void (*hide_symbol) (struct bfd_link_info *, struct coff_link_hash_entry *, |
| 3305 |
bfd_boolean); |
| 3306 |
}; |
| 3307 |
|
| 3308 |
static bfd_boolean |
| 3309 |
coff_gc_sweep_symbol (struct coff_link_hash_entry *h, void *data) |
| 3310 |
{ |
| 3311 |
|
| 3312 |
if (h->root.type == bfd_link_hash_warning) |
| 3313 |
h = (struct coff_link_hash_entry *) h->root.u.i.link; |
| 3314 |
|
| 3315 |
if ((h->root.type == bfd_link_hash_defined |
| 3316 |
|| h->root.type == bfd_link_hash_defweak) |
| 3317 |
&& !h->root.u.def.section->gc_mark |
| 3318 |
&& !(h->root.u.def.section->owner->flags & DYNAMIC)) |
| 3319 |
{ |
| 3320 |
struct coff_gc_sweep_symbol_info *inf ATTRIBUTE_UNUSED = |
| 3321 |
(struct coff_gc_sweep_symbol_info *) data; |
| 3322 |
/* FIXME: elflink.c hides the symbol here - how can we do this for COFF? |
| 3323 |
(*inf->hide_symbol) (inf->info, h, TRUE); */ |
| 3324 |
} |
| 3325 |
|
| 3326 |
return TRUE; |
| 3327 |
} |
| 3328 |
|
| 3329 |
/* The sweep phase of garbage collection. Remove all garbage sections. */ |
| 3330 |
|
| 3331 |
typedef bfd_boolean (*gc_sweep_hook_fn) |
| 3332 |
(bfd *, struct bfd_link_info *, asection *, const struct internal_reloc *); |
| 3333 |
|
| 3334 |
static bfd_boolean |
| 3335 |
coff_gc_sweep (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
| 3336 |
{ |
| 3337 |
bfd *sub; |
| 3338 |
struct coff_gc_sweep_symbol_info sweep_info; |
| 3339 |
|
| 3340 |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
| 3341 |
{ |
| 3342 |
asection *o; |
| 3343 |
|
| 3344 |
if (bfd_get_flavour (sub) != bfd_target_coff_flavour) |
| 3345 |
continue; |
| 3346 |
|
| 3347 |
for (o = sub->sections; o != NULL; o = o->next) |
| 3348 |
{ |
| 3349 |
|
| 3350 |
/* FIXME: We must preserve the import table, but is this the correct |
| 3351 |
way to do it? */ |
| 3352 |
if (strncmp(o->name, ".idata", 6) == 0) |
| 3353 |
o->gc_mark = 1; |
| 3354 |
|
| 3355 |
/* FIXME: elflink.c has some section group |
| 3356 |
functionality here - does COFF require something similar? */ |
| 3357 |
|
| 3358 |
if ((o->flags & (SEC_DEBUGGING | SEC_LINKER_CREATED)) != 0 |
| 3359 |
|| (o->flags & (SEC_ALLOC | SEC_LOAD | SEC_RELOC)) == 0) |
| 3360 |
{ |
| 3361 |
/* Keep debug and special sections. */ |
| 3362 |
o->gc_mark = 1; |
| 3363 |
} |
| 3364 |
|
| 3365 |
if (o->gc_mark) |
| 3366 |
continue; |
| 3367 |
|
| 3368 |
/* Skip sweeping sections already excluded. */ |
| 3369 |
if (o->flags & SEC_EXCLUDE) |
| 3370 |
continue; |
| 3371 |
|
| 3372 |
/* Since this is early in the link process, it is simple |
| 3373 |
to remove a section from the output. */ |
| 3374 |
o->flags |= SEC_EXCLUDE; |
| 3375 |
|
| 3376 |
if (info->print_gc_sections && o->size != 0) |
| 3377 |
_bfd_error_handler (_("Removing unused section '%s' in file '%B'"), sub, o->name); |
| 3378 |
|
| 3379 |
/* FIXME: Do we need something like this for COFF? */ |
| 3380 |
#if 0 |
| 3381 |
/* But we also have to update some of the relocation |
| 3382 |
info we collected before. */ |
| 3383 |
if (gc_sweep_hook |
| 3384 |
&& (o->flags & SEC_RELOC) != 0 |
| 3385 |
&& o->reloc_count > 0 |
| 3386 |
&& !bfd_is_abs_section (o->output_section)) |
| 3387 |
{ |
| 3388 |
struct internal_reloc *internal_relocs; |
| 3389 |
bfd_boolean r; |
| 3390 |
|
| 3391 |
internal_relocs |
| 3392 |
= _bfd_coff_link_read_relocs (o->owner, o, NULL, NULL, |
| 3393 |
info->keep_memory); |
| 3394 |
if (internal_relocs == NULL) |
| 3395 |
return FALSE; |
| 3396 |
|
| 3397 |
r = (*gc_sweep_hook) (o->owner, info, o, internal_relocs); |
| 3398 |
|
| 3399 |
if (coff_section_data (o)->relocs != internal_relocs) |
| 3400 |
free (internal_relocs); |
| 3401 |
|
| 3402 |
if (!r) |
| 3403 |
return FALSE; |
| 3404 |
} |
| 3405 |
#endif |
| 3406 |
} |
| 3407 |
} |
| 3408 |
|
| 3409 |
/* Remove the symbols that were in the swept sections from the dynamic |
| 3410 |
symbol table. GCFIXME: Anyone know how to get them out of the |
| 3411 |
static symbol table as well? */ |
| 3412 |
|
| 3413 |
sweep_info.info = info; |
| 3414 |
/* FIXME: Do we need this for COFF? |
| 3415 |
sweep_info.hide_symbol = bed->coff_backend_hide_symbol; */ |
| 3416 |
coff_link_hash_traverse (coff_hash_table (info), coff_gc_sweep_symbol, |
| 3417 |
&sweep_info); |
| 3418 |
|
| 3419 |
/* FIXME: Do we need this for COFF? |
| 3420 |
_bfd_coff_link_renumber_dynsyms (abfd, info, §ion_sym_count); */ |
| 3421 |
|
| 3422 |
return TRUE; |
| 3423 |
} |
| 3424 |
|
| 3425 |
/* Keep all sections containing symbols undefined on the command-line, |
| 3426 |
and the section containing the entry symbol. */ |
| 3427 |
|
| 3428 |
static void |
| 3429 |
_bfd_coff_gc_keep (struct bfd_link_info *info) |
| 3430 |
{ |
| 3431 |
struct bfd_sym_chain *sym; |
| 3432 |
|
| 3433 |
for (sym = info->gc_sym_list; sym != NULL; sym = sym->next) |
| 3434 |
{ |
| 3435 |
struct coff_link_hash_entry *h; |
| 3436 |
|
| 3437 |
h = coff_link_hash_lookup (coff_hash_table (info), sym->name, |
| 3438 |
FALSE, FALSE, FALSE); |
| 3439 |
|
| 3440 |
if (h != NULL |
| 3441 |
/* FIXME: elflink.c has more conditions - what about COFF? |
| 3442 |
&& (h->root.type == bfd_link_hash_defined |
| 3443 |
|| h->root.type == bfd_link_hash_defweak) |
| 3444 |
&& !bfd_is_abs_section (h->root.u.def.section)*/) |
| 3445 |
h->root.u.def.section->flags |= SEC_KEEP; |
| 3446 |
} |
| 3447 |
} |
| 3448 |
|
| 3449 |
/* Do mark and sweep of unused sections. */ |
| 3450 |
|
| 3451 |
bfd_boolean |
| 3452 |
bfd_coff_gc_sections (bfd *abfd ATTRIBUTE_UNUSED, struct bfd_link_info *info) |
| 3453 |
{ |
| 3454 |
|
| 3455 |
bfd *sub; |
| 3456 |
|
| 3457 |
/* FIXME: Should we implement this? */ |
| 3458 |
#if 0 |
| 3459 |
const bfd_coff_backend_data *bed = coff_backend_info (abfd); |
| 3460 |
|
| 3461 |
if (!bed->can_gc_sections |
| 3462 |
|| !is_coff_hash_table (info->hash)) |
| 3463 |
{ |
| 3464 |
(*_bfd_error_handler)(_("Warning: gc-sections option ignored")); |
| 3465 |
return TRUE; |
| 3466 |
} |
| 3467 |
#endif |
| 3468 |
|
| 3469 |
_bfd_coff_gc_keep (info); |
| 3470 |
|
| 3471 |
/* FIXME: elflink.c has some eh_frame handling here - does COFF |
| 3472 |
require something similar? */ |
| 3473 |
|
| 3474 |
/* FIXME: elflink.c does two things here: |
| 3475 |
- Apply transitive closure to the vtable entry usage info. |
| 3476 |
- Kill the vtable relocations that were not used. |
| 3477 |
does COFF require something similar? */ |
| 3478 |
|
| 3479 |
/* FIXME: elflink.c does a traverse with bfd_elf_gc_mark_dynamic_ref_symbol |
| 3480 |
here - does COFF require something similar? */ |
| 3481 |
|
| 3482 |
/* Grovel through relocs to find out who stays ... */ |
| 3483 |
for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) |
| 3484 |
{ |
| 3485 |
asection *o; |
| 3486 |
|
| 3487 |
if (bfd_get_flavour (sub) != bfd_target_coff_flavour) |
| 3488 |
continue; |
| 3489 |
|
| 3490 |
for (o = sub->sections; o != NULL; o = o->next) { |
| 3491 |
/* FIXME: Is this the proper way to check for global constructors? */ |
| 3492 |
if (((o->flags & (SEC_EXCLUDE | SEC_KEEP)) == SEC_KEEP || strncmp(o->name, ".ctors", 6) == 0) && !o->gc_mark) { |
| 3493 |
if (!_bfd_coff_gc_mark (info, o, _bfd_coff_gc_mark_hook)) { |
| 3494 |
return FALSE; |
| 3495 |
} |
| 3496 |
} |
| 3497 |
} |
| 3498 |
} |
| 3499 |
|
| 3500 |
/* FIXME: elflink.c has an hook for gc_mark_extra_sections |
| 3501 |
here - does COFF require something similar? */ |
| 3502 |
|
| 3503 |
/* ... and mark SEC_EXCLUDE for those that go. */ |
| 3504 |
return coff_gc_sweep (abfd, info); |
| 3505 |
} |
| 3506 |
|