Albert ARIBAUD | d6d4ec8 | 2012-10-09 09:28:15 +0000 | [diff] [blame] | 1 | If you are reading this because of a data abort: the following MIGHT |
| 2 | be relevant to your abort, if it was caused by an alignment violation. |
| 3 | In order to determine this, use the PC from the abort dump along with |
| 4 | an objdump -s -S of the u-boot ELF binary to locate the function where |
| 5 | the abort happened; then compare this function with the examples below. |
| 6 | If they match, then you've been hit with a compiler generated unaligned |
| 7 | access, and you should rewrite your code or add -mno-unaligned-access |
| 8 | to the command line of the offending file. |
| 9 | |
| 10 | Note that the PC shown in the abort message is relocated. In order to |
| 11 | be able to match it to an address in the ELF binary dump, you will need |
| 12 | to know the relocation offset. If your target defines CONFIG_CMD_BDI |
| 13 | and if you can get to the prompt and enter commands before the abort |
| 14 | happens, then command "bdinfo" will give you the offset. Otherwise you |
| 15 | will need to try a build with DEBUG set, which will display the offset, |
| 16 | or use a debugger and set a breakpoint at relocate_code() to see the |
| 17 | offset (passed as an argument). |
| 18 | |
| 19 | * |
| 20 | |
| 21 | Since U-Boot runs on a variety of hardware, some only able to perform |
| 22 | unaligned accesses with a strong penalty, some unable to perform them |
| 23 | at all, the policy regarding unaligned accesses is to not perform any, |
| 24 | unless absolutely necessary because of hardware or standards. |
| 25 | |
| 26 | Also, on hardware which permits it, the core is configured to throw |
| 27 | data abort exceptions on unaligned accesses in order to catch these |
| 28 | unallowed accesses as early as possible. |
| 29 | |
| 30 | Until version 4.7, the gcc default for performing unaligned accesses |
| 31 | (-mno-unaligned-access) is to emulate unaligned accesses using aligned |
| 32 | loads and stores plus shifts and masks. Emulated unaligned accesses |
| 33 | will not be caught by hardware. These accesses may be costly and may |
| 34 | be actually unnecessary. In order to catch these accesses and remove |
| 35 | or optimize them, option -munaligned-access is explicitly set for all |
| 36 | versions of gcc which support it. |
| 37 | |
| 38 | From gcc 4.7 onward starting at armv7 architectures, the default for |
| 39 | performing unaligned accesses is to use unaligned native loads and |
| 40 | stores (-munaligned-access), because the cost of unaligned accesses |
| 41 | has dropped on armv7 and beyond. This should not affect U-Boot's |
| 42 | policy of controlling unaligned accesses, however the compiler may |
| 43 | generate uncontrolled unaligned accesses on its own in at least one |
| 44 | known case: when declaring a local initialized char array, e.g. |
| 45 | |
| 46 | function foo() |
| 47 | { |
| 48 | char buffer[] = "initial value"; |
| 49 | /* or */ |
| 50 | char buffer[] = { 'i', 'n', 'i', 't', 0 }; |
| 51 | ... |
| 52 | } |
| 53 | |
| 54 | Under -munaligned-accesses with optimizations on, this declaration |
| 55 | causes the compiler to generate native loads from the literal string |
| 56 | and native stores to the buffer, and the literal string alignment |
| 57 | cannot be controlled. If it is misaligned, then the core will throw |
| 58 | a data abort exception. |
| 59 | |
| 60 | Quite probably the same might happen for 16-bit array initializations |
| 61 | where the constant is aligned on a boundary which is a multiple of 2 |
| 62 | but not of 4: |
| 63 | |
| 64 | function foo() |
| 65 | { |
| 66 | u16 buffer[] = { 1, 2, 3 }; |
| 67 | ... |
| 68 | } |
| 69 | |
| 70 | The long term solution to this issue is to add an option to gcc to |
| 71 | allow controlling the general alignment of data, including constant |
| 72 | initialization values. |
| 73 | |
| 74 | However this will only apply to the version of gcc which will have such |
| 75 | an option. For other versions, there are four workarounds: |
| 76 | |
| 77 | a) Enforce as a rule that array initializations as described above |
| 78 | are forbidden. This is generally not acceptable as they are valid, |
| 79 | and usual, C constructs. The only case where they could be rejected |
| 80 | is when they actually equate to a const char* declaration, i.e. the |
| 81 | array is initialized and never modified in the function's scope. |
| 82 | |
| 83 | b) Drop the requirement on unaligned accesses at least for ARMv7, |
| 84 | i.e. do not throw a data abort exception upon unaligned accesses. |
| 85 | But that will allow adding badly aligned code to U-Boot, only for |
| 86 | it to fail when re-used with a stricter target, possibly once the |
| 87 | bad code is already in mainline. |
| 88 | |
| 89 | c) Relax the -munaligned-access rule globally. This will prevent native |
| 90 | unaligned accesses of course, but that will also hide any bug caused |
| 91 | by a bad unaligned access, making it much harder to diagnose it. It |
| 92 | is actually what already happens when building ARM targets with a |
| 93 | pre-4.7 gcc, and it may actually already hide some bugs yet unseen |
| 94 | until the target gets compiled with -munaligned-access. |
| 95 | |
| 96 | d) Relax the -munaligned-access rule only for for files susceptible to |
| 97 | the local initialized array issue and for armv7 architectures and |
| 98 | beyond. This minimizes the quantity of code which can hide unwanted |
| 99 | misaligned accesses. |
| 100 | |
| 101 | The option retained is d). |
| 102 | |
| 103 | Considering that actual occurrences of the issue are rare (as of this |
| 104 | writing, 5 files out of 7840 in U-Boot, or .3%, contain an initialized |
| 105 | local char array which cannot actually be replaced with a const char*), |
| 106 | contributors should not be required to systematically try and detect |
| 107 | the issue in their patches. |
| 108 | |
| 109 | Detecting files susceptible to the issue can be automated through a |
| 110 | filter installed as a hook in .git which recognizes local char array |
| 111 | initializations. Automation should err on the false positive side, for |
| 112 | instance flagging non-local arrays as if they were local if they cannot |
| 113 | be told apart. |
| 114 | |
| 115 | In any case, detection shall not prevent committing the patch, but |
| 116 | shall pre-populate the commit message with a note to the effect that |
| 117 | this patch contains an initialized local char or 16-bit array and thus |
| 118 | should be protected from the gcc 4.7 issue. |
| 119 | |
| 120 | Upon a positive detection, either $(PLATFORM_NO_UNALIGNED) should be |
| 121 | added to CFLAGS for the affected file(s), or if the array is a pseudo |
| 122 | const char*, it should be replaced by an actual one. |