diff options
author | Jozef Lawrynowicz <jozef.l@mittosystems.com> | 2020-09-08 16:13:48 +0100 |
---|---|---|
committer | Jozef Lawrynowicz <jozef.l@mittosystems.com> | 2020-09-08 16:18:38 +0100 |
commit | 7d81bc937cd3949fc3bed8194646d3a4563f94b2 (patch) | |
tree | 6d1300169968fa3dae4c85e0c633f27ed61cb5ca /gas/config | |
parent | f1363b0fb4eb8bbe9ef08f1e78ff6ffa71e07b8b (diff) | |
download | gdb-7d81bc937cd3949fc3bed8194646d3a4563f94b2.zip gdb-7d81bc937cd3949fc3bed8194646d3a4563f94b2.tar.gz gdb-7d81bc937cd3949fc3bed8194646d3a4563f94b2.tar.bz2 |
MSP430: Support relocations for subtract expressions in .uleb128 directives
Link-time relaxations of branches are common for MSP430, given that GCC
can generate pessimal branch instructions, and the
-mcode-region=either/-mdata-region=either options to shuffle sections
can further change the type of branch instruction required.
These relaxations can result in invalid code when .uleb128
directives, used in the .gcc_except_table section, are used to calculate
the distance between two labels. A value for the .uleb128 directive is
calculated at assembly-time, and can't be updated at link-time, even if
relaxation causes the distance between the labels to change.
This patch adds relocations for subtract expressions in .uleb128
directives, to allow the linker to re-calculate the value of these
expressions after relaxation has been performed.
bfd/ChangeLog:
* bfd-in2.h (bfd_reloc_code_real): Add
BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
* elf32-msp430.c (msp430_elf_ignore_reloc): New.
(elf_msp430_howto_table): Add R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
(msp430_reloc_map): Add R_MSP430_GNU_{SET,SUB}_ULEB128.
(msp430x_reloc_map): Add R_MSP430X_GNU_{SET,SUB}_ULEB128.
(write_uleb128): New.
(msp430_final_link_relocate): Handle R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
* libbfd.c (_bfd_write_unsigned_leb128): New.
* libbfd.h (_bfd_write_unsigned_leb128): New prototype.
Add BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
* reloc.c: Document BFD_RELOC_MSP430_{SET,SUB}_ULEB128.
binutils/ChangeLog:
* readelf.c (target_specific_reloc_handling): Handle
R_MSP430{,X}_GNU_{SET,SUB}_ULEB128.
gas/ChangeLog:
* config/tc-msp430.c (msp430_insert_uleb128_fixes): New.
(msp430_md_end): Call msp430_insert_uleb128_fixes.
include/ChangeLog:
* elf/msp430.h (elf_msp430_reloc_type): Add
R_MSP430_GNU_{SET,SUB}_ULEB128.
(elf_msp430x_reloc_type): Add R_MSP430X_GNU_{SET,SUB}_ULEB128.
ld/ChangeLog:
* testsuite/ld-msp430-elf/msp430-elf.exp: Run new tests.
* testsuite/ld-msp430-elf/uleb128.s: New test.
* testsuite/ld-msp430-elf/uleb128_430.d: New test.
* testsuite/ld-msp430-elf/uleb128_430x.d: New test.
Diffstat (limited to 'gas/config')
-rw-r--r-- | gas/config/tc-msp430.c | 54 |
1 files changed, 53 insertions, 1 deletions
diff --git a/gas/config/tc-msp430.c b/gas/config/tc-msp430.c index 2738937..6d18032 100644 --- a/gas/config/tc-msp430.c +++ b/gas/config/tc-msp430.c @@ -5048,8 +5048,56 @@ msp430_fix_adjustable (struct fix *fixp ATTRIBUTE_UNUSED) return FALSE; } -/* Set the contents of the .MSP430.attributes and .GNU.attributes sections. */ +/* Scan uleb128 subtraction expressions and insert fixups for them. + e.g., .uleb128 .L1 - .L0 + Because relaxation may change the value of the subtraction, we + must resolve them at link-time. */ +static void +msp430_insert_uleb128_fixes (bfd *abfd ATTRIBUTE_UNUSED, + asection *sec, void *xxx ATTRIBUTE_UNUSED) +{ + segment_info_type *seginfo = seg_info (sec); + struct frag *fragP; + + subseg_set (sec, 0); + + for (fragP = seginfo->frchainP->frch_root; + fragP; fragP = fragP->fr_next) + { + expressionS *exp, *exp_dup; + + if (fragP->fr_type != rs_leb128 || fragP->fr_symbol == NULL) + continue; + + exp = symbol_get_value_expression (fragP->fr_symbol); + + if (exp->X_op != O_subtract) + continue; + + /* FIXME: Skip for .sleb128. */ + if (fragP->fr_subtype != 0) + continue; + + exp_dup = xmemdup (exp, sizeof (*exp), sizeof (*exp)); + exp_dup->X_op = O_symbol; + exp_dup->X_op_symbol = NULL; + + /* Emit the SUB relocation first, since the SET relocation will write out + the final value. */ + exp_dup->X_add_symbol = exp->X_op_symbol; + fix_new_exp (fragP, fragP->fr_fix, 0, + exp_dup, 0, BFD_RELOC_MSP430_SUB_ULEB128); + + exp_dup->X_add_symbol = exp->X_add_symbol; + /* Insert relocations to resolve the subtraction at link-time. */ + fix_new_exp (fragP, fragP->fr_fix, 0, + exp_dup, 0, BFD_RELOC_MSP430_SET_ULEB128); + + } +} + +/* Called after all assembly has been done. */ void msp430_md_end (void) { @@ -5065,6 +5113,10 @@ msp430_md_end (void) as_warn (_(WARN_NOP_AT_EOF)); } + /* Insert relocations for uleb128 directives, so the values can be recomputed + at link time. */ + bfd_map_over_sections (stdoutput, msp430_insert_uleb128_fixes, NULL); + /* We have already emitted an error if any of the following attributes disagree with the attributes in the input assembly file. See msp430_object_attribute. */ |