| Elliott Hughes | c212545 | 2017-11-27 13:42:41 -0800 | [diff] [blame] | 1 | # Clang Migration Notes |
| 2 | |
| Dan Albert | a08131f | 2021-06-16 14:40:29 -0700 | [diff] [blame] | 3 | NDK r17 was the last version to include GCC. If you're upgrading from an old NDK |
| 4 | and need to migrate to Clang, this doc can help. |
| Elliott Hughes | c212545 | 2017-11-27 13:42:41 -0800 | [diff] [blame] | 5 | |
| Dan Albert | a08131f | 2021-06-16 14:40:29 -0700 | [diff] [blame] | 6 | If you maintain a custom build system, see the [Build System Maintainers] |
| 7 | documentation. |
| Elliott Hughes | c212545 | 2017-11-27 13:42:41 -0800 | [diff] [blame] | 8 | |
| Dan Albert | a08131f | 2021-06-16 14:40:29 -0700 | [diff] [blame] | 9 | [Build System Maintainers]: ./BuildSystemMaintainers.md |
| Elliott Hughes | c212545 | 2017-11-27 13:42:41 -0800 | [diff] [blame] | 10 | |
| Elliott Hughes | 2a011a0 | 2021-05-18 16:44:36 -0700 | [diff] [blame] | 11 | ## `-Oz` versus `-Os` |
| Elliott Hughes | ac24478 | 2017-08-31 08:58:13 -0700 | [diff] [blame] | 12 | |
| 13 | [Clang Optimization Flags](https://clang.llvm.org/docs/CommandGuide/clang.html#code-generation-options) |
| 14 | has the full details, but if you used `-Os` to optimize your |
| 15 | code for size with GCC, you probably want `-Oz` when using |
| 16 | Clang. Although `-Os` attempts to make code small, it still |
| 17 | enables some optimizations that will increase code size (based on |
| 18 | https://stackoverflow.com/a/15548189/632035). For the smallest possible |
| 19 | code with Clang, prefer `-Oz`. With `-Oz`, Chromium actually saw both |
| 20 | size *and* performance improvements when moving to Clang compared to |
| 21 | `-Os` with GCC. |
| 22 | |
| Elliott Hughes | 2a011a0 | 2021-05-18 16:44:36 -0700 | [diff] [blame] | 23 | ## `__attribute__((__aligned__))` |
| Elliott Hughes | ac24478 | 2017-08-31 08:58:13 -0700 | [diff] [blame] | 24 | |
| 25 | Normally the `__aligned__` attribute is given an explicit alignment, |
| 26 | but with no value means “maximum alignment”. The interpretation of |
| 27 | “maximum” differs between GCC and Clang: Clang includes vector types |
| 28 | too so for ARM GCC thinks the maximum alignment is 8 (for `uint64_t`), but |
| 29 | Clang thinks it’s 16 (because there are NEON instructions that require |
| 30 | 16-byte alignment). Normally this shouldn’t matter because malloc is |
| 31 | always at least 16-byte aligned, and mmap regions are page (4096-byte) |
| 32 | aligned. Most code should either specify an explicit alignment or use |
| 33 | [alignas](http://en.cppreference.com/w/cpp/language/alignas) instead. |
| 34 | |
| Elliott Hughes | 2a011a0 | 2021-05-18 16:44:36 -0700 | [diff] [blame] | 35 | ## `-Bsymbolic` |
| Elliott Hughes | ac24478 | 2017-08-31 08:58:13 -0700 | [diff] [blame] | 36 | |
| 37 | When targeting Android (but no other platform), GCC passed |
| 38 | [-Bsymbolic](ftp://ftp.gnu.org/old-gnu/Manuals/ld-2.9.1/html_node/ld_3.html) |
| 39 | to the linker by default. This is not a good default, so Clang does not |
| 40 | do that. `-Bsymbolic` causes the following behavior change: |
| 41 | |
| 42 | ```c++ |
| 43 | // foo.cpp |
| 44 | #include <iostream> |
| 45 | |
| 46 | void foo() { |
| 47 | std::cout << "Goodbye, world" << std::endl; |
| 48 | } |
| 49 | |
| 50 | void bar() { |
| 51 | foo(); |
| 52 | } |
| 53 | ``` |
| 54 | |
| 55 | ```c++ |
| 56 | // main.cpp |
| 57 | #include <iostream> |
| 58 | |
| 59 | extern void bar(); |
| 60 | |
| 61 | void foo() { |
| 62 | std::cout << "Hello, world\n"; |
| 63 | } |
| 64 | |
| 65 | int main(int, char**) { |
| 66 | foo(); // Prints “Hello, world!” |
| 67 | bar(); // Without -Bsymbolic, prints “Hello, world!” With -Bsymbolic, prints “Goodbye, world!” |
| 68 | } |
| 69 | ``` |
| 70 | |
| 71 | In addition to not being the "expected" default behavior on all other |
| 72 | platforms, this prevents symbol interposition (used by tools such |
| 73 | as asan). |
| 74 | |
| 75 | You might however wish to add manually `-Bsymbolic` back because it can |
| 76 | result in smaller ELF files because fewer relocations are needed. If you |
| 77 | do want the non-`-Bsymbolic` behavior but would like fewer relocations, |
| 78 | that can be achieved via `-fvisibility=hidden` (and manually exporting |
| 79 | the symbols you want to be public, using the `JNI_EXPORT` macro in JNI |
| 80 | code or `__attribute__ ((visibility("default")))` otherwise. Linker |
| 81 | version scripts are an even more powerful mechanism for controlling |
| 82 | exported symbols, but harder to use. |
| 83 | |
| Elliott Hughes | 2a011a0 | 2021-05-18 16:44:36 -0700 | [diff] [blame] | 84 | ## Assembler issues |
| Elliott Hughes | ac24478 | 2017-08-31 08:58:13 -0700 | [diff] [blame] | 85 | |
| Elliott Hughes | 2a011a0 | 2021-05-18 16:44:36 -0700 | [diff] [blame] | 86 | For many years the problem of adjusting inline assembler to work with |
| 87 | LLVM could be punted down the road by using `-fno-integrated-as` to fall |
| 88 | back to the GNU Assembler (GAS). With the removal of GNU binutils from |
| 89 | the NDK, such issues will now need to be addressed. We’ve collected |
| 90 | some of the most common issues and their solutions/workarounds here. |
| 91 | |
| 92 | ### `.arch` or `.arch_extension` scope with `__asm__` |
| 93 | GAS doesn’t scope `.arch` or `.arch_extension`, so you can have a global |
| 94 | `__asm__(".arch foo")` that applies to the whole C/C++ source file, |
| 95 | just like a bare `.arch` or `.arch_extension` directive would in a .S |
| 96 | file. LLVM scopes these to the specific `__asm__` in which it occurs, |
| 97 | so you’ll need to adapt your inline assembler, or build the whole file |
| 98 | for the relevant arch variant. |
| 99 | |
| 100 | ### ARM `ADRL` |
| 101 | GAS lets you use the `ADRL` pseudoinstruction to get the address of |
| 102 | something too far away for a regular `ADR` to reference. This means |
| 103 | that it expands to two instructions, which LLVM doesn’t support, |
| 104 | so you’ll need to use a macro something like this instead: |
| 105 | ``` |
| 106 | .macro ADRL reg:req, label:req |
| 107 | add \reg, pc, #((\label - .L_adrl_\@) & 0xff00) |
| 108 | add \reg, \reg, #((\label - .L_adrl_\@) - ((\label - .L_adrl_\@) & 0xff00)) |
| 109 | .L_adrl_\@: |
| 110 | .endm |
| 111 | ``` |
| 112 | |
| 113 | ### ARM assembler syntactical strictness |
| 114 | While GAS supports the older divided and newer unified syntax (selectable |
| 115 | via `.syntax unified` and `.syntax divided`), LLVM only supports the |
| 116 | newer unified syntax. |
| 117 | |
| 118 | As an example of where this matters, `LDR` has an optional type and the |
| 119 | optional condition code allowed on all instructions. GAS allows these |
| 120 | to come in either order when using divided syntax, but LLVM only allows |
| 121 | them in the canonical order given in the ARM instruction reference (which |
| 122 | is what “unified” syntax means). So continuing this example, GAS |
| 123 | accepts both `LDRBEQ` and `LDREQB`, but LLVM only accepts `LDRBEQ` (with |
| 124 | the condition code at the end, as the instruction appears in the manual). |
| 125 | |
| 126 | Most humans usually use this order anyway, but you’ll have to rearrange |
| 127 | any instructions that don’t use the canonical order. |
| 128 | |
| 129 | ### ARM assembler implicit operands |
| 130 | Some ARM instructions have restrictions that make some operands |
| 131 | implicit. For example, the two target registers supplied to `LDREXD` |
| 132 | must be consecutive. GAS would allow you to write `LDREXD R1, [R4]` |
| 133 | because the other register _must_ be `R2`, but LLVM requires both |
| 134 | registers to be explicitly stated, in this case `LDREXD R1, R2, [R4]`. |
| 135 | |
| 136 | ### ARM `.arm` or `.code 32` alignment |
| 137 | Switching from Thumb to ARM mode implicitly forces 4-byte alignment |
| 138 | with GAS but doesn’t with LLVM. You may need to use an explicit |
| 139 | `.align`/`.balign`/`.p2align` directive in such cases. |
| 140 | |
| 141 | ### No `--defsym` command-line option |
| 142 | GAS and LLVM implement their own conditional assembly mechanism with |
| 143 | `.if`...`.endif` rather than the C preprocessor’s `#if`...`#endif`. The |
| 144 | equivalent of `-DA=B` for `.if` is `-Wa,-defsym,A=B`, but GAS allowed |
| 145 | `--defsym` instead of `-defsym`. LLVM requires `-defsym`. |
| 146 | |
| 147 | You might also prefer to just use the C preprocessor. If your assembly |
| 148 | is in a .S file it is already being preprocessed. If your assembly |
| 149 | is in a file with any other extension (including `.s` --- this is the |
| 150 | difference between `.s` and `.S`), you’ll need to either rename it to |
| 151 | `.S` or use the `-x assembler-with-cpp` flag to the compiler to override |
| 152 | the file extension-based guess. |
| 153 | |
| 154 | ### No `.func`/`.endfunc` |
| 155 | GAS ignores a request for obsolete STABS debugging information to be |
| 156 | emitted using `.func` and `.endfunc`. Neither GAS nor LLVM actually |
| 157 | support STABS, but LLVM rejects these meaningless directives. The fix |
| 158 | is simply to remove them. |