Yonghong Song | fc8c262 | 2021-05-26 08:24:57 -0700 | [diff] [blame] | 1 | .. SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) |
| 2 | |
| 3 | ==================== |
| 4 | BPF LLVM Relocations |
| 5 | ==================== |
| 6 | |
| 7 | This document describes LLVM BPF backend relocation types. |
| 8 | |
| 9 | Relocation Record |
| 10 | ================= |
| 11 | |
| 12 | LLVM BPF backend records each relocation with the following 16-byte |
| 13 | ELF structure:: |
| 14 | |
| 15 | typedef struct |
| 16 | { |
| 17 | Elf64_Addr r_offset; // Offset from the beginning of section. |
| 18 | Elf64_Xword r_info; // Relocation type and symbol index. |
| 19 | } Elf64_Rel; |
| 20 | |
| 21 | For example, for the following code:: |
| 22 | |
| 23 | int g1 __attribute__((section("sec"))); |
| 24 | int g2 __attribute__((section("sec"))); |
| 25 | static volatile int l1 __attribute__((section("sec"))); |
| 26 | static volatile int l2 __attribute__((section("sec"))); |
| 27 | int test() { |
| 28 | return g1 + g2 + l1 + l2; |
| 29 | } |
| 30 | |
| 31 | Compiled with ``clang -target bpf -O2 -c test.c``, the following is |
| 32 | the code with ``llvm-objdump -dr test.o``:: |
| 33 | |
| 34 | 0: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll |
| 35 | 0000000000000000: R_BPF_64_64 g1 |
| 36 | 2: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0) |
| 37 | 3: 18 02 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r2 = 0 ll |
| 38 | 0000000000000018: R_BPF_64_64 g2 |
| 39 | 5: 61 20 00 00 00 00 00 00 r0 = *(u32 *)(r2 + 0) |
| 40 | 6: 0f 10 00 00 00 00 00 00 r0 += r1 |
| 41 | 7: 18 01 00 00 08 00 00 00 00 00 00 00 00 00 00 00 r1 = 8 ll |
| 42 | 0000000000000038: R_BPF_64_64 sec |
| 43 | 9: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0) |
| 44 | 10: 0f 10 00 00 00 00 00 00 r0 += r1 |
| 45 | 11: 18 01 00 00 0c 00 00 00 00 00 00 00 00 00 00 00 r1 = 12 ll |
| 46 | 0000000000000058: R_BPF_64_64 sec |
| 47 | 13: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0) |
| 48 | 14: 0f 10 00 00 00 00 00 00 r0 += r1 |
| 49 | 15: 95 00 00 00 00 00 00 00 exit |
| 50 | |
| 51 | There are four relations in the above for four ``LD_imm64`` instructions. |
| 52 | The following ``llvm-readelf -r test.o`` shows the binary values of the four |
| 53 | relocations:: |
| 54 | |
| 55 | Relocation section '.rel.text' at offset 0x190 contains 4 entries: |
| 56 | Offset Info Type Symbol's Value Symbol's Name |
| 57 | 0000000000000000 0000000600000001 R_BPF_64_64 0000000000000000 g1 |
| 58 | 0000000000000018 0000000700000001 R_BPF_64_64 0000000000000004 g2 |
| 59 | 0000000000000038 0000000400000001 R_BPF_64_64 0000000000000000 sec |
| 60 | 0000000000000058 0000000400000001 R_BPF_64_64 0000000000000000 sec |
| 61 | |
| 62 | Each relocation is represented by ``Offset`` (8 bytes) and ``Info`` (8 bytes). |
| 63 | For example, the first relocation corresponds to the first instruction |
| 64 | (Offset 0x0) and the corresponding ``Info`` indicates the relocation type |
| 65 | of ``R_BPF_64_64`` (type 1) and the entry in the symbol table (entry 6). |
| 66 | The following is the symbol table with ``llvm-readelf -s test.o``:: |
| 67 | |
| 68 | Symbol table '.symtab' contains 8 entries: |
| 69 | Num: Value Size Type Bind Vis Ndx Name |
| 70 | 0: 0000000000000000 0 NOTYPE LOCAL DEFAULT UND |
| 71 | 1: 0000000000000000 0 FILE LOCAL DEFAULT ABS test.c |
| 72 | 2: 0000000000000008 4 OBJECT LOCAL DEFAULT 4 l1 |
| 73 | 3: 000000000000000c 4 OBJECT LOCAL DEFAULT 4 l2 |
| 74 | 4: 0000000000000000 0 SECTION LOCAL DEFAULT 4 sec |
| 75 | 5: 0000000000000000 128 FUNC GLOBAL DEFAULT 2 test |
| 76 | 6: 0000000000000000 4 OBJECT GLOBAL DEFAULT 4 g1 |
| 77 | 7: 0000000000000004 4 OBJECT GLOBAL DEFAULT 4 g2 |
| 78 | |
| 79 | The 6th entry is global variable ``g1`` with value 0. |
| 80 | |
| 81 | Similarly, the second relocation is at ``.text`` offset ``0x18``, instruction 3, |
| 82 | for global variable ``g2`` which has a symbol value 4, the offset |
| 83 | from the start of ``.data`` section. |
| 84 | |
| 85 | The third and fourth relocations refers to static variables ``l1`` |
| 86 | and ``l2``. From ``.rel.text`` section above, it is not clear |
| 87 | which symbols they really refers to as they both refers to |
| 88 | symbol table entry 4, symbol ``sec``, which has ``STT_SECTION`` type |
| 89 | and represents a section. So for static variable or function, |
| 90 | the section offset is written to the original insn |
| 91 | buffer, which is called ``A`` (addend). Looking at |
| 92 | above insn ``7`` and ``11``, they have section offset ``8`` and ``12``. |
| 93 | From symbol table, we can find that they correspond to entries ``2`` |
| 94 | and ``3`` for ``l1`` and ``l2``. |
| 95 | |
| 96 | In general, the ``A`` is 0 for global variables and functions, |
| 97 | and is the section offset or some computation result based on |
| 98 | section offset for static variables/functions. The non-section-offset |
| 99 | case refers to function calls. See below for more details. |
| 100 | |
| 101 | Different Relocation Types |
| 102 | ========================== |
| 103 | |
| 104 | Six relocation types are supported. The following is an overview and |
| 105 | ``S`` represents the value of the symbol in the symbol table:: |
| 106 | |
| 107 | Enum ELF Reloc Type Description BitSize Offset Calculation |
| 108 | 0 R_BPF_NONE None |
| 109 | 1 R_BPF_64_64 ld_imm64 insn 32 r_offset + 4 S + A |
| 110 | 2 R_BPF_64_ABS64 normal data 64 r_offset S + A |
| 111 | 3 R_BPF_64_ABS32 normal data 32 r_offset S + A |
| 112 | 4 R_BPF_64_NODYLD32 .BTF[.ext] data 32 r_offset S + A |
| 113 | 10 R_BPF_64_32 call insn 32 r_offset + 4 (S + A) / 8 - 1 |
| 114 | |
| 115 | For example, ``R_BPF_64_64`` relocation type is used for ``ld_imm64`` instruction. |
| 116 | The actual to-be-relocated data (0 or section offset) |
| 117 | is stored at ``r_offset + 4`` and the read/write |
| 118 | data bitsize is 32 (4 bytes). The relocation can be resolved with |
| 119 | the symbol value plus implicit addend. Note that the ``BitSize`` is 32 which |
| 120 | means the section offset must be less than or equal to ``UINT32_MAX`` and this |
| 121 | is enforced by LLVM BPF backend. |
| 122 | |
| 123 | In another case, ``R_BPF_64_ABS64`` relocation type is used for normal 64-bit data. |
| 124 | The actual to-be-relocated data is stored at ``r_offset`` and the read/write data |
| 125 | bitsize is 64 (8 bytes). The relocation can be resolved with |
| 126 | the symbol value plus implicit addend. |
| 127 | |
| 128 | Both ``R_BPF_64_ABS32`` and ``R_BPF_64_NODYLD32`` types are for 32-bit data. |
| 129 | But ``R_BPF_64_NODYLD32`` specifically refers to relocations in ``.BTF`` and |
| 130 | ``.BTF.ext`` sections. For cases like bcc where llvm ``ExecutionEngine RuntimeDyld`` |
| 131 | is involved, ``R_BPF_64_NODYLD32`` types of relocations should not be resolved |
| 132 | to actual function/variable address. Otherwise, ``.BTF`` and ``.BTF.ext`` |
| 133 | become unusable by bcc and kernel. |
| 134 | |
| 135 | Type ``R_BPF_64_32`` is used for call instruction. The call target section |
| 136 | offset is stored at ``r_offset + 4`` (32bit) and calculated as |
| 137 | ``(S + A) / 8 - 1``. |
| 138 | |
| 139 | Examples |
| 140 | ======== |
| 141 | |
| 142 | Types ``R_BPF_64_64`` and ``R_BPF_64_32`` are used to resolve ``ld_imm64`` |
| 143 | and ``call`` instructions. For example:: |
| 144 | |
| 145 | __attribute__((noinline)) __attribute__((section("sec1"))) |
| 146 | int gfunc(int a, int b) { |
| 147 | return a * b; |
| 148 | } |
| 149 | static __attribute__((noinline)) __attribute__((section("sec1"))) |
| 150 | int lfunc(int a, int b) { |
| 151 | return a + b; |
| 152 | } |
| 153 | int global __attribute__((section("sec2"))); |
| 154 | int test(int a, int b) { |
| 155 | return gfunc(a, b) + lfunc(a, b) + global; |
| 156 | } |
| 157 | |
| 158 | Compiled with ``clang -target bpf -O2 -c test.c``, we will have |
| 159 | following code with `llvm-objdump -dr test.o``:: |
| 160 | |
| 161 | Disassembly of section .text: |
| 162 | |
| 163 | 0000000000000000 <test>: |
| 164 | 0: bf 26 00 00 00 00 00 00 r6 = r2 |
| 165 | 1: bf 17 00 00 00 00 00 00 r7 = r1 |
| 166 | 2: 85 10 00 00 ff ff ff ff call -1 |
| 167 | 0000000000000010: R_BPF_64_32 gfunc |
| 168 | 3: bf 08 00 00 00 00 00 00 r8 = r0 |
| 169 | 4: bf 71 00 00 00 00 00 00 r1 = r7 |
| 170 | 5: bf 62 00 00 00 00 00 00 r2 = r6 |
| 171 | 6: 85 10 00 00 02 00 00 00 call 2 |
| 172 | 0000000000000030: R_BPF_64_32 sec1 |
| 173 | 7: 0f 80 00 00 00 00 00 00 r0 += r8 |
| 174 | 8: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll |
| 175 | 0000000000000040: R_BPF_64_64 global |
| 176 | 10: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0) |
| 177 | 11: 0f 10 00 00 00 00 00 00 r0 += r1 |
| 178 | 12: 95 00 00 00 00 00 00 00 exit |
| 179 | |
| 180 | Disassembly of section sec1: |
| 181 | |
| 182 | 0000000000000000 <gfunc>: |
| 183 | 0: bf 20 00 00 00 00 00 00 r0 = r2 |
| 184 | 1: 2f 10 00 00 00 00 00 00 r0 *= r1 |
| 185 | 2: 95 00 00 00 00 00 00 00 exit |
| 186 | |
| 187 | 0000000000000018 <lfunc>: |
| 188 | 3: bf 20 00 00 00 00 00 00 r0 = r2 |
| 189 | 4: 0f 10 00 00 00 00 00 00 r0 += r1 |
| 190 | 5: 95 00 00 00 00 00 00 00 exit |
| 191 | |
| 192 | The first relocation corresponds to ``gfunc(a, b)`` where ``gfunc`` has a value of 0, |
| 193 | so the ``call`` instruction offset is ``(0 + 0)/8 - 1 = -1``. |
| 194 | The second relocation corresponds to ``lfunc(a, b)`` where ``lfunc`` has a section |
| 195 | offset ``0x18``, so the ``call`` instruction offset is ``(0 + 0x18)/8 - 1 = 2``. |
| 196 | The third relocation corresponds to ld_imm64 of ``global``, which has a section |
| 197 | offset ``0``. |
| 198 | |
| 199 | The following is an example to show how R_BPF_64_ABS64 could be generated:: |
| 200 | |
| 201 | int global() { return 0; } |
| 202 | struct t { void *g; } gbl = { global }; |
| 203 | |
| 204 | Compiled with ``clang -target bpf -O2 -g -c test.c``, we will see a |
| 205 | relocation below in ``.data`` section with command |
| 206 | ``llvm-readelf -r test.o``:: |
| 207 | |
| 208 | Relocation section '.rel.data' at offset 0x458 contains 1 entries: |
| 209 | Offset Info Type Symbol's Value Symbol's Name |
| 210 | 0000000000000000 0000000700000002 R_BPF_64_ABS64 0000000000000000 global |
| 211 | |
| 212 | The relocation says the first 8-byte of ``.data`` section should be |
| 213 | filled with address of ``global`` variable. |
| 214 | |
| 215 | With ``llvm-readelf`` output, we can see that dwarf sections have a bunch of |
| 216 | ``R_BPF_64_ABS32`` and ``R_BPF_64_ABS64`` relocations:: |
| 217 | |
| 218 | Relocation section '.rel.debug_info' at offset 0x468 contains 13 entries: |
| 219 | Offset Info Type Symbol's Value Symbol's Name |
| 220 | 0000000000000006 0000000300000003 R_BPF_64_ABS32 0000000000000000 .debug_abbrev |
| 221 | 000000000000000c 0000000400000003 R_BPF_64_ABS32 0000000000000000 .debug_str |
| 222 | 0000000000000012 0000000400000003 R_BPF_64_ABS32 0000000000000000 .debug_str |
| 223 | 0000000000000016 0000000600000003 R_BPF_64_ABS32 0000000000000000 .debug_line |
| 224 | 000000000000001a 0000000400000003 R_BPF_64_ABS32 0000000000000000 .debug_str |
| 225 | 000000000000001e 0000000200000002 R_BPF_64_ABS64 0000000000000000 .text |
| 226 | 000000000000002b 0000000400000003 R_BPF_64_ABS32 0000000000000000 .debug_str |
| 227 | 0000000000000037 0000000800000002 R_BPF_64_ABS64 0000000000000000 gbl |
| 228 | 0000000000000040 0000000400000003 R_BPF_64_ABS32 0000000000000000 .debug_str |
| 229 | ...... |
| 230 | |
| 231 | The .BTF/.BTF.ext sections has R_BPF_64_NODYLD32 relocations:: |
| 232 | |
| 233 | Relocation section '.rel.BTF' at offset 0x538 contains 1 entries: |
| 234 | Offset Info Type Symbol's Value Symbol's Name |
| 235 | 0000000000000084 0000000800000004 R_BPF_64_NODYLD32 0000000000000000 gbl |
| 236 | |
| 237 | Relocation section '.rel.BTF.ext' at offset 0x548 contains 2 entries: |
| 238 | Offset Info Type Symbol's Value Symbol's Name |
| 239 | 000000000000002c 0000000200000004 R_BPF_64_NODYLD32 0000000000000000 .text |
| 240 | 0000000000000040 0000000200000004 R_BPF_64_NODYLD32 0000000000000000 .text |