[ARM] VFP11 denorm erratum workaround in linker

Julian Brown julian@codesourcery.com
Fri Dec 15 14:16:00 GMT 2006


Hi,

This patch implements a workaround for an erratum in ARM's VFP11 
coprocessor. The nature of the erratum is as follows: if a VFP 
instruction has denormal operands, the coprocessor must bounce to 
support code to handle the operation. In some circumstances, 
instructions following the bounced instruction may be issued before this 
happens, even if they overwrite one of the previous instruction's operands.

(Note that the erratum is only triggered if full IEEE754 compliance is 
enabled by the relevant processor flags, e.g. it doesn't apply in 
"RunFast" mode, where denorm values are not bounced to support code. See 
ARM documentation for full details).

The erroneous behaviour can be avoided by inserting extra instructions 
between the anti-dependent instructions; for scalar code one 
intermediate instruction suffices to avoid the erratum, and in vector 
code two intermediate instructions must be used.

We've worked around this erratum in the linker: this means code 
(particularly third-party static libraries) doesn't need to be 
recompiled to invoke the workaround, and if future revisions of the chip 
fix the bug, the erratum can simply be switched off and programs 
relinked. Solving the problem in the linker also works for hand-written 
sequences of VFP code, which a fix in the compiler would not.

GCC at present only outputs scalar code for VFP units, so the default 
(pre-ARMv7 architectures) is to fix scalar code. The workaround can be 
disabled or selected for vector operations using the linker options:

   --vfp11-denorm-fix={none,scalar,vector}

A suitable warning is printed if ARMv7+ objects are being linked, and an 
attempt is made to enable the erratum workaround explicitly.

The workaround works by scanning input code sections for 
potentially-troublesome code sequences, and replacing them by branches 
to a specially-constructed veneer (similar to the way ARM<->Thumb 
interworking stubs are created at link-time). The veneer contains the 
original instruction plus a branch back to the original subsequent 
instruction, which is sufficient to avoid the erratum in either scalar 
or vector mode.

Note that we must be able to distinguish between code and data whilst 
scanning input sections -- this is done using mapping symbols, which 
must now be created for *input* sections, not output sections as 
previously. The previous code to create code/data maps for output 
sections has been removed, and dependent code adjusted accordingly (only 
elf32_arm_write_section, in fact).

BE8 mode needs some special attention -- since mapping tables are now 
always created, their existence alone is not enough to justify 
code-swapping in elf32_arm_write_section. We must pass an extra argument 
to the function (bfd_link_info) to determine whether to byteswap code or 
not. We also modify the input-section mapping tables for generated 
veneer sections, to make sure that they're byteswapped correctly, if needed.

Tested with cross to arm-none-eabi, and also with the GCC testsuite 
(C/C++/libstdc++) with -mfpu=vfp/-mfloat-abi=softfp.

This patch is dependent on a Newlib patch to add the .vfp11_veneer 
section to libgloss's linker scripts. That will follow shortly.

OK?

ChangeLog

     bfd/
     * bfd-in2.h: Regenerate.
     * bfd-in.h (bfd_arm_vfp11_fix): New enum. Specify how VFP11
     instruction scanning should be done.
     (bfd_elf32_arm_init_maps, bfd_elf32_arm_vfp11_erratum_scan)
     (bfd_elf32_arm_vfp11_fix_veneer_locations): Add prototypes.
     (bfd_elf32_arm_set_target_relocs): Add vfp11 fix type argument to
     prototype.
     * elf-bfd.h (elf_backend_write_section): Add struct bfd_link_info
     argument.
     * elf32-arm.c (VFP11_ERRATUM_VENEER_SECTION_NAME)
     (VFP11_ERRATUM_VENEER_ENTRY_NAME): Define macros.
     (elf32_vfp11_erratum_list): New struct. List of veneers or jumps to
     veneers.
     (_arm_elf_section_data): Add mapsize, erratumcount, erratumlist.
     (elf32_arm_link_hash_table): Add vfp11_erratum_glue_size,
     vfp11_fix and num_vfp11_fixes fields.
     (elf32_arm_link_hash_table_create): Initialise vfp11_fix,
     vfp11_erratum_glue_size, num_vfp11_fixes fields.
     (VFP11_ERRATUM_VENEER_SIZE): Define. Size of an (ARM) veneer.
     (bfd_elf32_arm_allocate_interworking_sections): Initialise erratum
     glue section.
     (elf32_arm_section_map_add): Add an code/data mapping symbol entry
     to a section's map.
     (record_vfp11_erratum_veneer): Create a single veneer, and its
     associated symbols.
     (bfd_elf32_arm_add_glue_sections_to_bfd): Add vfp11 erratum glue.
     (bfd_elf32_arm_init_maps): Initialise mapping symbol table for input
     BFDs.
     (bfd_elf32_arm_set_vfp11_fix): Set the type of erratum workaround
     required.
     (bfd_arm_vfp11_pipe): Define VFP11 instruction pipes.
     (bfd_arm_vfp11_regno): Recode a register number from a VFP11 insn.
     (bfd_arm_vfp11_write_mask): Update write mask according to coded
     register number.
     (bfd_arm_vfp11_antidependency): New function.
     (bfd_arm_vfp11_insn_decode): Decode a VFP11 insn.
     (bfd_elf32_arm_vfp11_erratum_scan): Scan the sections of an input
     BFD for potential erratum-triggering insns. Record results.
     (bfd_elf32_arm_vfp11_fix_veneer_locations): Find out where veneers
     and branches to veneers have been placed in virtual memory after
     layout.
     (bfd_elf32_arm_set_target_relocs): Set vfp11_fix field in global
     hash table.
     (elf32_arm_output_symbol_hook): Remove.
     (elf32_arm_write_section): Output veneers, and branches to veneers.
     Use maps from input sections, not output sections, for code
     byte-swapping.
     * elf32-ppc.c (ppc_elf_write_section): Add dummy link_info argument.
     * elf32-score.c (_bfd_score_elf_write_section): Likewise.
     * elfxx-mips.c (_bfd_mips_elf_write_section): Likewise.
     * elfxx-mips.h (_bfd_mips_elf_write_section): Likewise.

     ld/
     * emulparams/armelf_linux.sh (OTHER_TEXT_SECTIONS): Add
     .vfp11_veneer section.
     * emulparams/armelf.sh (OTHER_TEXT_SECTIONS): Likewise.
     * emultempl/armelf.em (vfp11_denorm_fix): New static variable.
     (arm_elf_before_allocation): Call bfd_elf32_arm_set_vfp11_fix,
     bfd_elf32_arm_init_maps and bfd_elf32_arm_vfp11_erratum_scan.
     (arm_elf_after_allocation): New function. Call
     bfd_elf32_arm_vfp11_fix_veneer_locations for all input statements.
     (arm_elf_create_output_section_statements): Pass vfp11 fix command
     line option to BFD.
     (OPTION_VFP11_DENORM_FIX): New option.
     (PARSE_AND_LIST_LONGOPTS): Handle new option.
     (PARSE_AND_LIST_OPTIONS): Likewise.
     (PARSE_AND_LIST_ARGS_CASES): Likewise.
     (LDEMUL_AFTER_ALLOCATION): Define.
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: mainline-vfp11-erratum-fix-11
URL: <https://sourceware.org/pipermail/binutils/attachments/20061215/2b2893f6/attachment.ksh>


More information about the Binutils mailing list