[PATCH] Fix 3 bugs in --eh-frame-hdr patch
Jakub Jelinek
jakub@redhat.com
Mon Dec 17 06:25:00 GMT 2001
More information about the Binutils mailing list
Mon Dec 17 06:25:00 GMT 2001
- Previous message (by thread): Makefile in /src/bfd/po
- Next message (by thread): [PATCH] Fix 3 bugs in --eh-frame-hdr patch
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
Hi! During further testing of GCC and binutils --eh-frame-hdr changes, I've discovered 3 problems: 1) the code didn't handle zero values specially (if memory value with (encoding & 0xf) is zero, then the value is zero for encoding too, ie. base is not added and indirection is not done either). 2) value to be stored into binary search table was computed improperly for DW_EH_PE_pcrel FDEs if some FDEs or CIEs have been removed before them (it was off by the difference between original and optimized placement of the FDE) 3) the code must update LSDA fields too if LSDA encoding is DW_EH_PE_pcrel, since again, if new_offset != offset for FDE, it will be off by their difference Bootstrapped, no binutils make check regressions. Fixes g++.old-deja/g++.eh/spec[23].C which I somehow missed during make check comparisons (being confused why badalloc1.C fails both with and without --eh-frame-hdr). Ok to commit? 2001-12-17 Jakub Jelinek <jakub@redhat.com> * elf-eh-frame.c (struct cie): Add make_lsda_relative. (struct eh_cie_fde): Add lsda_encoding, lsda_offset, make_lsda_relative. (read_value, write_value): New. (_bfd_elf_discard_section_eh_frame): Inicialize lsda_encoding, lsda_offset and make_lsda_relative. (_bfd_elf_eh_frame_section_offset): If make_lsda_relative, request no dynamic reloc for LSDA field of FDE. (_bfd_elf_write_section_eh_frame): Handle make_lsda_relative. If a non-DW_EH_PE_absptr value is 0, don't adjust it by base or pcrel. Fix address computation for DW_EH_PE_pcrel relocs. Update LSDA field if LSDA encoding is DW_EH_PE_pcrel, because . might have changed due to deleted FDE or CIEs. --- bfd/elf-eh-frame.c.jj Sat Dec 15 11:08:36 2001 +++ bfd/elf-eh-frame.c Mon Dec 17 15:14:48 2001 @@ -47,6 +47,7 @@ struct cie unsigned char fde_encoding; unsigned char initial_insn_length; unsigned char make_relative; + unsigned char make_lsda_relative; unsigned char initial_instructions[50]; }; @@ -57,9 +58,12 @@ struct eh_cie_fde asection *sec; unsigned int new_offset; unsigned char fde_encoding; + unsigned char lsda_encoding; + unsigned char lsda_offset; unsigned char cie : 1; unsigned char removed : 1; unsigned char make_relative : 1; + unsigned char make_lsda_relative : 1; }; struct eh_frame_sec_info @@ -95,6 +99,10 @@ static bfd_signed_vma read_signed_leb128 PARAMS ((bfd *, char *, unsigned int *)); static int get_DW_EH_PE_width PARAMS ((int, int)); +static bfd_vma read_value + PARAMS ((bfd *, bfd_byte *, int)); +static void write_value + PARAMS ((bfd *, bfd_byte *, bfd_vma, int)); static int cie_compare PARAMS ((struct cie *, struct cie *)); static int vma_compare @@ -200,6 +208,45 @@ int get_DW_EH_PE_width (encoding, ptr_si return 0; } +/* Read a width sized value from memory. */ + +static bfd_vma +read_value (abfd, buf, width) + bfd *abfd; + bfd_byte *buf; + int width; +{ + bfd_vma value; + + switch (width) + { + case 2: value = bfd_get_16 (abfd, buf); break; + case 4: value = bfd_get_32 (abfd, buf); break; + case 8: value = bfd_get_64 (abfd, buf); break; + default: BFD_FAIL (); return 0; + } + + return value; +} + +/* Store a width sized value to memory. */ + +static void +write_value (abfd, buf, value, width) + bfd *abfd; + bfd_byte *buf; + bfd_vma value; + int width; +{ + switch (width) + { + case 2: bfd_put_16 (abfd, value, buf); break; + case 4: bfd_put_32 (abfd, value, buf); break; + case 8: bfd_put_64 (abfd, value, buf); break; + default: BFD_FAIL (); + } +} + /* Return zero if C1 and C2 CIEs can be merged. */ static @@ -249,7 +296,8 @@ _bfd_elf_discard_section_eh_frame (abfd, struct eh_frame_hdr_info *hdr_info; struct eh_frame_sec_info *sec_info = NULL; unsigned int leb128_tmp; - unsigned int cie_usage_count, last_cie_ndx, i, offset, make_relative; + unsigned int cie_usage_count, last_cie_ndx, i, offset; + unsigned int make_relative, make_lsda_relative; Elf_Internal_Rela *rel; bfd_size_type new_size; unsigned int ptr_size; @@ -306,6 +354,7 @@ _bfd_elf_discard_section_eh_frame (abfd, cie_usage_count = 0; new_size = sec->_raw_size; make_relative = hdr_info->last_cie.make_relative; + make_lsda_relative = hdr_info->last_cie.make_lsda_relative; sec_info = bfd_zmalloc (sizeof (struct eh_frame_sec_info) + 99 * sizeof (struct eh_cie_fde)); if (sec_info == NULL) @@ -418,6 +467,8 @@ _bfd_elf_discard_section_eh_frame (abfd, hdr_info->last_cie_offset = last_cie - ehbuf; sec_info->entry[last_cie_ndx].make_relative = cie.make_relative; + sec_info->entry[last_cie_ndx].make_lsda_relative + = cie.make_lsda_relative; } } @@ -543,6 +594,11 @@ _bfd_elf_discard_section_eh_frame (abfd, && (cie.fde_encoding & 0xf0) == DW_EH_PE_absptr) cie.make_relative = 1; + if (0 + && info->shared + && (cie.lsda_encoding & 0xf0) == DW_EH_PE_absptr) + cie.make_lsda_relative = 1; + /* If FDE encoding was not specified, it defaults to DW_EH_absptr. */ if (cie.fde_encoding == DW_EH_PE_omit) @@ -584,11 +640,24 @@ _bfd_elf_discard_section_eh_frame (abfd, hdr_info->fde_count++; } cookie->rel = rel; + if (cie.lsda_encoding != DW_EH_PE_omit) + { + unsigned int dummy; + + aug = buf; + buf += 2 * get_DW_EH_PE_width (cie.fde_encoding, ptr_size); + if (cie.augmentation[0] == 'z') + read_uleb128 (dummy, buf); + /* If some new augmentation data is added before LSDA + in FDE augmentation area, this need to be adjusted. */ + sec_info->entry[sec_info->count].lsda_offset = (buf - aug); + } buf = last_fde + 4 + hdr.length; SKIP_RELOCS (buf); } sec_info->entry[sec_info->count].fde_encoding = cie.fde_encoding; + sec_info->entry[sec_info->count].lsda_encoding = cie.lsda_encoding; sec_info->count++; } @@ -608,9 +677,13 @@ _bfd_elf_discard_section_eh_frame (abfd, { last_cie_ndx = i; make_relative = sec_info->entry[i].make_relative; + make_lsda_relative = sec_info->entry[i].make_lsda_relative; } else - sec_info->entry[i].make_relative = make_relative; + { + sec_info->entry[i].make_relative = make_relative; + sec_info->entry[i].make_lsda_relative = make_lsda_relative; + } } else if (sec_info->entry[i].cie && sec_info->entry[i].sec == sec) { @@ -781,6 +854,15 @@ _bfd_elf_eh_frame_section_offset (output && offset == sec_info->entry[mid].offset + 8) return (bfd_vma) -1; + /* If converting LSDA pointers to DW_EH_PE_pcrel, there will be no need + for run-time relocation against LSDA field. */ + if (sec_info->entry[mid].make_lsda_relative + && ! sec_info->entry[mid].cie + && (offset + == (sec_info->entry[mid].offset + 8 + + sec_info->entry[mid].lsda_offset))) + return (bfd_vma) -1; + return (offset + (sec_info->entry[mid].new_offset - sec_info->entry[mid].offset)); } @@ -845,13 +927,17 @@ _bfd_elf_write_section_eh_frame (abfd, s { /* CIE */ cie_offset = sec_info->entry[i].new_offset; - if (sec_info->entry[i].make_relative) + if (sec_info->entry[i].make_relative + || sec_info->entry[i].make_lsda_relative) { unsigned char *aug; + unsigned int action; unsigned int dummy, per_width, per_encoding; - /* Need to find 'R' augmentation's argument and modify + /* Need to find 'R' or 'L' augmentation's argument and modify DW_EH_PE_* value. */ + action = (sec_info->entry[i].make_relative ? 1 : 0) + | (sec_info->entry[i].make_lsda_relative ? 2 : 0); buf = contents + sec_info->entry[i].offset; /* Skip length, id and version. */ buf += 9; @@ -866,10 +952,16 @@ _bfd_elf_write_section_eh_frame (abfd, s aug++; } - while (*aug != 'R') + while (action) switch (*aug++) { case 'L': + if (action & 2) + { + BFD_ASSERT (*buf == sec_info->entry[i].lsda_encoding); + *buf |= DW_EH_PE_pcrel; + action &= ~2; + } buf++; break; case 'P': @@ -883,19 +975,25 @@ _bfd_elf_write_section_eh_frame (abfd, s & ~((bfd_size_type) per_width - 1))); buf += per_width; break; + case 'R': + if (action & 1) + { + BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding); + *buf |= DW_EH_PE_pcrel; + action &= ~1; + } + buf++; + break; default: BFD_FAIL (); } - - BFD_ASSERT (*buf == sec_info->entry[i].fde_encoding); - *buf |= DW_EH_PE_pcrel; } } else { /* FDE */ bfd_vma value = 0, address; - unsigned int fde_width; + unsigned int width; buf = contents + sec_info->entry[i].offset; /* Skip length. */ @@ -903,45 +1001,36 @@ _bfd_elf_write_section_eh_frame (abfd, s bfd_put_32 (abfd, sec_info->entry[i].new_offset + 4 - cie_offset, buf); buf += 4; - fde_width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding, - ptr_size); - switch (fde_width) + width = get_DW_EH_PE_width (sec_info->entry[i].fde_encoding, + ptr_size); + address = value = read_value (abfd, buf, width); + if (value) { - case 2: value = bfd_get_16 (abfd, buf); break; - case 4: value = bfd_get_32 (abfd, buf); break; - case 8: value = bfd_get_64 (abfd, buf); break; - default: BFD_FAIL (); - } - address = value; - switch (sec_info->entry[i].fde_encoding & 0xf0) - { - case DW_EH_PE_indirect: - case DW_EH_PE_textrel: - BFD_ASSERT (hdr_info == NULL); - break; - case DW_EH_PE_datarel: - { - asection *got = bfd_get_section_by_name (abfd, ".got"); - - BFD_ASSERT (got != NULL); - address += got->vma; - } - break; - case DW_EH_PE_pcrel: - value += (sec_info->entry[i].offset - - sec_info->entry[i].new_offset); - address += (sec->output_section->vma + sec->output_offset + switch (sec_info->entry[i].fde_encoding & 0xf0) + { + case DW_EH_PE_indirect: + case DW_EH_PE_textrel: + BFD_ASSERT (hdr_info == NULL); + break; + case DW_EH_PE_datarel: + { + asection *got = bfd_get_section_by_name (abfd, ".got"); + + BFD_ASSERT (got != NULL); + address += got->vma; + } + break; + case DW_EH_PE_pcrel: + value += (sec_info->entry[i].offset + - sec_info->entry[i].new_offset); + address += (sec->output_section->vma + sec->output_offset + + sec_info->entry[i].offset + 8); + break; + } + if (sec_info->entry[i].make_relative) + value -= (sec->output_section->vma + sec->output_offset + sec_info->entry[i].new_offset + 8); - break; - } - if (sec_info->entry[i].make_relative) - value -= (sec->output_section->vma + sec->output_offset - + sec_info->entry[i].new_offset + 8); - switch (fde_width) - { - case 2: bfd_put_16 (abfd, value, buf); break; - case 4: bfd_put_32 (abfd, value, buf); break; - case 8: bfd_put_64 (abfd, value, buf); break; + write_value (abfd, buf, value, width); } if (hdr_info) @@ -951,6 +1040,27 @@ _bfd_elf_write_section_eh_frame (abfd, s = (sec->output_section->vma + sec->output_offset + sec_info->entry[i].new_offset); } + + if ((sec_info->entry[i].lsda_encoding & 0xf0) == DW_EH_PE_pcrel + || sec_info->entry[i].make_lsda_relative) + { + buf += sec_info->entry[i].lsda_offset; + width = get_DW_EH_PE_width (sec_info->entry[i].lsda_encoding, + ptr_size); + value = read_value (abfd, buf, width); + if (value) + { + if ((sec_info->entry[i].lsda_encoding & 0xf0) + == DW_EH_PE_pcrel) + value += (sec_info->entry[i].offset + - sec_info->entry[i].new_offset); + else if (sec_info->entry[i].make_lsda_relative) + value -= (sec->output_section->vma + sec->output_offset + + sec_info->entry[i].new_offset + 8 + + sec_info->entry[i].lsda_offset); + write_value (abfd, buf, value, width); + } + } } BFD_ASSERT (p == contents + sec_info->entry[i].new_offset); Jakub
- Previous message (by thread): Makefile in /src/bfd/po
- Next message (by thread): [PATCH] Fix 3 bugs in --eh-frame-hdr patch
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
More information about the Binutils mailing list