@@ -240,3 +240,307 @@ The .BTF/.BTF.ext sections has R_BPF_64_NODYLD32 relocations::
240240 Offset Info Type Symbol's Value Symbol's Name
241241 000000000000002c 0000000200000004 R_BPF_64_NODYLD32 0000000000000000 .text
242242 0000000000000040 0000000200000004 R_BPF_64_NODYLD32 0000000000000000 .text
243+
244+ .. _btf-co-re-relocations :
245+
246+ =================
247+ CO-RE Relocations
248+ =================
249+
250+ From object file point of view CO-RE mechanism is implemented as a set
251+ of CO-RE specific relocation records. These relocation records are not
252+ related to ELF relocations and are encoded in .BTF.ext section.
253+ See :ref: `Documentation/bpf/btf <BTF_Ext_Section >` for more
254+ information on .BTF.ext structure.
255+
256+ CO-RE relocations are applied to BPF instructions to update immediate
257+ or offset fields of the instruction at load time with information
258+ relevant for target kernel.
259+
260+ Field to patch is selected basing on the instruction class:
261+
262+ * For BPF_ALU, BPF_ALU64, BPF_LD `immediate ` field is patched;
263+ * For BPF_LDX, BPF_STX, BPF_ST `offset ` field is patched;
264+ * BPF_JMP, BPF_JMP32 instructions **should not ** be patched.
265+
266+ Relocation kinds
267+ ================
268+
269+ There are several kinds of CO-RE relocations that could be split in
270+ three groups:
271+
272+ * Field-based - patch instruction with field related information, e.g.
273+ change offset field of the BPF_LDX instruction to reflect offset
274+ of a specific structure field in the target kernel.
275+
276+ * Type-based - patch instruction with type related information, e.g.
277+ change immediate field of the BPF_ALU move instruction to 0 or 1 to
278+ reflect if specific type is present in the target kernel.
279+
280+ * Enum-based - patch instruction with enum related information, e.g.
281+ change immediate field of the BPF_LD_IMM64 instruction to reflect
282+ value of a specific enum literal in the target kernel.
283+
284+ The complete list of relocation kinds is represented by the following enum:
285+
286+ .. code-block :: c
287+
288+ enum bpf_core_relo_kind {
289+ BPF_CORE_FIELD_BYTE_OFFSET = 0, /* field byte offset */
290+ BPF_CORE_FIELD_BYTE_SIZE = 1, /* field size in bytes */
291+ BPF_CORE_FIELD_EXISTS = 2, /* field existence in target kernel */
292+ BPF_CORE_FIELD_SIGNED = 3, /* field signedness (0 - unsigned, 1 - signed) */
293+ BPF_CORE_FIELD_LSHIFT_U64 = 4, /* bitfield-specific left bitshift */
294+ BPF_CORE_FIELD_RSHIFT_U64 = 5, /* bitfield-specific right bitshift */
295+ BPF_CORE_TYPE_ID_LOCAL = 6, /* type ID in local BPF object */
296+ BPF_CORE_TYPE_ID_TARGET = 7, /* type ID in target kernel */
297+ BPF_CORE_TYPE_EXISTS = 8, /* type existence in target kernel */
298+ BPF_CORE_TYPE_SIZE = 9, /* type size in bytes */
299+ BPF_CORE_ENUMVAL_EXISTS = 10, /* enum value existence in target kernel */
300+ BPF_CORE_ENUMVAL_VALUE = 11, /* enum value integer value */
301+ BPF_CORE_TYPE_MATCHES = 12, /* type match in target kernel */
302+ };
303+
304+ Notes:
305+
306+ * ``BPF_CORE_FIELD_LSHIFT_U64 `` and ``BPF_CORE_FIELD_RSHIFT_U64 `` are
307+ supposed to be used to read bitfield values using the following
308+ algorithm:
309+
310+ .. code-block :: c
311+
312+ // To read bitfield ``f`` from ``struct s``
313+ is_signed = relo(s->f, BPF_CORE_FIELD_SIGNED)
314+ off = relo(s->f, BPF_CORE_FIELD_BYTE_OFFSET)
315+ sz = relo(s->f, BPF_CORE_FIELD_BYTE_SIZE)
316+ l = relo(s->f, BPF_CORE_FIELD_LSHIFT_U64)
317+ r = relo(s->f, BPF_CORE_FIELD_RSHIFT_U64)
318+ // define ``v`` as signed or unsigned integer of size ``sz``
319+ v = *({s|u}<sz> *)((void *)s + off)
320+ v <<= l
321+ v >>= r
322+
323+ * The ``BPF_CORE_TYPE_MATCHES `` queries matching relation, defined as
324+ follows:
325+
326+ * for integers: types match if size and signedness match;
327+ * for arrays & pointers: target types are recursively matched;
328+ * for structs & unions:
329+
330+ * local members need to exist in target with the same name;
331+
332+ * for each member we recursively check match unless it is already behind a
333+ pointer, in which case we only check matching names and compatible kind;
334+
335+ * for enums:
336+
337+ * local variants have to have a match in target by symbolic name (but not
338+ numeric value);
339+
340+ * size has to match (but enum may match enum64 and vice versa);
341+
342+ * for function pointers:
343+
344+ * number and position of arguments in local type has to match target;
345+ * for each argument and the return value we recursively check match.
346+
347+ CO-RE Relocation Record
348+ =======================
349+
350+ Relocation record is encoded as the following structure:
351+
352+ .. code-block :: c
353+
354+ struct bpf_core_relo {
355+ __u32 insn_off;
356+ __u32 type_id;
357+ __u32 access_str_off;
358+ enum bpf_core_relo_kind kind;
359+ };
360+
361+ * ``insn_off `` - instruction offset (in bytes) within a code section
362+ associated with this relocation;
363+
364+ * ``type_id `` - BTF type ID of the "root" (containing) entity of a
365+ relocatable type or field;
366+
367+ * ``access_str_off `` - offset into corresponding .BTF string section.
368+ String interpretation depends on specific relocation kind:
369+
370+ * for field-based relocations, string encodes an accessed field using
371+ a sequence of field and array indices, separated by colon (:). It's
372+ conceptually very close to LLVM's `getelementptr <GEP _>`_ instruction's
373+ arguments for identifying offset to a field. For example, consider the
374+ following C code:
375+
376+ .. code-block :: c
377+
378+ struct sample {
379+ int a;
380+ int b;
381+ struct { int c[10]; };
382+ } __attribute__((preserve_access_index));
383+ struct sample *s;
384+
385+ * Access to ``s[0].a `` would be encoded as ``0:0 ``:
386+
387+ * ``0 ``: first element of ``s `` (as if ``s `` is an array);
388+ * ``0 ``: index of field ``a `` in ``struct sample ``.
389+
390+ * Access to ``s->a `` would be encoded as ``0:0 `` as well.
391+ * Access to ``s->b `` would be encoded as ``0:1 ``:
392+
393+ * ``0 ``: first element of ``s ``;
394+ * ``1 ``: index of field ``b `` in ``struct sample ``.
395+
396+ * Access to ``s[1].c[5] `` would be encoded as ``1:2:0:5 ``:
397+
398+ * ``1 ``: second element of ``s ``;
399+ * ``2 ``: index of anonymous structure field in ``struct sample ``;
400+ * ``0 ``: index of field ``c `` in anonymous structure;
401+ * ``5 ``: access to array element #5.
402+
403+ * for type-based relocations, string is expected to be just "0";
404+
405+ * for enum value-based relocations, string contains an index of enum
406+ value within its enum type;
407+
408+ * ``kind `` - one of ``enum bpf_core_relo_kind ``.
409+
410+ .. _GEP : https://llvm.org/docs/LangRef.html#getelementptr-instruction
411+
412+ .. _btf_co_re_relocation_examples :
413+
414+ CO-RE Relocation Examples
415+ =========================
416+
417+ For the following C code:
418+
419+ .. code-block :: c
420+
421+ struct foo {
422+ int a;
423+ int b;
424+ unsigned c:15;
425+ } __attribute__((preserve_access_index));
426+
427+ enum bar { U, V };
428+
429+ With the following BTF definitions:
430+
431+ .. code-block ::
432+
433+ ...
434+ [2] STRUCT 'foo' size=8 vlen=2
435+ 'a' type_id=3 bits_offset=0
436+ 'b' type_id=3 bits_offset=32
437+ 'c' type_id=4 bits_offset=64 bitfield_size=15
438+ [3] INT 'int' size=4 bits_offset=0 nr_bits=32 encoding=SIGNED
439+ [4] INT 'unsigned int' size=4 bits_offset=0 nr_bits=32 encoding=(none)
440+ ...
441+ [16] ENUM 'bar' encoding=UNSIGNED size=4 vlen=2
442+ 'U' val=0
443+ 'V' val=1
444+
445+ Field offset relocations are generated automatically when
446+ ``__attribute__((preserve_access_index)) `` is used, for example:
447+
448+ .. code-block :: c
449+
450+ void alpha(struct foo *s, volatile unsigned long *g) {
451+ *g = s->a;
452+ s->a = 1;
453+ }
454+
455+ 00 <alpha>:
456+ 0: r3 = *(s32 *)(r1 + 0x0)
457+ 00: CO-RE <byte_off> [2] struct foo::a (0:0)
458+ 1: *(u64 *)(r2 + 0x0) = r3
459+ 2: *(u32 *)(r1 + 0x0) = 0x1
460+ 10: CO-RE <byte_off> [2] struct foo::a (0:0)
461+ 3: exit
462+
463+
464+ All relocation kinds could be requested via built-in functions.
465+ E.g. field-based relocations:
466+
467+ .. code-block :: c
468+
469+ void bravo(struct foo *s, volatile unsigned long *g) {
470+ *g = __builtin_preserve_field_info(s->b, 0 /* field byte offset */);
471+ *g = __builtin_preserve_field_info(s->b, 1 /* field byte size */);
472+ *g = __builtin_preserve_field_info(s->b, 2 /* field existence */);
473+ *g = __builtin_preserve_field_info(s->b, 3 /* field signedness */);
474+ *g = __builtin_preserve_field_info(s->c, 4 /* bitfield left shift */);
475+ *g = __builtin_preserve_field_info(s->c, 5 /* bitfield right shift */);
476+ }
477+
478+ 20 <bravo>:
479+ 4: r1 = 0x4
480+ 20: CO-RE <byte_off> [2] struct foo::b (0:1)
481+ 5: *(u64 *)(r2 + 0x0) = r1
482+ 6: r1 = 0x4
483+ 30: CO-RE <byte_sz> [2] struct foo::b (0:1)
484+ 7: *(u64 *)(r2 + 0x0) = r1
485+ 8: r1 = 0x1
486+ 40: CO-RE <field_exists> [2] struct foo::b (0:1)
487+ 9: *(u64 *)(r2 + 0x0) = r1
488+ 10: r1 = 0x1
489+ 50: CO-RE <signed> [2] struct foo::b (0:1)
490+ 11: *(u64 *)(r2 + 0x0) = r1
491+ 12: r1 = 0x31
492+ 60: CO-RE <lshift_u64> [2] struct foo::c (0:2)
493+ 13: *(u64 *)(r2 + 0x0) = r1
494+ 14: r1 = 0x31
495+ 70: CO-RE <rshift_u64> [2] struct foo::c (0:2)
496+ 15: *(u64 *)(r2 + 0x0) = r1
497+ 16: exit
498+
499+
500+ Type-based relocations:
501+
502+ .. code-block :: c
503+
504+ void charlie(struct foo *s, volatile unsigned long *g) {
505+ *g = __builtin_preserve_type_info(*s, 0 /* type existence */);
506+ *g = __builtin_preserve_type_info(*s, 1 /* type size */);
507+ *g = __builtin_preserve_type_info(*s, 2 /* type matches */);
508+ *g = __builtin_btf_type_id(*s, 0 /* type id in this object file */);
509+ *g = __builtin_btf_type_id(*s, 1 /* type id in target kernel */);
510+ }
511+
512+ 88 <charlie>:
513+ 17: r1 = 0x1
514+ 88: CO-RE <type_exists> [2] struct foo
515+ 18: *(u64 *)(r2 + 0x0) = r1
516+ 19: r1 = 0xc
517+ 98: CO-RE <type_size> [2] struct foo
518+ 20: *(u64 *)(r2 + 0x0) = r1
519+ 21: r1 = 0x1
520+ a8: CO-RE <type_matches> [2] struct foo
521+ 22: *(u64 *)(r2 + 0x0) = r1
522+ 23: r1 = 0x2 ll
523+ b8: CO-RE <local_type_id> [2] struct foo
524+ 25: *(u64 *)(r2 + 0x0) = r1
525+ 26: r1 = 0x2 ll
526+ d0: CO-RE <target_type_id> [2] struct foo
527+ 28: *(u64 *)(r2 + 0x0) = r1
528+ 29: exit
529+
530+ Enum-based relocations:
531+
532+ .. code-block :: c
533+
534+ void delta(struct foo *s, volatile unsigned long *g) {
535+ *g = __builtin_preserve_enum_value(*(enum bar *)U, 0 /* enum literal existence */);
536+ *g = __builtin_preserve_enum_value(*(enum bar *)V, 1 /* enum literal value */);
537+ }
538+
539+ f0 <delta>:
540+ 30: r1 = 0x1 ll
541+ f0: CO-RE <enumval_exists> [16] enum bar::U = 0
542+ 32: *(u64 *)(r2 + 0x0) = r1
543+ 33: r1 = 0x1 ll
544+ 108: CO-RE <enumval_value> [16] enum bar::V = 1
545+ 35: *(u64 *)(r2 + 0x0) = r1
546+ 36: exit
0 commit comments