reloc.c
来自「基于4个mips核的noc设计」· C语言 代码 · 共 2,228 行 · 第 1/5 页
C
2,228 行
{ case 0: { char x = bfd_get_8 (abfd, (char *) data + octets); DOIT (x); bfd_put_8 (abfd, x, (unsigned char *) data + octets); } break; case 1: { short x = bfd_get_16 (abfd, (bfd_byte *) data + octets); DOIT (x); bfd_put_16 (abfd, x, (unsigned char *) data + octets); } break; case 2: { long x = bfd_get_32 (abfd, (bfd_byte *) data + octets); DOIT (x); bfd_put_32 (abfd, x, (bfd_byte *) data + octets); } break; case -2: { long x = bfd_get_32 (abfd, (bfd_byte *) data + octets); relocation = -relocation; DOIT (x); bfd_put_32 (abfd, x, (bfd_byte *) data + octets); } break; case -1: { long x = bfd_get_16 (abfd, (bfd_byte *) data + octets); relocation = -relocation; DOIT (x); bfd_put_16 (abfd, x, (bfd_byte *) data + octets); } break; case 3: /* Do nothing */ break; case 4:#ifdef BFD64 { bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data + octets); DOIT (x); bfd_put_64 (abfd, x, (bfd_byte *) data + octets); }#else abort ();#endif break; default: return bfd_reloc_other; } return flag;}/*FUNCTION bfd_install_relocationSYNOPSIS bfd_reloc_status_type bfd_install_relocation (bfd *abfd, arelent *reloc_entry, PTR data, bfd_vma data_start, asection *input_section, char **error_message);DESCRIPTION This looks remarkably like <<bfd_perform_relocation>>, except it does not expect that the section contents have been filled in. I.e., it's suitable for use when creating, rather than applying a relocation. For now, this function should be considered reserved for the assembler.*/bfd_reloc_status_typebfd_install_relocation (abfd, reloc_entry, data_start, data_start_offset, input_section, error_message) bfd *abfd; arelent *reloc_entry; PTR data_start; bfd_vma data_start_offset; asection *input_section; char **error_message;{ bfd_vma relocation; bfd_reloc_status_type flag = bfd_reloc_ok; bfd_size_type octets = reloc_entry->address * bfd_octets_per_byte (abfd); bfd_vma output_base = 0; reloc_howto_type *howto = reloc_entry->howto; asection *reloc_target_output_section; asymbol *symbol; bfd_byte *data; symbol = *(reloc_entry->sym_ptr_ptr); if (bfd_is_abs_section (symbol->section)) { reloc_entry->address += input_section->output_offset; return bfd_reloc_ok; } /* If there is a function supplied to handle this relocation type, call it. It'll return `bfd_reloc_continue' if further processing can be done. */ if (howto->special_function) { bfd_reloc_status_type cont; /* XXX - The special_function calls haven't been fixed up to deal with creating new relocations and section contents. */ cont = howto->special_function (abfd, reloc_entry, symbol, /* XXX - Non-portable! */ ((bfd_byte *) data_start - data_start_offset), input_section, abfd, error_message); if (cont != bfd_reloc_continue) return cont; } /* Is the address of the relocation really within the section? */ if (reloc_entry->address > input_section->_cooked_size) return bfd_reloc_outofrange; /* Work out which section the relocation is targetted at and the initial relocation command value. */ /* Get symbol value. (Common symbols are special.) */ if (bfd_is_com_section (symbol->section)) relocation = 0; else relocation = symbol->value; reloc_target_output_section = symbol->section->output_section; /* Convert input-section-relative symbol value to absolute. */ if (howto->partial_inplace == false) output_base = 0; else output_base = reloc_target_output_section->vma; relocation += output_base + symbol->section->output_offset; /* Add in supplied addend. */ relocation += reloc_entry->addend; /* Here the variable relocation holds the final address of the symbol we are relocating against, plus any addend. */ if (howto->pc_relative == true) { /* This is a PC relative relocation. We want to set RELOCATION to the distance between the address of the symbol and the location. RELOCATION is already the address of the symbol. We start by subtracting the address of the section containing the location. If pcrel_offset is set, we must further subtract the position of the location within the section. Some targets arrange for the addend to be the negative of the position of the location within the section; for example, i386-aout does this. For i386-aout, pcrel_offset is false. Some other targets do not include the position of the location; for example, m88kbcs, or ELF. For those targets, pcrel_offset is true. If we are producing relocateable output, then we must ensure that this reloc will be correctly computed when the final relocation is done. If pcrel_offset is false we want to wind up with the negative of the location within the section, which means we must adjust the existing addend by the change in the location within the section. If pcrel_offset is true we do not want to adjust the existing addend at all. FIXME: This seems logical to me, but for the case of producing relocateable output it is not what the code actually does. I don't want to change it, because it seems far too likely that something will break. */ relocation -= input_section->output_section->vma + input_section->output_offset; if (howto->pcrel_offset == true && howto->partial_inplace == true) relocation -= reloc_entry->address; } if (howto->partial_inplace == false) { /* This is a partial relocation, and we want to apply the relocation to the reloc entry rather than the raw data. Modify the reloc inplace to reflect what we now know. */ reloc_entry->addend = relocation; reloc_entry->address += input_section->output_offset; return flag; } else { /* This is a partial relocation, but inplace, so modify the reloc record a bit. If we've relocated with a symbol with a section, change into a ref to the section belonging to the symbol. */ reloc_entry->address += input_section->output_offset; /* WTF?? */ if (abfd->xvec->flavour == bfd_target_coff_flavour && strcmp (abfd->xvec->name, "coff-Intel-little") != 0 && strcmp (abfd->xvec->name, "coff-Intel-big") != 0) {#if 1/* For m68k-coff, the addend was being subtracted twice during relocation with -r. Removing the line below this comment fixes that problem; see PR 2953.However, Ian wrote the following, regarding removing the line below,which explains why it is still enabled: --djmIf you put a patch like that into BFD you need to check all the COFFlinkers. I am fairly certain that patch will break coff-i386 (e.g.,SCO); see coff_i386_reloc in coff-i386.c where I worked around theproblem in a different way. There may very well be a reason that thecode works as it does.Hmmm. The first obvious point is that bfd_install_relocation shouldnot have any tests that depend upon the flavour. It's seem likeentirely the wrong place for such a thing. The second obvious pointis that the current code ignores the reloc addend when producingrelocateable output for COFF. That's peculiar. In fact, I reallyhave no idea what the point of the line you want to remove is.A typical COFF reloc subtracts the old value of the symbol and adds inthe new value to the location in the object file (if it's a pcrelative reloc it adds the difference between the symbol value and thelocation). When relocating we need to preserve that property.BFD handles this by setting the addend to the negative of the oldvalue of the symbol. Unfortunately it handles common symbols in anon-standard way (it doesn't subtract the old value) but that's adifferent story (we can't change it without losing backwardcompatibility with old object files) (coff-i386 does subtract the oldvalue, to be compatible with existing coff-i386 targets, like SCO).So everything works fine when not producing relocateable output. Whenwe are producing relocateable output, logically we should do exactlywhat we do when not producing relocateable output. Therefore, yourpatch is correct. In fact, it should probably always just setreloc_entry->addend to 0 for all cases, since it is, in fact, going toadd the value into the object file. This won't hurt the COFF code,which doesn't use the addend; I'm not sure what it will do to otherformats (the thing to check for would be whether any formats both usethe addend and set partial_inplace).When I wanted to make coff-i386 produce relocateable output, I raninto the problem that you are running into: I wanted to remove thatline. Rather than risk it, I made the coff-i386 relocs use a specialfunction; it's coff_i386_reloc in coff-i386.c. The functionspecifically adds the addend field into the object file, knowing thatbfd_install_relocation is not going to. If you remove that line, thencoff-i386.c will wind up adding the addend field in twice. It'strivial to fix; it just needs to be done.The problem with removing the line is just that it may break someworking code. With BFD it's hard to be sure of anything. The rightway to deal with this is simply to build and test at least all thesupported COFF targets. It should be straightforward if time and diskspace consuming. For each target: 1) build the linker 2) generate some executable, and link it using -r (I would probably use paranoia.o and link against newlib/libc.a, which for all the supported targets would be available in /usr/cygnus/progressive/H-host/target/lib/libc.a). 3) make the change to reloc.c 4) rebuild the linker 5) repeat step 2 6) if the resulting object files are the same, you have at least made it no worse 7) if they are different you have to figure out which version is right*/ relocation -= reloc_entry->addend;#endif reloc_entry->addend = 0; } else { reloc_entry->addend = relocation; } } /* FIXME: This overflow checking is incomplete, because the value might have overflowed before we get here. For a correct check we need to compute the value in a size larger than bitsize, but we can't reasonably do that for a reloc the same size as a host machine word. FIXME: We should also do overflow checking on the result after adding in the value contained in the object file. */ if (howto->complain_on_overflow != complain_overflow_dont) flag = bfd_check_overflow (howto->complain_on_overflow, howto->bitsize, howto->rightshift, bfd_arch_bits_per_address (abfd), relocation); /* Either we are relocating all the way, or we don't want to apply the relocation to the reloc entry (probably because there isn't any room in the output format to describe addends to relocs) */ /* The cast to bfd_vma avoids a bug in the Alpha OSF/1 C compiler (OSF version 1.3, compiler version 3.11). It miscompiles the following program: struct str { unsigned int i0; } s = { 0 }; int main () { unsigned long x; x = 0x100000000; x <<= (unsigned long) s.i0; if (x == 0) printf ("failed\n"); else printf ("succeeded (%lx)\n", x); } */ relocation >>= (bfd_vma) howto->rightshift; /* Shift everything up to where it's going to be used */ relocation <<= (bfd_vma) howto->bitpos; /* Wait for the day when all have the mask in them */ /* What we do: i instruction to be left alone o offset within instruction r relocation offset to apply S src mask D dst mask N ~dst mask A part 1 B part 2 R result Do this: (( i i i i i o o o o o from bfd_get<size> and S S S S S) to get the size offset we want + r r r r r r r r r r) to get the final value to place and D D D D D to chop to right size ----------------------- = A A A A A And this: ( i i i i i o o o o o from bfd_get<size> and N N N N N ) get instruction ----------------------- = B B B B B And then: ( B B B B B or A A A A A) ----------------------- = R R R R R R R R R R put into bfd_put<size> */#define DOIT(x) \ x = ( (x & ~howto->dst_mask) | (((x & howto->src_mask) + relocation) & howto->dst_mask)) data = (bfd_byte *) data_start + (octets - data_start_offset); switch (howto->size) { case 0: { char x = bfd_get_8 (abfd, (char *) data); DOIT (x); bfd_put_8 (abfd, x, (unsigned char *) data); } break; case 1: { short x = bfd_get_16 (abfd, (bfd_byte *) data); DOIT (x); bfd_put_16 (abfd, x, (unsigned char *) data); } break; case 2: { long x = bfd_get_32 (abfd, (bfd_byte *) data); DOIT (x); bfd_put_32 (abfd, x, (bfd_byte *) data); } break; case -2: { long x = bfd_get_32 (abfd, (bfd_byte *) data); relocation = -relocation; DOIT (x); bfd_put_32 (abfd, x, (bfd_byte *) data); } break; case 3: /* Do nothing */ break; case 4: { bfd_vma x = bfd_get_64 (abfd, (bfd_byte *) data); DOIT (x); bfd_put_64 (abfd, x, (bfd_byte *) data); } break; default: return bfd_reloc_other; } return flag;}/* This relocation routine is used by some of the backend linkers. They do not construct asymbol or arelent structures, so there is no reason for them to use bfd_perform_relocation. Also, bfd_perform_relocation is so hacked up it is easier to write a new function than to try to deal with it. This routine does a final relocation. Whether it is useful for a
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?