aboutsummaryrefslogtreecommitdiff
path: root/lldb/test/API/commands/register
AgeCommit message (Expand)AuthorFilesLines
2025-10-30[lldb][AArch64][test] Require SVE for some Linux testsDavid Spickett1-0/+7
2025-09-24[lldb][test] Unify test infrastructure for checking CPU features (#153914)Julian Lettner1-19/+1
2025-07-28[lldb][AArch64][Linux] Show MTE store only setting in mte_ctrl (#145033)David Spickett1-10/+22
2025-06-19[lldb][AArch64] Fix live process test for Linux's mte_ctrl registerDavid Spickett1-1/+2
2025-05-27[lldb][NFC] update API tests which skip/expect-fail armJason Molenda1-5/+5
2025-05-13[lldb] Move lldb_enable_attach from test_common to a separate header (#139550)Pavel Labath1-2/+2
2025-02-28[lldb] fix(lldb/**.py): fix invalid escape sequences (#94034)Eisuke Kawashima2-5/+5
2025-02-06[lldb][NFC] Remove old skipIfOutOfTreeDebugserver's (#126144)Jason Molenda1-1/+0
2024-12-31[lldb] Update two API tests to fix x86 Darwin failures (#121380)Jason Molenda1-0/+7
2024-12-19[lldb][debugserver] Read/write SME registers on arm64 (#119171)Jason Molenda1-2/+28
2024-12-04[lldb][tests] Fix passing pthread library to a linker for some API tests (#11...Vladislav Dzhidzhoev2-2/+4
2024-08-12[lldb][test][AArch64] Regex match field values in register testDavid Spickett1-4/+9
2024-07-03[lldb][AArch64] Add register field enum information (#96887)David Spickett1-1/+7
2024-07-01[lldb][FreeBSD][AArch64] Enable register field detection (#85058)David Spickett1-1/+1
2024-02-21[lldb][test] Modernize asserts (#82503)Jordan Rupprecht3-3/+3
2023-11-27[lldb][AArch64][Linux] Correct name of FPCR fieldDavid Spickett1-2/+2
2023-11-10[lldb][AArch64][Linux] Add register field information for SME's SVCR register...David Spickett1-4/+8
2023-11-10[lldb][AArch64][Linux] Add field information for the mte_ctrl register (#71808)David Spickett1-8/+19
2023-11-09[lldb][AArch64][Linux] Add fields for FPCR register (#71694)David Spickett1-0/+4
2023-11-09[lldb][AArch64][Linux] Add field information for the fpsr register (#71651)David Spickett1-2/+3
2023-11-08[lldb][AArch64][Linux] Add field information for the CPSR register (#70300)David Spickett1-0/+12
2023-11-01[lldb][AArch64] Add SME2's ZT0 register (#70205)David Spickett7-21/+124
2023-10-25[lldb][AArch64] Add isAArch64SMEFA64 check to SME testing (#68094)David Spickett7-14/+29
2023-10-25Reland "[lldb][AArch64] Invalidate SVG prior to reconfiguring ZA regdef (#667...David Spickett1-0/+2
2023-10-25Revert "[lldb][AArch64] Invalidate SVG prior to reconfiguring ZA regdef (#667...David Spickett1-2/+0
2023-10-25[lldb][AArch64] Invalidate SVG prior to reconfiguring ZA regdef (#66768)David Spickett1-0/+2
2023-09-22[lldb] Require paused process and frame for "register info" command (#67124)David Spickett1-0/+14
2023-09-20[lldb][AArch64] Add SME's streaming vector control registerDavid Spickett4-7/+36
2023-09-19[lldb][AArch64] Add testing for SME's ZA and SVG registersDavid Spickett8-33/+927
2023-09-19[lldb][AArch64] Document how to control the SVE/SSVE testsDavid Spickett4-0/+21
2023-09-13[lldb][AArch64] Reformat register set test with blackDavid Spickett1-2/+3
2023-09-13[lldb][AArch64] Add tests for SME's SVE register state to TestArm64DynamicReg...David Spickett2-2/+46
2023-09-11[lldb][Tests] Reformat API tests with blackDavid Spickett2-3/+5
2023-08-31[lldb][AArch64] Add testing of save/restore for Linux MTE control registerDavid Spickett3-0/+67
2023-08-31[lldb][AArch64] Check SIMD save/restore in SVE SIMD testDavid Spickett2-15/+17
2023-08-31[lldb][AArch64] Use atomics to sync threads in SVE threading testDavid Spickett2-4/+16
2023-08-04[lldb] Fix Python test formatting (NFC)Jonas Devlieghere4-26/+52
2023-07-26[lldb][AArch64] Add support for SME's SVE streaming mode registersDavid Spickett8-63/+431
2023-07-20[lldb][x86_64] Support fs_base/gs_base register in LinuxJeffrey Tan1-0/+44
2023-07-17[lldb][AArch64] Fix flakiness in TestSVEThreadedDynamicDavid Spickett1-2/+4
2023-07-04[lldb][AArch64] Handle different default vector length in SVE testingDavid Spickett1-4/+50
2023-06-21[lldb] Add register field tables to the "register info" commandDavid Spickett1-1/+2
2023-06-21[lldb] Add "register info" commandDavid Spickett1-0/+38
2023-05-25[NFC][Py Reformat] Reformat python files in lldbJonas Devlieghere5-328/+409
2023-03-22[lldb] Add test for unavailable registersDavid Spickett1-0/+53
2023-01-25[lldb][test] Replace use of p with expression (NFC)Dave Lee1-1/+1
2022-08-15[LLDB] Remove __future__ imports from testsDavid Spickett1-3/+0
2022-06-20[lldb] [test] Make AVX/MPX register tests more robust and fix on BSDMichał Górny1-18/+14
2022-06-17[lldb][tests] Automatically call compute_mydir (NFC)Dave Lee4-8/+0
2022-06-09[lldb] Use assertState in more tests (NFC)Dave Lee1-2/+2
ass="hl opt">(rel_size); aout_section_data (sec)->relocs = relocs; } } if (relocs == NULL) return FALSE; if (bfd_seek (abfd, sec->rel_filepos, SEEK_SET) != 0 || bfd_bread (relocs, rel_size, abfd) != rel_size) goto error_return; if (obj_reloc_entry_size (abfd) == RELOC_STD_SIZE) { if (! sunos_scan_std_relocs (info, abfd, sec, (struct reloc_std_external *) relocs, rel_size)) goto error_return; } else { if (! sunos_scan_ext_relocs (info, abfd, sec, (struct reloc_ext_external *) relocs, rel_size)) goto error_return; } if (free_relocs != NULL) free (free_relocs); return TRUE; error_return: if (free_relocs != NULL) free (free_relocs); return FALSE; } /* Build the hash table of dynamic symbols, and to mark as written all symbols from dynamic objects which we do not plan to write out. */ static bfd_boolean sunos_scan_dynamic_symbol (struct sunos_link_hash_entry *h, void * data) { struct bfd_link_info *info = (struct bfd_link_info *) data; if (h->root.root.type == bfd_link_hash_warning) h = (struct sunos_link_hash_entry *) h->root.root.u.i.link; /* Set the written flag for symbols we do not want to write out as part of the regular symbol table. This is all symbols which are not defined in a regular object file. For some reason symbols which are referenced by a regular object and defined by a dynamic object do not seem to show up in the regular symbol table. It is possible for a symbol to have only SUNOS_REF_REGULAR set here, it is an undefined symbol which was turned into a common symbol because it was found in an archive object which was not included in the link. */ if ((h->flags & SUNOS_DEF_REGULAR) == 0 && (h->flags & SUNOS_DEF_DYNAMIC) != 0 && strcmp (h->root.root.root.string, "__DYNAMIC") != 0) h->root.written = TRUE; /* If this symbol is defined by a dynamic object and referenced by a regular object, see whether we gave it a reasonable value while scanning the relocs. */ if ((h->flags & SUNOS_DEF_REGULAR) == 0 && (h->flags & SUNOS_DEF_DYNAMIC) != 0 && (h->flags & SUNOS_REF_REGULAR) != 0) { if ((h->root.root.type == bfd_link_hash_defined || h->root.root.type == bfd_link_hash_defweak) && ((h->root.root.u.def.section->owner->flags & DYNAMIC) != 0) && h->root.root.u.def.section->output_section == NULL) { bfd *sub; /* This symbol is currently defined in a dynamic section which is not being put into the output file. This implies that there is no reloc against the symbol. I'm not sure why this case would ever occur. In any case, we change the symbol to be undefined. */ sub = h->root.root.u.def.section->owner; h->root.root.type = bfd_link_hash_undefined; h->root.root.u.undef.abfd = sub; } } /* If this symbol is defined or referenced by a regular file, add it to the dynamic symbols. */ if ((h->flags & (SUNOS_DEF_REGULAR | SUNOS_REF_REGULAR)) != 0) { asection *s; size_t len; bfd_byte *contents; unsigned char *name; unsigned long hash; bfd *dynobj; BFD_ASSERT (h->dynindx == -2); dynobj = sunos_hash_table (info)->dynobj; h->dynindx = sunos_hash_table (info)->dynsymcount; ++sunos_hash_table (info)->dynsymcount; len = strlen (h->root.root.root.string); /* We don't bother to construct a BFD hash table for the strings which are the names of the dynamic symbols. Using a hash table for the regular symbols is beneficial, because the regular symbols includes the debugging symbols, which have long names and are often duplicated in several object files. There are no debugging symbols in the dynamic symbols. */ s = bfd_get_section_by_name (dynobj, ".dynstr"); BFD_ASSERT (s != NULL); contents = bfd_realloc (s->contents, s->size + len + 1); if (contents == NULL) return FALSE; s->contents = contents; h->dynstr_index = s->size; strcpy ((char *) contents + s->size, h->root.root.root.string); s->size += len + 1; /* Add it to the dynamic hash table. */ name = (unsigned char *) h->root.root.root.string; hash = 0; while (*name != '\0') hash = (hash << 1) + *name++; hash &= 0x7fffffff; hash %= sunos_hash_table (info)->bucketcount; s = bfd_get_section_by_name (dynobj, ".hash"); BFD_ASSERT (s != NULL); if (GET_SWORD (dynobj, s->contents + hash * HASH_ENTRY_SIZE) == -1) PUT_WORD (dynobj, h->dynindx, s->contents + hash * HASH_ENTRY_SIZE); else { bfd_vma next; next = GET_WORD (dynobj, (s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD)); PUT_WORD (dynobj, s->size / HASH_ENTRY_SIZE, s->contents + hash * HASH_ENTRY_SIZE + BYTES_IN_WORD); PUT_WORD (dynobj, h->dynindx, s->contents + s->size); PUT_WORD (dynobj, next, s->contents + s->size + BYTES_IN_WORD); s->size += HASH_ENTRY_SIZE; } } return TRUE; } /* Set up the sizes and contents of the dynamic sections created in sunos_add_dynamic_symbols. This is called by the SunOS linker emulation before_allocation routine. We must set the sizes of the sections before the linker sets the addresses of the various sections. This unfortunately requires reading all the relocs so that we can work out which ones need to become dynamic relocs. If info->keep_memory is TRUE, we keep the relocs in memory; otherwise, we discard them, and will read them again later. */ bfd_boolean bfd_sunos_size_dynamic_sections (bfd *output_bfd, struct bfd_link_info *info, asection **sdynptr, asection **sneedptr, asection **srulesptr) { bfd *dynobj; bfd_size_type dynsymcount; struct sunos_link_hash_entry *h; asection *s; size_t bucketcount; bfd_size_type hashalloc; size_t i; bfd *sub; *sdynptr = NULL; *sneedptr = NULL; *srulesptr = NULL; if (info->relocatable) return TRUE; if (output_bfd->xvec != &MY(vec)) return TRUE; /* Look through all the input BFD's and read their relocs. It would be better if we didn't have to do this, but there is no other way to determine the number of dynamic relocs we need, and, more importantly, there is no other way to know which symbols should get an entry in the procedure linkage table. */ for (sub = info->input_bfds; sub != NULL; sub = sub->link_next) { if ((sub->flags & DYNAMIC) == 0 && sub->xvec == output_bfd->xvec) { if (! sunos_scan_relocs (info, sub, obj_textsec (sub), exec_hdr (sub)->a_trsize) || ! sunos_scan_relocs (info, sub, obj_datasec (sub), exec_hdr (sub)->a_drsize)) return FALSE; } } dynobj = sunos_hash_table (info)->dynobj; dynsymcount = sunos_hash_table (info)->dynsymcount; /* If there were no dynamic objects in the link, and we don't need to build a global offset table, there is nothing to do here. */ if (! sunos_hash_table (info)->dynamic_sections_needed && ! sunos_hash_table (info)->got_needed) return TRUE; /* If __GLOBAL_OFFSET_TABLE_ was mentioned, define it. */ h = sunos_link_hash_lookup (sunos_hash_table (info), "__GLOBAL_OFFSET_TABLE_", FALSE, FALSE, FALSE); if (h != NULL && (h->flags & SUNOS_REF_REGULAR) != 0) { h->flags |= SUNOS_DEF_REGULAR; if (h->dynindx == -1) { ++sunos_hash_table (info)->dynsymcount; h->dynindx = -2; } h->root.root.type = bfd_link_hash_defined; h->root.root.u.def.section = bfd_get_section_by_name (dynobj, ".got"); /* If the .got section is more than 0x1000 bytes, we set __GLOBAL_OFFSET_TABLE_ to be 0x1000 bytes into the section, so that 13 bit relocations have a greater chance of working. */ s = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (s != NULL); if (s->size >= 0x1000) h->root.root.u.def.value = 0x1000; else h->root.root.u.def.value = 0; sunos_hash_table (info)->got_base = h->root.root.u.def.value; } /* If there are any shared objects in the link, then we need to set up the dynamic linking information. */ if (sunos_hash_table (info)->dynamic_sections_needed) { *sdynptr = bfd_get_section_by_name (dynobj, ".dynamic"); /* The .dynamic section is always the same size. */ s = *sdynptr; BFD_ASSERT (s != NULL); s->size = (sizeof (struct external_sun4_dynamic) + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE + sizeof (struct external_sun4_dynamic_link)); /* Set the size of the .dynsym and .hash sections. We counted the number of dynamic symbols as we read the input files. We will build the dynamic symbol table (.dynsym) and the hash table (.hash) when we build the final symbol table, because until then we do not know the correct value to give the symbols. We build the dynamic symbol string table (.dynstr) in a traversal of the symbol table using sunos_scan_dynamic_symbol. */ s = bfd_get_section_by_name (dynobj, ".dynsym"); BFD_ASSERT (s != NULL); s->size = dynsymcount * sizeof (struct external_nlist); s->contents = bfd_alloc (output_bfd, s->size); if (s->contents == NULL && s->size != 0) return FALSE; /* The number of buckets is just the number of symbols divided by four. To compute the final size of the hash table, we must actually compute the hash table. Normally we need exactly as many entries in the hash table as there are dynamic symbols, but if some of the buckets are not used we will need additional entries. In the worst case, every symbol will hash to the same bucket, and we will need BUCKETCOUNT - 1 extra entries. */ if (dynsymcount >= 4) bucketcount = dynsymcount / 4; else if (dynsymcount > 0) bucketcount = dynsymcount; else bucketcount = 1; s = bfd_get_section_by_name (dynobj, ".hash"); BFD_ASSERT (s != NULL); hashalloc = (dynsymcount + bucketcount - 1) * HASH_ENTRY_SIZE; s->contents = bfd_zalloc (dynobj, hashalloc); if (s->contents == NULL && dynsymcount > 0) return FALSE; for (i = 0; i < bucketcount; i++) PUT_WORD (output_bfd, (bfd_vma) -1, s->contents + i * HASH_ENTRY_SIZE); s->size = bucketcount * HASH_ENTRY_SIZE; sunos_hash_table (info)->bucketcount = bucketcount; /* Scan all the symbols, place them in the dynamic symbol table, and build the dynamic hash table. We reuse dynsymcount as a counter for the number of symbols we have added so far. */ sunos_hash_table (info)->dynsymcount = 0; sunos_link_hash_traverse (sunos_hash_table (info), sunos_scan_dynamic_symbol, (void *) info); BFD_ASSERT (sunos_hash_table (info)->dynsymcount == dynsymcount); /* The SunOS native linker seems to align the total size of the symbol strings to a multiple of 8. I don't know if this is important, but it can't hurt much. */ s = bfd_get_section_by_name (dynobj, ".dynstr"); BFD_ASSERT (s != NULL); if ((s->size & 7) != 0) { bfd_size_type add; bfd_byte *contents; add = 8 - (s->size & 7); contents = bfd_realloc (s->contents, s->size + add); if (contents == NULL) return FALSE; memset (contents + s->size, 0, (size_t) add); s->contents = contents; s->size += add; } } /* Now that we have worked out the sizes of the procedure linkage table and the dynamic relocs, allocate storage for them. */ s = bfd_get_section_by_name (dynobj, ".plt"); BFD_ASSERT (s != NULL); if (s->size != 0) { s->contents = bfd_alloc (dynobj, s->size); if (s->contents == NULL) return FALSE; /* Fill in the first entry in the table. */ switch (bfd_get_arch (dynobj)) { case bfd_arch_sparc: memcpy (s->contents, sparc_plt_first_entry, SPARC_PLT_ENTRY_SIZE); break; case bfd_arch_m68k: memcpy (s->contents, m68k_plt_first_entry, M68K_PLT_ENTRY_SIZE); break; default: abort (); } } s = bfd_get_section_by_name (dynobj, ".dynrel"); if (s->size != 0) { s->contents = bfd_alloc (dynobj, s->size); if (s->contents == NULL) return FALSE; } /* We use the reloc_count field to keep track of how many of the relocs we have output so far. */ s->reloc_count = 0; /* Make space for the global offset table. */ s = bfd_get_section_by_name (dynobj, ".got"); s->contents = bfd_alloc (dynobj, s->size); if (s->contents == NULL) return FALSE; *sneedptr = bfd_get_section_by_name (dynobj, ".need"); *srulesptr = bfd_get_section_by_name (dynobj, ".rules"); return TRUE; } /* Link a dynamic object. We actually don't have anything to do at this point. This entry point exists to prevent the regular linker code from doing anything with the object. */ static bfd_boolean sunos_link_dynamic_object (struct bfd_link_info *info ATTRIBUTE_UNUSED, bfd *abfd ATTRIBUTE_UNUSED) { return TRUE; } /* Write out a dynamic symbol. This is called by the final traversal over the symbol table. */ static bfd_boolean sunos_write_dynamic_symbol (bfd *output_bfd, struct bfd_link_info *info, struct aout_link_hash_entry *harg) { struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg; int type; bfd_vma val; asection *s; struct external_nlist *outsym; /* If this symbol is in the procedure linkage table, fill in the table entry. */ if (h->plt_offset != 0) { bfd *dynobj; asection *splt; bfd_byte *p; bfd_vma r_address; dynobj = sunos_hash_table (info)->dynobj; splt = bfd_get_section_by_name (dynobj, ".plt"); p = splt->contents + h->plt_offset; s = bfd_get_section_by_name (dynobj, ".dynrel"); r_address = (splt->output_section->vma + splt->output_offset + h->plt_offset); switch (bfd_get_arch (output_bfd)) { case bfd_arch_sparc: if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0) { bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD0, p); bfd_put_32 (output_bfd, (SPARC_PLT_ENTRY_WORD1 + (((- (h->plt_offset + 4) >> 2) & 0x3fffffff))), p + 4); bfd_put_32 (output_bfd, SPARC_PLT_ENTRY_WORD2 + s->reloc_count, p + 8); } else { val = (h->root.root.u.def.section->output_section->vma + h->root.root.u.def.section->output_offset + h->root.root.u.def.value); bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD0 + ((val >> 10) & 0x3fffff), p); bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD1 + (val & 0x3ff), p + 4); bfd_put_32 (output_bfd, SPARC_PLT_PIC_WORD2, p + 8); } break; case bfd_arch_m68k: if (! info->shared && (h->flags & SUNOS_DEF_REGULAR) != 0) abort (); bfd_put_16 (output_bfd, M68K_PLT_ENTRY_WORD0, p); bfd_put_32 (output_bfd, (- (h->plt_offset + 2)), p + 2); bfd_put_16 (output_bfd, (bfd_vma) s->reloc_count, p + 6); r_address += 2; break; default: abort (); } /* We also need to add a jump table reloc, unless this is the result of a JMP_TBL reloc from PIC compiled code. */ if (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0) { BFD_ASSERT (h->dynindx >= 0); BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->size); p = s->contents + s->reloc_count * obj_reloc_entry_size (output_bfd); if (obj_reloc_entry_size (output_bfd) == RELOC_STD_SIZE) { struct reloc_std_external *srel; srel = (struct reloc_std_external *) p; PUT_WORD (output_bfd, r_address, srel->r_address); if (bfd_header_big_endian (output_bfd)) { srel->r_index[0] = (bfd_byte) (h->dynindx >> 16); srel->r_index[1] = (bfd_byte) (h->dynindx >> 8); srel->r_index[2] = (bfd_byte) (h->dynindx); srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG | RELOC_STD_BITS_JMPTABLE_BIG); } else { srel->r_index[2] = (bfd_byte) (h->dynindx >> 16); srel->r_index[1] = (bfd_byte) (h->dynindx >> 8); srel->r_index[0] = (bfd_byte)h->dynindx; srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE | RELOC_STD_BITS_JMPTABLE_LITTLE); } } else { struct reloc_ext_external *erel; erel = (struct reloc_ext_external *) p; PUT_WORD (output_bfd, r_address, erel->r_address); if (bfd_header_big_endian (output_bfd)) { erel->r_index[0] = (bfd_byte) (h->dynindx >> 16); erel->r_index[1] = (bfd_byte) (h->dynindx >> 8); erel->r_index[2] = (bfd_byte)h->dynindx; erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_BIG | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_BIG)); } else { erel->r_index[2] = (bfd_byte) (h->dynindx >> 16); erel->r_index[1] = (bfd_byte) (h->dynindx >> 8); erel->r_index[0] = (bfd_byte)h->dynindx; erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_LITTLE | (RELOC_JMP_SLOT << RELOC_EXT_BITS_TYPE_SH_LITTLE)); } PUT_WORD (output_bfd, (bfd_vma) 0, erel->r_addend); } ++s->reloc_count; } } /* If this is not a dynamic symbol, we don't have to do anything else. We only check this after handling the PLT entry, because we can have a PLT entry for a nondynamic symbol when linking PIC compiled code from a regular object. */ if (h->dynindx < 0) return TRUE; switch (h->root.root.type) { default: case bfd_link_hash_new: abort (); /* Avoid variable not initialized warnings. */ return TRUE; case bfd_link_hash_undefined: type = N_UNDF | N_EXT; val = 0; break; case bfd_link_hash_defined: case bfd_link_hash_defweak: { asection *sec; asection *output_section; sec = h->root.root.u.def.section; output_section = sec->output_section; BFD_ASSERT (bfd_is_abs_section (output_section) || output_section->owner == output_bfd); if (h->plt_offset != 0 && (h->flags & SUNOS_DEF_REGULAR) == 0) { type = N_UNDF | N_EXT; val = 0; } else { if (output_section == obj_textsec (output_bfd)) type = (h->root.root.type == bfd_link_hash_defined ? N_TEXT : N_WEAKT); else if (output_section == obj_datasec (output_bfd)) type = (h->root.root.type == bfd_link_hash_defined ? N_DATA : N_WEAKD); else if (output_section == obj_bsssec (output_bfd)) type = (h->root.root.type == bfd_link_hash_defined ? N_BSS : N_WEAKB); else type = (h->root.root.type == bfd_link_hash_defined ? N_ABS : N_WEAKA); type |= N_EXT; val = (h->root.root.u.def.value + output_section->vma + sec->output_offset); } } break; case bfd_link_hash_common: type = N_UNDF | N_EXT; val = h->root.root.u.c.size; break; case bfd_link_hash_undefweak: type = N_WEAKU; val = 0; break; case bfd_link_hash_indirect: case bfd_link_hash_warning: /* FIXME: Ignore these for now. The circumstances under which they should be written out are not clear to me. */ return TRUE; } s = bfd_get_section_by_name (sunos_hash_table (info)->dynobj, ".dynsym"); BFD_ASSERT (s != NULL); outsym = ((struct external_nlist *) (s->contents + h->dynindx * EXTERNAL_NLIST_SIZE)); H_PUT_8 (output_bfd, type, outsym->e_type); H_PUT_8 (output_bfd, 0, outsym->e_other); /* FIXME: The native linker doesn't use 0 for desc. It seems to use one less than the desc value in the shared library, although that seems unlikely. */ H_PUT_16 (output_bfd, 0, outsym->e_desc); PUT_WORD (output_bfd, h->dynstr_index, outsym->e_strx); PUT_WORD (output_bfd, val, outsym->e_value); return TRUE; } /* This is called for each reloc against an external symbol. If this is a reloc which are are going to copy as a dynamic reloc, then copy it over, and tell the caller to not bother processing this reloc. */ static bfd_boolean sunos_check_dynamic_reloc (struct bfd_link_info *info, bfd *input_bfd, asection *input_section, struct aout_link_hash_entry *harg, void * reloc, bfd_byte *contents ATTRIBUTE_UNUSED, bfd_boolean *skip, bfd_vma *relocationp) { struct sunos_link_hash_entry *h = (struct sunos_link_hash_entry *) harg; bfd *dynobj; bfd_boolean baserel; bfd_boolean jmptbl; bfd_boolean pcrel; asection *s; bfd_byte *p; long indx; *skip = FALSE; dynobj = sunos_hash_table (info)->dynobj; if (h != NULL && h->plt_offset != 0 && (info->shared || (h->flags & SUNOS_DEF_REGULAR) == 0)) { asection *splt; /* Redirect the relocation to the PLT entry. */ splt = bfd_get_section_by_name (dynobj, ".plt"); *relocationp = (splt->output_section->vma + splt->output_offset + h->plt_offset); } if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) { struct reloc_std_external *srel; srel = (struct reloc_std_external *) reloc; if (bfd_header_big_endian (input_bfd)) { baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_BIG)); jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_BIG)); pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_BIG)); } else { baserel = (0 != (srel->r_type[0] & RELOC_STD_BITS_BASEREL_LITTLE)); jmptbl = (0 != (srel->r_type[0] & RELOC_STD_BITS_JMPTABLE_LITTLE)); pcrel = (0 != (srel->r_type[0] & RELOC_STD_BITS_PCREL_LITTLE)); } } else { struct reloc_ext_external *erel; int r_type; erel = (struct reloc_ext_external *) reloc; if (bfd_header_big_endian (input_bfd)) r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_BIG) >> RELOC_EXT_BITS_TYPE_SH_BIG); else r_type = ((erel->r_type[0] & RELOC_EXT_BITS_TYPE_LITTLE) >> RELOC_EXT_BITS_TYPE_SH_LITTLE); baserel = (r_type == RELOC_BASE10 || r_type == RELOC_BASE13 || r_type == RELOC_BASE22); jmptbl = r_type == RELOC_JMP_TBL; pcrel = (r_type == RELOC_DISP8 || r_type == RELOC_DISP16 || r_type == RELOC_DISP32 || r_type == RELOC_WDISP30 || r_type == RELOC_WDISP22); /* We don't consider the PC10 and PC22 types to be PC relative, because they are pcrel_offset. */ } if (baserel) { bfd_vma *got_offsetp; asection *sgot; if (h != NULL) got_offsetp = &h->got_offset; else if (adata (input_bfd).local_got_offsets == NULL) got_offsetp = NULL; else { struct reloc_std_external *srel; int r_index; srel = (struct reloc_std_external *) reloc; if (obj_reloc_entry_size (input_bfd) == RELOC_STD_SIZE) { if (bfd_header_big_endian (input_bfd)) r_index = ((srel->r_index[0] << 16) | (srel->r_index[1] << 8) | srel->r_index[2]); else r_index = ((srel->r_index[2] << 16) | (srel->r_index[1] << 8) | srel->r_index[0]); } else { struct reloc_ext_external *erel; erel = (struct reloc_ext_external *) reloc; if (bfd_header_big_endian (input_bfd)) r_index = ((erel->r_index[0] << 16) | (erel->r_index[1] << 8) | erel->r_index[2]); else r_index = ((erel->r_index[2] << 16) | (erel->r_index[1] << 8) | erel->r_index[0]); } got_offsetp = adata (input_bfd).local_got_offsets + r_index; } BFD_ASSERT (got_offsetp != NULL && *got_offsetp != 0); sgot = bfd_get_section_by_name (dynobj, ".got"); /* We set the least significant bit to indicate whether we have already initialized the GOT entry. */ if ((*got_offsetp & 1) == 0) { if (h == NULL || (! info->shared && ((h->flags & SUNOS_DEF_DYNAMIC) == 0 || (h->flags & SUNOS_DEF_REGULAR) != 0))) PUT_WORD (dynobj, *relocationp, sgot->contents + *got_offsetp); else PUT_WORD (dynobj, 0, sgot->contents + *got_offsetp); if (info->shared || (h != NULL && (h->flags & SUNOS_DEF_DYNAMIC) != 0 && (h->flags & SUNOS_DEF_REGULAR) == 0)) { /* We need to create a GLOB_DAT or 32 reloc to tell the dynamic linker to fill in this entry in the table. */ s = bfd_get_section_by_name (dynobj, ".dynrel"); BFD_ASSERT (s != NULL); BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->size); p = (s->contents + s->reloc_count * obj_reloc_entry_size (dynobj)); if (h != NULL) indx = h->dynindx; else indx = 0; if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE) { struct reloc_std_external *srel; srel = (struct reloc_std_external *) p; PUT_WORD (dynobj, (*got_offsetp + sgot->output_section->vma + sgot->output_offset), srel->r_address); if (bfd_header_big_endian (dynobj)) { srel->r_index[0] = (bfd_byte) (indx >> 16); srel->r_index[1] = (bfd_byte) (indx >> 8); srel->r_index[2] = (bfd_byte)indx; if (h == NULL) srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_BIG; else srel->r_type[0] = (RELOC_STD_BITS_EXTERN_BIG | RELOC_STD_BITS_BASEREL_BIG | RELOC_STD_BITS_RELATIVE_BIG | (2 << RELOC_STD_BITS_LENGTH_SH_BIG)); } else { srel->r_index[2] = (bfd_byte) (indx >> 16); srel->r_index[1] = (bfd_byte) (indx >> 8); srel->r_index[0] = (bfd_byte)indx; if (h == NULL) srel->r_type[0] = 2 << RELOC_STD_BITS_LENGTH_SH_LITTLE; else srel->r_type[0] = (RELOC_STD_BITS_EXTERN_LITTLE | RELOC_STD_BITS_BASEREL_LITTLE | RELOC_STD_BITS_RELATIVE_LITTLE | (2 << RELOC_STD_BITS_LENGTH_SH_LITTLE)); } } else { struct reloc_ext_external *erel; erel = (struct reloc_ext_external *) p; PUT_WORD (dynobj, (*got_offsetp + sgot->output_section->vma + sgot->output_offset), erel->r_address); if (bfd_header_big_endian (dynobj)) { erel->r_index[0] = (bfd_byte) (indx >> 16); erel->r_index[1] = (bfd_byte) (indx >> 8); erel->r_index[2] = (bfd_byte)indx; if (h == NULL) erel->r_type[0] = RELOC_32 << RELOC_EXT_BITS_TYPE_SH_BIG; else erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_BIG | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_BIG)); } else { erel->r_index[2] = (bfd_byte) (indx >> 16); erel->r_index[1] = (bfd_byte) (indx >> 8); erel->r_index[0] = (bfd_byte)indx; if (h == NULL) erel->r_type[0] = RELOC_32 << RELOC_EXT_BITS_TYPE_SH_LITTLE; else erel->r_type[0] = (RELOC_EXT_BITS_EXTERN_LITTLE | (RELOC_GLOB_DAT << RELOC_EXT_BITS_TYPE_SH_LITTLE)); } PUT_WORD (dynobj, 0, erel->r_addend); } ++s->reloc_count; } *got_offsetp |= 1; } *relocationp = (sgot->vma + (*got_offsetp &~ (bfd_vma) 1) - sunos_hash_table (info)->got_base); /* There is nothing else to do for a base relative reloc. */ return TRUE; } if (! sunos_hash_table (info)->dynamic_sections_needed) return TRUE; if (! info->shared) { if (h == NULL || h->dynindx == -1 || h->root.root.type != bfd_link_hash_undefined || (h->flags & SUNOS_DEF_REGULAR) != 0 || (h->flags & SUNOS_DEF_DYNAMIC) == 0 || (h->root.root.u.undef.abfd->flags & DYNAMIC) == 0) return TRUE; } else { if (h != NULL && (h->dynindx == -1 || jmptbl || strcmp (h->root.root.root.string, "__GLOBAL_OFFSET_TABLE_") == 0)) return TRUE; } /* It looks like this is a reloc we are supposed to copy. */ s = bfd_get_section_by_name (dynobj, ".dynrel"); BFD_ASSERT (s != NULL); BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) < s->size); p = s->contents + s->reloc_count * obj_reloc_entry_size (dynobj); /* Copy the reloc over. */ memcpy (p, reloc, obj_reloc_entry_size (dynobj)); if (h != NULL) indx = h->dynindx; else indx = 0; /* Adjust the address and symbol index. */ if (obj_reloc_entry_size (dynobj) == RELOC_STD_SIZE) { struct reloc_std_external *srel; srel = (struct reloc_std_external *) p; PUT_WORD (dynobj, (GET_WORD (dynobj, srel->r_address) + input_section->output_section->vma + input_section->output_offset), srel->r_address); if (bfd_header_big_endian (dynobj)) { srel->r_index[0] = (bfd_byte) (indx >> 16); srel->r_index[1] = (bfd_byte) (indx >> 8); srel->r_index[2] = (bfd_byte)indx; } else { srel->r_index[2] = (bfd_byte) (indx >> 16); srel->r_index[1] = (bfd_byte) (indx >> 8); srel->r_index[0] = (bfd_byte)indx; } /* FIXME: We may have to change the addend for a PC relative reloc. */ } else { struct reloc_ext_external *erel; erel = (struct reloc_ext_external *) p; PUT_WORD (dynobj, (GET_WORD (dynobj, erel->r_address) + input_section->output_section->vma + input_section->output_offset), erel->r_address); if (bfd_header_big_endian (dynobj)) { erel->r_index[0] = (bfd_byte) (indx >> 16); erel->r_index[1] = (bfd_byte) (indx >> 8); erel->r_index[2] = (bfd_byte)indx; } else { erel->r_index[2] = (bfd_byte) (indx >> 16); erel->r_index[1] = (bfd_byte) (indx >> 8); erel->r_index[0] = (bfd_byte)indx; } if (pcrel && h != NULL) { /* Adjust the addend for the change in address. */ PUT_WORD (dynobj, (GET_WORD (dynobj, erel->r_addend) - (input_section->output_section->vma + input_section->output_offset - input_section->vma)), erel->r_addend); } } ++s->reloc_count; if (h != NULL) *skip = TRUE; return TRUE; } /* Finish up the dynamic linking information. */ static bfd_boolean sunos_finish_dynamic_link (bfd *abfd, struct bfd_link_info *info) { bfd *dynobj; asection *o; asection *s; asection *sdyn; if (! sunos_hash_table (info)->dynamic_sections_needed && ! sunos_hash_table (info)->got_needed) return TRUE; dynobj = sunos_hash_table (info)->dynobj; sdyn = bfd_get_section_by_name (dynobj, ".dynamic"); BFD_ASSERT (sdyn != NULL); /* Finish up the .need section. The linker emulation code filled it in, but with offsets from the start of the section instead of real addresses. Now that we know the section location, we can fill in the final values. */ s = bfd_get_section_by_name (dynobj, ".need"); if (s != NULL && s->size != 0) { file_ptr filepos; bfd_byte *p; filepos = s->output_section->filepos + s->output_offset; p = s->contents; while (1) { bfd_vma val; PUT_WORD (dynobj, GET_WORD (dynobj, p) + filepos, p); val = GET_WORD (dynobj, p + 12); if (val == 0) break; PUT_WORD (dynobj, val + filepos, p + 12); p += 16; } } /* The first entry in the .got section is the address of the dynamic information, unless this is a shared library. */ s = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (s != NULL); if (info->shared || sdyn->size == 0) PUT_WORD (dynobj, 0, s->contents); else PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset, s->contents); for (o = dynobj->sections; o != NULL; o = o->next) { if ((o->flags & SEC_HAS_CONTENTS) != 0 && o->contents != NULL) { BFD_ASSERT (o->output_section != NULL && o->output_section->owner == abfd); if (! bfd_set_section_contents (abfd, o->output_section, o->contents, (file_ptr) o->output_offset, o->size)) return FALSE; } } if (sdyn->size > 0) { struct external_sun4_dynamic esd; struct external_sun4_dynamic_link esdl; file_ptr pos; /* Finish up the dynamic link information. */ PUT_WORD (dynobj, (bfd_vma) 3, esd.ld_version); PUT_WORD (dynobj, sdyn->output_section->vma + sdyn->output_offset + sizeof esd, esd.ldd); PUT_WORD (dynobj, (sdyn->output_section->vma + sdyn->output_offset + sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE), esd.ld); if (! bfd_set_section_contents (abfd, sdyn->output_section, &esd, (file_ptr) sdyn->output_offset, (bfd_size_type) sizeof esd)) return FALSE; PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_loaded); s = bfd_get_section_by_name (dynobj, ".need"); if (s == NULL || s->size == 0) PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_need); else PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, esdl.ld_need); s = bfd_get_section_by_name (dynobj, ".rules"); if (s == NULL || s->size == 0) PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_rules); else PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, esdl.ld_rules); s = bfd_get_section_by_name (dynobj, ".got"); BFD_ASSERT (s != NULL); PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_got); s = bfd_get_section_by_name (dynobj, ".plt"); BFD_ASSERT (s != NULL); PUT_WORD (dynobj, s->output_section->vma + s->output_offset, esdl.ld_plt); PUT_WORD (dynobj, s->size, esdl.ld_plt_sz); s = bfd_get_section_by_name (dynobj, ".dynrel"); BFD_ASSERT (s != NULL); BFD_ASSERT (s->reloc_count * obj_reloc_entry_size (dynobj) == s->size); PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, esdl.ld_rel); s = bfd_get_section_by_name (dynobj, ".hash"); BFD_ASSERT (s != NULL); PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, esdl.ld_hash); s = bfd_get_section_by_name (dynobj, ".dynsym"); BFD_ASSERT (s != NULL); PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, esdl.ld_stab); PUT_WORD (dynobj, (bfd_vma) 0, esdl.ld_stab_hash); PUT_WORD (dynobj, (bfd_vma) sunos_hash_table (info)->bucketcount, esdl.ld_buckets); s = bfd_get_section_by_name (dynobj, ".dynstr"); BFD_ASSERT (s != NULL); PUT_WORD (dynobj, s->output_section->filepos + s->output_offset, esdl.ld_symbols); PUT_WORD (dynobj, s->size, esdl.ld_symb_size); /* The size of the text area is the size of the .text section rounded up to a page boundary. FIXME: Should the page size be conditional on something? */ PUT_WORD (dynobj, BFD_ALIGN (obj_textsec (abfd)->size, 0x2000), esdl.ld_text); pos = sdyn->output_offset; pos += sizeof esd + EXTERNAL_SUN4_DYNAMIC_DEBUGGER_SIZE; if (! bfd_set_section_contents (abfd, sdyn->output_section, &esdl, pos, (bfd_size_type) sizeof esdl)) return FALSE; abfd->flags |= DYNAMIC; } return TRUE; }