diff --git a/gdb/rs6000-nat.c b/gdb/rs6000-nat.c index d7b95712e4..a40b9a76fe 100644 --- a/gdb/rs6000-nat.c +++ b/gdb/rs6000-nat.c @@ -651,6 +651,71 @@ vmap_secs (struct vmap *vp, LdInfo *ldi, int arch64) vp->tstart += vp->toffs; } +/* If the .bss section's VMA is set to an address located before + the end of the .data section, causing the two sections to overlap, + return the overlap in bytes. Otherwise, return zero. + + Motivation: + + The GNU linker sometimes sets the start address of the .bss session + before the end of the .data section, making the 2 sections overlap. + The loader appears to handle this situation gracefully, by simply + loading the bss section right after the end of the .data section. + + This means that the .data and the .bss sections are sometimes + no longer relocated by the same amount. The problem is that + the ldinfo data does not contain any information regarding + the relocation of the .bss section, assuming that it would be + identical to the information provided for the .data section + (this is what would normally happen if the program was linked + correctly). + + GDB therefore needs to detect those cases, and make the corresponding + adjustment to the .bss section offset computed from the ldinfo data + when necessary. This function returns the adjustment amount (or + zero when no adjustment is needed). */ + +static CORE_ADDR +bss_data_overlap (struct objfile *objfile) +{ + struct obj_section *osect; + struct bfd_section *data = NULL; + struct bfd_section *bss = NULL; + + /* First, find the .data and .bss sections. */ + ALL_OBJFILE_OSECTIONS (objfile, osect) + { + if (strcmp (bfd_section_name (objfile->obfd, + osect->the_bfd_section), + ".data") == 0) + data = osect->the_bfd_section; + else if (strcmp (bfd_section_name (objfile->obfd, + osect->the_bfd_section), + ".bss") == 0) + bss = osect->the_bfd_section; + } + + /* If either section is not defined, there can be no overlap. */ + if (data == NULL || bss == NULL) + return 0; + + /* Assume the problem only occurs with linkers that place the .bss + section after the .data section (the problem has only been + observed when using the GNU linker, and the default linker + script always places the .data and .bss sections in that order). */ + if (bfd_section_vma (objfile->obfd, bss) + < bfd_section_vma (objfile->obfd, data)) + return 0; + + if (bfd_section_vma (objfile->obfd, bss) + < bfd_section_vma (objfile->obfd, data) + bfd_get_section_size (data)) + return ((bfd_section_vma (objfile->obfd, data) + + bfd_get_section_size (data)) + - bfd_section_vma (objfile->obfd, bss)); + + return 0; +} + /* Handle symbol translation on vmapping. */ static void @@ -687,6 +752,10 @@ vmap_symtab (struct vmap *vp) new_offsets->offsets[SECT_OFF_DATA (objfile)] = vp->dstart - vp->dvma; new_offsets->offsets[SECT_OFF_BSS (objfile)] = vp->dstart - vp->dvma; + /* Perform the same adjustment as the loader if the .data and + .bss sections overlap. */ + new_offsets->offsets[SECT_OFF_BSS (objfile)] += bss_data_overlap (objfile); + objfile_relocate (objfile, new_offsets); }