123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122 |
- If you are reading this because of a data abort: the following MIGHT
- be relevant to your abort, if it was caused by an alignment violation.
- In order to determine this, use the PC from the abort dump along with
- an objdump -s -S of the u-boot ELF binary to locate the function where
- the abort happened; then compare this function with the examples below.
- If they match, then you've been hit with a compiler generated unaligned
- access, and you should rewrite your code or add -mno-unaligned-access
- to the command line of the offending file.
- Note that the PC shown in the abort message is relocated. In order to
- be able to match it to an address in the ELF binary dump, you will need
- to know the relocation offset. If your target defines CONFIG_CMD_BDI
- and if you can get to the prompt and enter commands before the abort
- happens, then command "bdinfo" will give you the offset. Otherwise you
- will need to try a build with DEBUG set, which will display the offset,
- or use a debugger and set a breakpoint at relocate_code() to see the
- offset (passed as an argument).
- *
- Since U-Boot runs on a variety of hardware, some only able to perform
- unaligned accesses with a strong penalty, some unable to perform them
- at all, the policy regarding unaligned accesses is to not perform any,
- unless absolutely necessary because of hardware or standards.
- Also, on hardware which permits it, the core is configured to throw
- data abort exceptions on unaligned accesses in order to catch these
- unallowed accesses as early as possible.
- Until version 4.7, the gcc default for performing unaligned accesses
- (-mno-unaligned-access) is to emulate unaligned accesses using aligned
- loads and stores plus shifts and masks. Emulated unaligned accesses
- will not be caught by hardware. These accesses may be costly and may
- be actually unnecessary. In order to catch these accesses and remove
- or optimize them, option -munaligned-access is explicitly set for all
- versions of gcc which support it.
- From gcc 4.7 onward starting at armv7 architectures, the default for
- performing unaligned accesses is to use unaligned native loads and
- stores (-munaligned-access), because the cost of unaligned accesses
- has dropped on armv7 and beyond. This should not affect U-Boot's
- policy of controlling unaligned accesses, however the compiler may
- generate uncontrolled unaligned accesses on its own in at least one
- known case: when declaring a local initialized char array, e.g.
- function foo()
- {
- char buffer[] = "initial value";
- /* or */
- char buffer[] = { 'i', 'n', 'i', 't', 0 };
- ...
- }
- Under -munaligned-accesses with optimizations on, this declaration
- causes the compiler to generate native loads from the literal string
- and native stores to the buffer, and the literal string alignment
- cannot be controlled. If it is misaligned, then the core will throw
- a data abort exception.
- Quite probably the same might happen for 16-bit array initializations
- where the constant is aligned on a boundary which is a multiple of 2
- but not of 4:
- function foo()
- {
- u16 buffer[] = { 1, 2, 3 };
- ...
- }
- The long term solution to this issue is to add an option to gcc to
- allow controlling the general alignment of data, including constant
- initialization values.
- However this will only apply to the version of gcc which will have such
- an option. For other versions, there are four workarounds:
- a) Enforce as a rule that array initializations as described above
- are forbidden. This is generally not acceptable as they are valid,
- and usual, C constructs. The only case where they could be rejected
- is when they actually equate to a const char* declaration, i.e. the
- array is initialized and never modified in the function's scope.
- b) Drop the requirement on unaligned accesses at least for ARMv7,
- i.e. do not throw a data abort exception upon unaligned accesses.
- But that will allow adding badly aligned code to U-Boot, only for
- it to fail when re-used with a stricter target, possibly once the
- bad code is already in mainline.
- c) Relax the -munaligned-access rule globally. This will prevent native
- unaligned accesses of course, but that will also hide any bug caused
- by a bad unaligned access, making it much harder to diagnose it. It
- is actually what already happens when building ARM targets with a
- pre-4.7 gcc, and it may actually already hide some bugs yet unseen
- until the target gets compiled with -munaligned-access.
- d) Relax the -munaligned-access rule only for for files susceptible to
- the local initialized array issue and for armv7 architectures and
- beyond. This minimizes the quantity of code which can hide unwanted
- misaligned accesses.
- The option retained is d).
- Considering that actual occurrences of the issue are rare (as of this
- writing, 5 files out of 7840 in U-Boot, or .3%, contain an initialized
- local char array which cannot actually be replaced with a const char*),
- contributors should not be required to systematically try and detect
- the issue in their patches.
- Detecting files susceptible to the issue can be automated through a
- filter installed as a hook in .git which recognizes local char array
- initializations. Automation should err on the false positive side, for
- instance flagging non-local arrays as if they were local if they cannot
- be told apart.
- In any case, detection shall not prevent committing the patch, but
- shall pre-populate the commit message with a note to the effect that
- this patch contains an initialized local char or 16-bit array and thus
- should be protected from the gcc 4.7 issue.
- Upon a positive detection, either $(PLATFORM_NO_UNALIGNED) should be
- added to CFLAGS for the affected file(s), or if the array is a pseudo
- const char*, it should be replaced by an actual one.
|