LLVM backend handling of packed structures


Nadav Amit
 

I get a strange phenomenon with packed structs in which each byte is
loaded in a different instruction.

Consider for example xdp_prog1 for Linux samples. After building it, the
disassembly starts with:

xdp_prog1:
0: 61 12 04 00 00 00 00 00 r2 = *(u32 *)(r1 + 4)
1: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0)
2: bf 13 00 00 00 00 00 00 r3 = r1
3: 07 03 00 00 0e 00 00 00 r3 += 14
4: 2d 23 37 00 00 00 00 00 if r3 > r2 goto 55
5: 71 13 0c 00 00 00 00 00 r3 = *(u8 *)(r1 + 12)
6: 71 14 0d 00 00 00 00 00 r4 = *(u8 *)(r1 + 13)
7: 67 04 00 00 08 00 00 00 r4 <<= 8
8: 4f 34 00 00 00 00 00 00 r4 |= r3
9: 15 04 02 00 88 a8 00 00 if r4 == 43144 goto 2
10: b7 03 00 00 0e 00 00 00 r3 = 14
11: 55 04 05 00 81 00 00 00 if r4 != 129 goto 5


As you can see, the games in instructions 5-8 that access h_proto (u16) are
very unnecessary. Redefining 'struct ethhdr’ as “unpacked” (i.e., without
the packed attribute), eliminates this behavior.

xdp_prog1:
0: 61 12 04 00 00 00 00 00 r2 = *(u32 *)(r1 + 4)
1: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0)
2: bf 13 00 00 00 00 00 00 r3 = r1
3: 07 03 00 00 0e 00 00 00 r3 += 14
4: 2d 23 34 00 00 00 00 00 if r3 > r2 goto 52
5: 69 14 0c 00 00 00 00 00 r4 = *(u16 *)(r1 + 12)
6: 15 04 02 00 88 a8 00 00 if r4 == 43144 goto 2
7: b7 03 00 00 0e 00 00 00 r3 = 14
8: 55 04 05 00 81 00 00 00 if r4 != 129 goto 5

As you can see, now the the variable is accessed in one chunk, as expected.

Any clues to what went wrong?

Thanks,
Nadav


Yonghong Song
 

On Mon, Jul 3, 2017 at 8:23 PM, Nadav Amit via iovisor-dev
<iovisor-dev@...> wrote:
I get a strange phenomenon with packed structs in which each byte is
loaded in a different instruction.

Consider for example xdp_prog1 for Linux samples. After building it, the
disassembly starts with:

xdp_prog1:
0: 61 12 04 00 00 00 00 00 r2 = *(u32 *)(r1 + 4)
1: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0)
2: bf 13 00 00 00 00 00 00 r3 = r1
3: 07 03 00 00 0e 00 00 00 r3 += 14
4: 2d 23 37 00 00 00 00 00 if r3 > r2 goto 55
5: 71 13 0c 00 00 00 00 00 r3 = *(u8 *)(r1 + 12)
6: 71 14 0d 00 00 00 00 00 r4 = *(u8 *)(r1 + 13)
7: 67 04 00 00 08 00 00 00 r4 <<= 8
8: 4f 34 00 00 00 00 00 00 r4 |= r3
9: 15 04 02 00 88 a8 00 00 if r4 == 43144 goto 2
10: b7 03 00 00 0e 00 00 00 r3 = 14
11: 55 04 05 00 81 00 00 00 if r4 != 129 goto 5


As you can see, the games in instructions 5-8 that access h_proto (u16) are
very unnecessary. Redefining 'struct ethhdr’ as “unpacked” (i.e., without
the packed attribute), eliminates this behavior.

xdp_prog1:
0: 61 12 04 00 00 00 00 00 r2 = *(u32 *)(r1 + 4)
1: 61 11 00 00 00 00 00 00 r1 = *(u32 *)(r1 + 0)
2: bf 13 00 00 00 00 00 00 r3 = r1
3: 07 03 00 00 0e 00 00 00 r3 += 14
4: 2d 23 34 00 00 00 00 00 if r3 > r2 goto 52
5: 69 14 0c 00 00 00 00 00 r4 = *(u16 *)(r1 + 12)
6: 15 04 02 00 88 a8 00 00 if r4 == 43144 goto 2
7: b7 03 00 00 0e 00 00 00 r3 = 14
8: 55 04 05 00 81 00 00 00 if r4 != 129 goto 5

As you can see, now the the variable is accessed in one chunk, as expected.

Any clues to what went wrong?
This is expected from current llvm implementation. For unpacked, the
compiler is able to use field natural alignment to decide which load
variant to use.
For packed, the field alignment is assumed to be 1, so it use load-byte.


Thanks,
Nadav
_______________________________________________
iovisor-dev mailing list
iovisor-dev@...
https://lists.iovisor.org/mailman/listinfo/iovisor-dev


Nadav Amit
 

Y Song <ys114321@...> wrote:

On Mon, Jul 3, 2017 at 8:23 PM, Nadav Amit via iovisor-dev
<iovisor-dev@...> wrote:
I get a strange phenomenon with packed structs in which each byte is
loaded in a different instruction.
This is expected from current llvm implementation. For unpacked, the
compiler is able to use field natural alignment to decide which load
variant to use.
For packed, the field alignment is assumed to be 1, so it use load-byte.
Thanks! From your response, I would assume the solution is nontrivial.