nlmconv.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,181 行 · 第 1/5 页
C
2,181 行
if (! bfd_set_section_contents (outbfd, secsec, (PTR) inname, secsecoff, strlen (inname) + 1)) bfd_fatal (_("set .nlmsection contents")); secsecoff += strlen (inname) + 1; add = ((secsecoff + 3) &~ 3) - secsecoff; if (add != 0) { bfd_h_put_32 (outbfd, (bfd_vma) 0, buf); if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, add)) bfd_fatal (_("set .nlmsection contents")); secsecoff += add; } if (contents != NULL) bfd_h_put_32 (outbfd, (bfd_vma) outsec->filepos, buf); else bfd_h_put_32 (outbfd, (bfd_vma) 0, buf); if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4)) bfd_fatal (_("set .nlmsection contents")); secsecoff += 4; bfd_h_put_32 (outbfd, (bfd_vma) size, buf); if (! bfd_set_section_contents (outbfd, secsec, buf, secsecoff, 4)) bfd_fatal (_("set .nlmsection contents")); secsecoff += 4;}/* Some, perhaps all, NetWare targets require changing the relocs used by the input formats. */static voidmangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size) bfd *outbfd; asection *insec; arelent ***relocs_ptr; long *reloc_count_ptr; char *contents; bfd_size_type contents_size;{ switch (bfd_get_arch (outbfd)) {#ifdef NLMCONV_I386 case bfd_arch_i386: i386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size); break;#endif#ifdef NLMCONV_ALPHA case bfd_arch_alpha: alpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size); break;#endif#ifdef NLMCONV_POWERPC case bfd_arch_powerpc: powerpc_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size); break;#endif default: default_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size); break; }}/* By default all we need to do for relocs is change the address by the output_offset. *//*ARGSUSED*/static voiddefault_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size) bfd *outbfd; asection *insec; arelent ***relocs_ptr; long *reloc_count_ptr; char *contents; bfd_size_type contents_size;{ if (insec->output_offset != 0) { long reloc_count; register arelent **relocs; register long i; reloc_count = *reloc_count_ptr; relocs = *relocs_ptr; for (i = 0; i < reloc_count; i++, relocs++) (*relocs)->address += insec->output_offset; }}#ifdef NLMCONV_I386/* NetWare on the i386 supports a restricted set of relocs, which are different from those used on other i386 targets. This routine converts the relocs. It is, obviously, very target dependent. At the moment, the nlm32-i386 backend performs similar translations; however, it is more reliable and efficient to do them here. */static reloc_howto_type nlm_i386_pcrel_howto = HOWTO (1, /* type */ 0, /* rightshift */ 2, /* size (0 = byte, 1 = short, 2 = long) */ 32, /* bitsize */ true, /* pc_relative */ 0, /* bitpos */ complain_overflow_signed, /* complain_on_overflow */ 0, /* special_function */ "DISP32", /* name */ true, /* partial_inplace */ 0xffffffff, /* src_mask */ 0xffffffff, /* dst_mask */ true); /* pcrel_offset */static voidi386_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size) bfd *outbfd; asection *insec; arelent ***relocs_ptr; long *reloc_count_ptr; char *contents; bfd_size_type contents_size;{ long reloc_count, i; arelent **relocs; reloc_count = *reloc_count_ptr; relocs = *relocs_ptr; for (i = 0; i < reloc_count; i++) { arelent *rel; asymbol *sym; bfd_size_type address; bfd_vma addend; rel = *relocs++; sym = *rel->sym_ptr_ptr; /* We're moving the relocs from the input section to the output section, so we must adjust the address accordingly. */ address = rel->address; rel->address += insec->output_offset; /* Note that no serious harm will ensue if we fail to change a reloc. The backend will fail when writing out the reloc. */ /* Make sure this reloc is within the data we have. We use only 4 byte relocs here, so we insist on having 4 bytes. */ if (address + 4 > contents_size) continue; /* A PC relative reloc entirely within a single section is completely unnecessary. This can be generated by ld -r. */ if (sym == insec->symbol && rel->howto != NULL && rel->howto->pc_relative && ! rel->howto->pcrel_offset) { --*reloc_count_ptr; --relocs; memmove (relocs, relocs + 1, (size_t) ((reloc_count - i) * sizeof (arelent *))); continue; } /* Get the amount the relocation will add in. */ addend = rel->addend + sym->value; /* NetWare doesn't support PC relative relocs against defined symbols, so we have to eliminate them by doing the relocation now. We can only do this if the reloc is within a single section. */ if (rel->howto != NULL && rel->howto->pc_relative && bfd_get_section (sym) == insec->output_section) { bfd_vma val; if (rel->howto->pcrel_offset) addend -= address; val = bfd_get_32 (outbfd, (bfd_byte *) contents + address); val += addend; bfd_put_32 (outbfd, val, (bfd_byte *) contents + address); --*reloc_count_ptr; --relocs; memmove (relocs, relocs + 1, (size_t) ((reloc_count - i) * sizeof (arelent *))); continue; } /* NetWare doesn't support reloc addends, so we get rid of them here by simply adding them into the object data. We handle the symbol value, if any, the same way. */ if (addend != 0 && rel->howto != NULL && rel->howto->rightshift == 0 && rel->howto->size == 2 && rel->howto->bitsize == 32 && rel->howto->bitpos == 0 && rel->howto->src_mask == 0xffffffff && rel->howto->dst_mask == 0xffffffff) { bfd_vma val; val = bfd_get_32 (outbfd, (bfd_byte *) contents + address); val += addend; bfd_put_32 (outbfd, val, (bfd_byte *) contents + address); /* Adjust the reloc for the changes we just made. */ rel->addend = 0; if (! bfd_is_und_section (bfd_get_section (sym))) rel->sym_ptr_ptr = bfd_get_section (sym)->symbol_ptr_ptr; } /* NetWare uses a reloc with pcrel_offset set. We adjust pc_relative relocs accordingly. We are going to change the howto field, so we can only do this if the current one is compatible. We should check that special_function is NULL here, but at the moment coff-i386 uses a special_function which does not affect what we are doing here. */ if (rel->howto != NULL && rel->howto->pc_relative && ! rel->howto->pcrel_offset && rel->howto->rightshift == 0 && rel->howto->size == 2 && rel->howto->bitsize == 32 && rel->howto->bitpos == 0 && rel->howto->src_mask == 0xffffffff && rel->howto->dst_mask == 0xffffffff) { bfd_vma val; /* When pcrel_offset is not set, it means that the negative of the address of the memory location is stored in the memory location. We must add it back in. */ val = bfd_get_32 (outbfd, (bfd_byte *) contents + address); val += address; bfd_put_32 (outbfd, val, (bfd_byte *) contents + address); /* We must change to a new howto. */ rel->howto = &nlm_i386_pcrel_howto; } }}#endif /* NLMCONV_I386 */#ifdef NLMCONV_ALPHA/* On the Alpha the first reloc for every section must be a special relocs which hold the GP address. Also, the first reloc in the file must be a special reloc which holds the address of the .lita section. */static reloc_howto_type nlm32_alpha_nw_howto = HOWTO (ALPHA_R_NW_RELOC, /* type */ 0, /* rightshift */ 0, /* size (0 = byte, 1 = short, 2 = long) */ 0, /* bitsize */ false, /* pc_relative */ 0, /* bitpos */ complain_overflow_dont, /* complain_on_overflow */ 0, /* special_function */ "NW_RELOC", /* name */ false, /* partial_inplace */ 0, /* src_mask */ 0, /* dst_mask */ false); /* pcrel_offset *//*ARGSUSED*/static voidalpha_mangle_relocs (outbfd, insec, relocs_ptr, reloc_count_ptr, contents, contents_size) bfd *outbfd; asection *insec; register arelent ***relocs_ptr; long *reloc_count_ptr; char *contents; bfd_size_type contents_size;{ long old_reloc_count; arelent **old_relocs; register arelent **relocs; old_reloc_count = *reloc_count_ptr; old_relocs = *relocs_ptr; relocs = (arelent **) xmalloc ((old_reloc_count + 3) * sizeof (arelent *)); *relocs_ptr = relocs; if (nlm_alpha_backend_data (outbfd)->lita_address == 0) { bfd *inbfd; asection *lita_section; inbfd = insec->owner; lita_section = bfd_get_section_by_name (inbfd, _LITA); if (lita_section != (asection *) NULL) { nlm_alpha_backend_data (outbfd)->lita_address = bfd_get_section_vma (inbfd, lita_section); nlm_alpha_backend_data (outbfd)->lita_size = bfd_section_size (inbfd, lita_section); } else { /* Avoid outputting this reloc again. */ nlm_alpha_backend_data (outbfd)->lita_address = 4; } *relocs = (arelent *) xmalloc (sizeof (arelent)); (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; (*relocs)->address = nlm_alpha_backend_data (outbfd)->lita_address; (*relocs)->addend = nlm_alpha_backend_data (outbfd)->lita_size + 1; (*relocs)->howto = &nlm32_alpha_nw_howto; ++relocs; ++(*reloc_count_ptr); } /* Get the GP value from bfd. */ if (nlm_alpha_backend_data (outbfd)->gp == 0) nlm_alpha_backend_data (outbfd)->gp = bfd_ecoff_get_gp_value (insec->owner); *relocs = (arelent *) xmalloc (sizeof (arelent)); (*relocs)->sym_ptr_ptr = bfd_abs_section_ptr->symbol_ptr_ptr; (*relocs)->address = nlm_alpha_backend_data (outbfd)->gp; (*relocs)->addend = 0; (*relocs)->howto = &nlm32_alpha_nw_howto; ++relocs; ++(*reloc_count_ptr); memcpy ((PTR) relocs, (PTR) old_relocs, (size_t) old_reloc_count * sizeof (arelent *)); relocs[old_reloc_count] = (arelent *) NULL; free (old_relocs); if (insec->output_offset != 0) { register bfd_size_type i; for (i = 0; i < (bfd_size_type) old_reloc_count; i++, relocs++) (*relocs)->address += insec->output_offset; }}#endif /* NLMCONV_ALPHA */#ifdef NLMCONV_POWERPC/* We keep a linked list of stubs which we must build. Because BFD requires us to know the sizes of all sections before we can set the contents of any, we must figure out which stubs we want to build before we can actually build any of them. */struct powerpc_stub{ /* Next stub in linked list. */ struct powerpc_stub *next; /* Symbol whose value is the start of the stub. This is a symbol whose name begins with `.'. */ asymbol *start; /* Symbol we are going to create a reloc against. This is a symbol with the same name as START but without the leading `.'. */ asymbol *reloc; /* The TOC index for this stub. This is the index into the TOC section at which the reloc is created. */ unsigned int toc_index;};/* The linked list of stubs. */static struct powerpc_stub *powerpc_stubs;/* This is what a stub looks like. The first instruction will get adjusted with the correct TOC index. */static unsigned long powerpc_stub_insns[] ={ 0x81820000, /* lwz r12,0(r2) */ 0x90410014, /* stw r2,20(r1) */ 0x800c0000, /* lwz r0,0(r12) */ 0x804c0004, /* lwz r2,r(r12) */ 0x7c0903a6, /* mtctr r0 */ 0x4e800420, /* bctr */ 0, /* Traceback table. */ 0xc8000, 0};#define POWERPC_STUB_INSN_COUNT \ (sizeof powerpc_stub_insns / sizeof powerpc_stub_insns[0])#define POWERPC_STUB_SIZE (4 * POWERPC_STUB_INSN_COUNT)/* Each stub uses a four byte TOC entry. */#define POWERPC_STUB_TOC_ENTRY_SIZE (4)/* The original size of the .got section. */static bfd_size_type powerpc_initial_got_size;/* Look for all undefined symbols beginning with `.', and prepare to build a stub for each one. */static voidpowerpc_build_stubs (inbfd, outbfd, symbols_ptr, symcount_ptr) bfd *inbfd; bfd *outbfd; asymbol ***symbols_ptr; long *symcount_ptr;{ asection *stub_sec; asection *got_sec; unsigned int got_base; long i; long symcount; long stubcount; /* Make a section to hold stubs. We don't set SEC_HAS_CONTENTS for the section to prevent copy_sections from reading from it. */ stub_sec = bfd_make_section (inbfd, ".stubs"); if (stub_sec == (asection *) NULL || ! bfd_set_section_flags (inbfd, stub_sec, (SEC_CODE | SEC_RELOC | SEC_ALLOC | SEC_LOAD))
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?