On 02/08/2017 09:22 PM, William Tu via iovisor-dev wrote:
Hi,
I have a program which I use around at most 300byte of local stack as
below. The largest struct is the "struct Headers" which is around 80
byte. However, when loading into the verifier, it says
393: (7b) *(u64 *)(r10 -56) = r1
394: (05) goto pc+56
451: (7b) *(u64 *)(r10 -528) = r0
invalid stack off=-528 size=8
I don't think I'm using more than 512byte. It seems that the llvm
generates the code which use more stack memory than I thought. Any
idea how to debug it? Or how to dump the llvm IR to know how it
allocates stack? Thanks
snippet of the code:
SEC("prog")
int ebpf_filter(struct xdp_md* skb){
struct Headers hd;
unsigned ebpf_packetOffsetInBits = 0;
enum ebpf_errorCodes ebpf_errorCode = NoError;
void* ebpf_packetStart = ((void*)(long)skb->data);
void* ebpf_packetEnd = ((void*)(long)skb->data_end);
u32 ebpf_zero = 0;
u8 ebpf_byte = 0;
u32 ebpf_outHeaderLength = 0;
struct xdp_output xout;
/* TODO: this should be initialized by the environment. HOW? */
struct xdp_input xin;
goto start;
start: {
/* extract(hd.ethernet
Looks like a code generation issue perhaps? It seems your prog parses
and fills a huge struct on the stack, f.e. eth dest is filled from
direct packet acces byte by byte (inefficient, but fair enough). The
below annotation somehow seems to be off slightly (?), but it's always
patterns like:
r1 = *(u8 *)(r2 + 11) ; load byte 1 from pkt into reg (u8)
*(u64 *)(r10 - 408) = r1 ; store byte 1 into stack (u64)
r1 = *(u8 *)(r2 + 10) ; load byte 2 from pkt into reg (u8)
*(u64 *)(r10 - 416) = r1 ; store byte 2 into stack (u64)
[...]
; void* ebpf_packetStart = ((void*)(long)skb->data);
2: r2 = *(u32 *)(r6 + 0)
[...]
; hd.ethernet.destination[5] = (u8)((load_byte(ebpf_packetStart,
BYTES(ebpf_packetOffsetInBits) + 5) >> 0));
9: r1 = *(u8 *)(r2 + 11)
; hd.ethernet.destination[4] = (u8)((load_byte(ebpf_packetStart,
BYTES(ebpf_packetOffsetInBits) + 4) >> 0));
10: *(u64 *)(r10 - 408) = r1
11: r1 = *(u8 *)(r2 + 10)
; hd.ethernet.destination[3] = (u8)((load_byte(ebpf_packetStart,
BYTES(ebpf_packetOffsetInBits) + 3) >> 0));
12: *(u64 *)(r10 - 416) = r1
13: r1 = *(u8 *)(r2 + 9)
; hd.ethernet.destination[2] = (u8)((load_byte(ebpf_packetStart,
BYTES(ebpf_packetOffsetInBits) + 2) >> 0));
14: *(u64 *)(r10 - 424) = r1
15: r1 = *(u8 *)(r2 + 8)
; hd.ethernet.destination[1] = (u8)((load_byte(ebpf_packetStart,
BYTES(ebpf_packetOffsetInBits) + 1) >> 0));
16: *(u64 *)(r10 - 432) = r1
17: r1 = *(u8 *)(r2 + 7)
; hd.ethernet.destination[0] = (u8)((load_byte(ebpf_packetStart,
BYTES(ebpf_packetOffsetInBits) + 0) >> 0));
18: *(u64 *)(r10 - 440) = r1
19: r1 = *(u8 *)(r2 + 6)
[...]
Despite a struct of:
struct Ethernet {
char source[6]; /* bit<48> */
char destination[6]; /* bit<48> */
u16 protocol; /* bit<16> */
u8 ebpf_valid;
};
Maybe packing structs helps a bit (but still shouldn't be such waste,
hmm ...).
full C, objdump
https://gist.github.com/williamtu/5a09b60a951ee5fc062328766403ab4b
thanks
_______________________________________________
iovisor-dev mailing list
[email protected]
https://lists.iovisor.org/mailman/listinfo/iovisor-dev
_______________________________________________
iovisor-dev mailing list
[email protected]
https://lists.iovisor.org/mailman/listinfo/iovisor-dev