下面是我的代码和libbpf抛出的错误
libbpf: Program 'xdp' contains unrecognized relo data pointing to section 6
ERR: loading BPF-OBJ file(./k.o) (-2): No such file or directory
ERR: loading file: ./k.o为什么会这样呢。我就是这样用bpf_trace_printk打印的
bpf_trace_printk("hello\n",sizeof("hello\n"));这是完整的代码
#include <stddef.h>
#include <linux/bpf.h>
#include <linux/in.h>
#include <linux/if_ether.h>
#include <linux/if_packet.h>
#include <linux/ipv6.h>
#include <linux/icmpv6.h>
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_endian.h>
/* Defines xdp_stats_map from packet04 */
#include "../common/xdp_stats_kern_user.h"
#include "../common/xdp_stats_kern.h"
#include <../common/parsing_helpers.h>
#include <bpf/bpf_helpers.h>
#define ETH_ALEN 6
#define MAX_ENTRIES 1000
/*struct {
__uint(type, BPF_MAP_TYPE_ARRAY_OF_MAPS);
__type(key, __u32);
__type(value, __u64);
__uint(max_entries, MAX_ENTRIES);
} hash_map SEC(".maps");
*/
struct hash_elem {
int cnt;
struct bpf_spin_lock lock;
};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, struct hash_elem);
__uint(max_entries, 100);
} hash_map SEC(".maps");
struct a{struct bpf_spin_lock lock;};
struct {
__uint(type, BPF_MAP_TYPE_HASH);
__type(key, __u32);
__type(value, long);
__uint(max_entries, 2);
} hash_map1 SEC(".maps");
//static __u32 i=0;
struct icmphdr1
{
__u8 type; /* message type */
__u8 code; /* type sub-code */
__u16 checksum;
union
{
struct
{
__u16 id;
__u16 sequence;
} echo; /* echo datagram */
__u32 gateway; /* gateway address */
struct
{
__u16 __glibc_reserved;
__u16 mtu;
} frag; /* path mtu discovery */
} un;
};
SEC("xdp")
int xdp_prog_simple(struct xdp_md *ctx)
{
void *data_end = (void *)(long)ctx->data_end;
void *data = (void *)(long)ctx->data;
struct ethhdr *eth = data;
__u16 h_proto;
if (eth + 1 > data_end)
return XDP_DROP;
h_proto = eth->h_proto;
if (h_proto == bpf_htons(ETH_P_IP))
{
struct iphdr *ip=(struct iphdr *)(eth+sizeof(struct ethhdr));
if(ip+1>data_end)
{
__u8 protocol_ip=ip->protocol;
if(protocol_ip==0x01)
{
struct icmphdr1 *icmp=(struct icmphdr1 *)(ip+sizeof(struct iphdr));
if(icmp+1>data_end)
{
__u8 type=icmp->type;
__u8 code=icmp->code;
if(type!=10 && code!=11)
bpf_trace_printk("hello\n",sizeof("hello\n"));
// if(type==8)
// if(code==0)
// bpf_trace_printk("code is 0\n",sizeof("code is 0\n"));
// bpf_trace_printk("icmp type:code = %d:%d\n",sizeof("icmp type:code = %d:%d\n"),type,code);
}
//__u32 key=i;
//__u64 val=bpf_ktime_get_ns();
//int x=bpf_map_update_elem(&hash_map, &key, &val, BPF_ANY);
}
}
}
return XDP_DROP;
}发布于 2022-08-24 21:26:29
TL;DR
不要这样称呼你的帮手:
// BAD
bpf_trace_printk("hello\n", sizeof("hello\n"));或者像这样:
// BAD
const char *msg = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));但是,将您的字符串声明为一个动态的字符数组:
// GOOD
char msg[] = "hello\n";
bpf_trace_printk(msg, sizeof(msg));这将防止clang创建libbpf无法处理的重新定位。
解释
让我们看看对象文件,当直接传递字符串时:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
bpf_trace_printk("hello\n", sizeof("hello\n"));
return 0;
}执行此操作时,clang将字符串放入只读部分,并请求重新定位。我们可以用llvm-objdump观察到这一点。让我们检查重新定位并拆卸程序:
$ clang -O2 -emit-llvm -c foo.c -o - | llc -march=bpf -filetype=obj -o foo.
$ llvm-objdump -r foo.o
foo.o: file format elf64-bpf
RELOCATION RECORDS FOR [.text]:
OFFSET TYPE VALUE
0000000000000000 R_BPF_64_64 .rodata.str1.1
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
000000000000001c R_BPF_64_ABS64 .text
$ lvm-objdump --section=.text -D foo.o
foo.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo>:
0: 18 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 r1 = 0 ll
2: b7 02 00 00 07 00 00 00 r2 = 7
3: 85 00 00 00 06 00 00 00 call 6
4: b7 00 00 00 00 00 00 00 r0 = 0
5: 95 00 00 00 00 00 00 00 exit我们注意到,包含程序的.text部分以单个load r1 = 0开头:寄存器r1包含传递给调用bpf_trace_printk() (call 6)的第一个参数,直到这种重定位发生时才设置。
但是libbpf不支持这种重定位,这就是您获得错误消息的原因:
Program 'xdp' contains unrecognized relo data pointing to section 6在以下方面也可以看到这一点:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
const char* msg = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
return 0;
}这是等价的,clang也创造了一个重新安置。
但是,我们可以将字符串声明为一个动态的字符数组:
#include <linux/bpf.h>
#include "bpf_helper_defs.h"
int foo(void)
{
char msg[] = "hello\n";
bpf_trace_printk(msg, sizeof("hello\n"));
return 0;
}在这种情况下,数组进入堆栈。不发生搬迁。文件中不存在.rodata.str1.1部分。我们可以检查llvm-objdump说了什么:
$ clang -O2 -emit-llvm -c foo.c -o - | llc -march=bpf -filetype=obj -o foo.o
$ llvm-objdump -r foo.o
foo.o: file format elf64-bpf
RELOCATION RECORDS FOR [.eh_frame]:
OFFSET TYPE VALUE
000000000000001c R_BPF_64_ABS64 .text
$ lvm-objdump --section=.text -D foo.o
foo.o: file format elf64-bpf
Disassembly of section .text:
0000000000000000 <foo>:
0: b7 01 00 00 6f 0a 00 00 r1 = 2671
1: 6b 1a fc ff 00 00 00 00 *(u16 *)(r10 - 4) = r1
2: b7 01 00 00 68 65 6c 6c r1 = 1819043176
3: 63 1a f8 ff 00 00 00 00 *(u32 *)(r10 - 8) = r1
4: b7 01 00 00 00 00 00 00 r1 = 0
5: 73 1a fe ff 00 00 00 00 *(u8 *)(r10 - 2) = r1
6: bf a1 00 00 00 00 00 00 r1 = r10
7: 07 01 00 00 f8 ff ff ff r1 += -8
8: b7 02 00 00 07 00 00 00 r2 = 7
9: 85 00 00 00 06 00 00 00 call 6
10: b7 00 00 00 00 00 00 00 r0 = 0
11: 95 00 00 00 00 00 00 00 exit在这里,我们用字符串的字符填充堆栈(r10是堆栈指针) (68 65 6c 6c 6f 0a 00 00是hello\n\0\0)。每件事都是在BPF处理的,不涉及搬迁。而且这个很好用。
我们能做得更好吗?是的,对于Linux5.2和更高版本,我们可以通过将字符串声明为:
static const char msg[] = "hello\n";这一次,这将导致重新定位到节.rodata,但是libbpf通过对静态变量的支持来处理这个部分。更多详细信息可获得这里。
一般来说,https://nakryiko.com/posts/bpf-tips-printk/是bpf_trace_printk()助手的一个极好的参考。
https://stackoverflow.com/questions/73472044
复制相似问题