I think there is something weird going on with BTF_TYPE_ID_LOCAL. A call to bpf_obj_new is getting the "wrong" type as an argument as emitted by clang into the instruction stream. Compiling local_kptr_stash.c from 6.6 selftest with clang-16 and clang-17 yields the following disassembly for the stash_plain function (source is at [1]): 00000000000001b0 <stash_plain>: ... 64: 18 01 00 00 1c 00 00 00 00 00 00 00 00 00 00 00 r1 = 0x1c ll 66: b7 02 00 00 00 00 00 00 r2 = 0x0 67: 85 10 00 00 ff ff ff ff call -0x1 ; bpf_obj_new ... This is looking at local_kptr_stash.bpf.linked3.o specifically, but local_kptr_stash.bpf.o has the same problem. 0x1c being 28. From bpftool we can see that 28 corresponds to a FUNC type which doesn't make much sense to me: [28] FUNC 'unstash_rb_node' type_id=15 linkage=global The source code actually passes struct plain_local to bpf_obj_new, which has type ID 27: [27] STRUCT 'plain_local' size=16 vlen=2 'key' type_id=16 bits_offset=0 'data' type_id=16 bits_offset=64 I'm guessing that this works in practice since the CO-RE relo in ext_infos actually carries the correct local_type_id: CORERelocation(local_type_id, Struct:"node_data"[0], local_id=18) CORERelocation(local_type_id, Struct:"node_data"[0], local_id=18) CORERelocation(local_type_id, Struct:"plain_local"[0], local_id=27) 1: https://elixir.bootlin.com/linux/v6.6/source/tools/testing/selftests/bpf/progs/local_kptr_stash.c#L76