On Thu, Feb 9, 2017 at 5:11 AM, Daniel Borkmann <[email protected]> wrote:
> 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?
yes, I guess LLVM doesn't like the pattern we generate, I will try
different patterns to see if it makes any difference.
> 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
The performance of byte-by-byte load will be bad, but we decide to
work on correctness first.
> below annotation somehow seems to be off slightly (?), but it's always
> patterns like:
ya. it is off by 1 line.
I do try packing the structure, using
#pragma pack(1)
but makes no difference.
Thanks for your reply~
--William
>
> 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