Em Mon, Jan 14, 2019 at 10:06:11PM +0000, Yonghong Song escreveu: > On 1/14/19 10:13 AM, Arnaldo Carvalho de Melo wrote: > > Em Mon, Jan 14, 2019 at 04:55:42PM +0000, Yonghong Song escreveu: > >> On 1/14/19 6:27 AM, Arnaldo Carvalho de Melo wrote: > > Which ends up producing this output, that still has stuff to do wrt the > > hole/padding calculations, but has the offset adjusted to that '30' > > value instead of showing -1: > > > > [acme@quaco pahole]$ pahole examples/yonghong/packed_bitfield.o > > struct packed { > > char x1:1; /* 0: 7 1 */ > > char x2:3; /* 0: 4 1 */ > > char x3:3; /* 0: 1 1 */ > > int y1:7; /* 0:18 4 */ > > int y2:20; /* 0:30 4 */ > > The y2 should be "4:30"? So, I kept that patch and added another hunk, the first one here: diff --git a/dwarves_fprintf.c b/dwarves_fprintf.c index bd46f97916fc..39f96318625e 100644 --- a/dwarves_fprintf.c +++ b/dwarves_fprintf.c @@ -753,6 +753,9 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb sconf.base_offset = offset; } + if (member->bitfield_offset < 0) + offset += member->byte_size; + if (!conf->suppress_comments) printed_cacheline = class__fprintf_cacheline_boundary(conf, offset, fp); @@ -807,9 +810,14 @@ static size_t class_member__fprintf(struct class_member *member, bool union_memb offset); if (member->bitfield_size != 0) { + unsigned int bitfield_offset = member->bitfield_offset; + + if (member->bitfield_offset < 0) + bitfield_offset = member->byte_size * 8 + member->bitfield_offset; + printed += fprintf(fp, sconf.hex_fmt ? ":%#2x" : ":%2u", - member->bitfield_offset); + bitfield_offset); size_spacing -= 3; } With it we get what you suggested: [acme@quaco pahole]$ pahole examples/yonghong/packed_bitfield.o struct packed { char x1:1; /* 0: 7 1 */ char x2:3; /* 0: 4 1 */ char x3:3; /* 0: 1 1 */ int y1:7; /* 0:18 4 */ int y2:20; /* 4:30 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; [acme@quaco pahole]$ And, if I use a cross compiler to build a big endian .o: [acme@quaco ~]$ dsh ubuntu:18.04-x-powerpc perfbuilder@47aa4489b67f:/git/pahole$ powerpc-linux-gnu-gcc -O2 -g -c examples/yonghong/packed_bitfield.c -o /git/tmp/packed_bitfield.powerpc.o perfbuilder@47aa4489b67f:/git/pahole$ exit The one for x86_64: [acme@quaco pahole]$ file examples/yonghong/packed_bitfield.o examples/yonghong/packed_bitfield.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped For powerpc: [acme@quaco pahole]$ file ~acme/git/tmp/packed_bitfield.powerpc.o /home/acme/git/tmp/packed_bitfield.powerpc.o: ELF 32-bit MSB relocatable, PowerPC or cisco 4500, version 1 (SYSV), with debug_info, not stripped [acme@quaco pahole]$ [acme@quaco pahole]$ pahole ~acme/git/tmp/packed_bitfield.powerpc.o struct packed { char x1:1; /* 0: 0 1 */ char x2:3; /* 0: 1 1 */ char x3:3; /* 0: 4 1 */ int y1:7; /* 0: 7 4 */ int y2:20; /* 0:14 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; [acme@quaco pahole]$ And with sparc64: [acme@quaco ~]$ dsh ubuntu:18.04-x-sparc64 perfbuilder@1ded5e9c526a:/git/pahole$ sparc64-linux-gnu-gcc -O2 -g -c examples/yonghong/packed_bitfield.c -o /git/tmp/packed_bitfield.sparc64.o perfbuilder@1ded5e9c526a:/git/pahole$ exit [acme@quaco pahole]$ file ~acme/git/tmp/packed_bitfield.sparc64.o /home/acme/git/tmp/packed_bitfield.sparc64.o: ELF 64-bit MSB relocatable, SPARC V9, relaxed memory ordering, version 1 (SYSV), with debug_info, not stripped [acme@quaco pahole]$ pahole ~acme/git/tmp/packed_bitfield.sparc64.o struct packed { char x1:1; /* 0: 0 1 */ char x2:3; /* 0: 1 1 */ char x3:3; /* 0: 4 1 */ int y1:7; /* 0: 7 4 */ int y2:20; /* 0:14 4 */ /* size: 5, cachelines: 1, members: 5 */ /* padding: 1 */ /* bit_padding: 254 bits */ /* last cacheline: 5 bytes */ /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ }; [acme@quaco pahole]$ Seems to work? Now need to tackle the holes calculations. > This is how I interpret the above: > > > char x1:1; /* 0: 7 1 */ > > ==> this will convert to big endian offset 0, size 1 > ==> offset = sizeof(char) - 7 - 1 > > > char x2:3; /* 0: 4 1 */ > ===> this will convert to big endian offset 1, size 3 > ===> offset = sizeof(char) - 4 - 3 > > > char x3:3; /* 0: 1 1 */ > ===> this will convert to big endian offset 4, size 3 > ===> offset = sizeof(char) - 1 - 3 > > > int y1:7; /* 0:18 4 */ > ===> this will convert to big endian offset 7, size 7 > ===> offset = sizeof(int) - 18 - 7 = 7 > > int y2:20; /* 4:30 4 */ > ===> this will convert to big endian offset 14, size 20 > ===> offset = 4 * 8 + sizeof(int) - 30 - 20 = 14 > > > > > > /* size: 5, cachelines: 1, members: 5 */ > > /* padding: 1 */ > > /* bit_padding: 254 bits */ > > /* last cacheline: 5 bytes */ > > > > /* BRAIN FART ALERT! 5 != 1 + 0(holes), diff = 4 */ > > }; > > [acme@quaco pahole]$ > > > > The following drawing _tries_ to paint this picture according to the > > description you gave for negative bit_offsets, butthen it would be 8 > > bytes, the size of the struct is 5 bytes, sizeof(char) + sizeof(int), > > and since the sum of the bit sizes is 34 bits, we need 5 bytes. > > > > x x > > + 3 + + 2 + x1 +---- y2 ---+ +-- y2 --+ > > | | | | | | | | | > > V V V V V V V V V > > [0 1 2 3 4 5 6 7 ... 30 31][0 .. 17 18 ..... 24 .. 31] > > With packing, the elements layout may not be similar to the above. > > It probably likes below (I have a C program later): > > => memory increasing > bits > 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ... 30 31 32 33 34 ... > x1 | x2 | | x3 | | y1 | | y2 | > > In little representation, the following looks like the case: > x1: byte0, bit 7 > x2: byte0, bit 4 - 6 > x3: byte0, bit 1 - 3 > y1: byte0, bit 0 and byte1, bit 2 - 7. > y2: byte1, bit 0 - 1, and byte 2, 3, and byte4 6 -7. > > So there is no wasted bits. In the above your diagram, there are > some wasted bits. > > I didn't check exactly how the little endian DW attributes are computed > inside the compiler for the packed case. But one way to do it is > - do a big endian bit offset/size assignment first. This should be > straight forward. > - convert to the little endian offset based on the corresponding > field type and big endian field offset/type. > > -bash-4.4$ cat t2.c > #include <stdio.h> > > struct packed { > char x1: 1; > char x2: 3; > char x3: 3; > int y1: 7; > int y2: 20; > } __attribute__((packed)); > > int main() { > struct packed p; > int i; > > p.x1 = 1; > p.x2 = 0; > p.x3 = 2; > p.y1 = 7 << 2; > p.y2 = (1 << 18) + 3; > > for (i = 0; i < sizeof(p); i++) > printf("i = %x\n", *(((unsigned char *)&p) + i)); > > return 0; > } > -bash-4.4$ gcc t2.c > -bash-4.4$ ./a.out > i = 21 > i = ce > i = 0 > i = 0 > i = fd > -bash-4.4$ > > > > > Doesn't make sense, we don't have 64 bits, just 40. > > > > Can you hand hold me here? :-) > > > >>> seeing negative DW_AT_bit_offsets we should think it starts in this > >>> location (0 in this case), but straddles to the next, so I should say > >>> that it is at bit offset (DW_AT_byte_size * 8 - DW_AT_bit_offset), the > >>> user, looking at this new pahole output will realize that it has 2 bits > >>> at the end of the current DW_AT_data_member_location (0) but has 18 bits > >>> in the next. > >>> > >>> > >>>> (2). the -2 means the the starting bit is at the "4" byte boundary - 2 > >>>> bits. So basically it covers: > >>>> > >>>> | | > >>>> V V > >>>> [0 1 .....30 31][0 .. 17 18 ... 31] > >>>> > >>>> totally 20 bits. > >>>> > >>>> The following patch fixed the issue: > >>>> -bash-4.4$ git diff > >>>> diff --git a/dwarves.h b/dwarves.h > >>>> index e6bffe8..e5f8347 100644 > >>>> --- a/dwarves.h > >>>> +++ b/dwarves.h > >>>> @@ -831,7 +831,7 @@ struct class_member { > >>>> uint32_t bit_size; > >>>> uint32_t byte_offset; > >>>> size_t byte_size; > >>>> - uint8_t bitfield_offset; > >>>> + int8_t bitfield_offset; > >>>> uint8_t bitfield_size; > >>>> uint8_t bit_hole; > >>>> uint8_t bitfield_end:1; > >>>> -bash-4.4$ > >>>> > >>>> With the above change: > >>>> -bash-4.4$ ~/work/github/pahole/build/pahole -JV bitfields.o > >>>> File bitfields.o: > >>>> [1] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED > >>>> [2] STRUCT packed kind_flag=1 size=5 vlen=5 > >>>> x1 type_id=3 bitfield_size=1 bits_offset=0 > >>>> x2 type_id=3 bitfield_size=3 bits_offset=1 > >>>> x3 type_id=3 bitfield_size=3 bits_offset=4 > >>>> y1 type_id=1 bitfield_size=7 bits_offset=7 > >>>> y2 type_id=1 bitfield_size=20 bits_offset=14 > >>>> [3] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) > >>>> [4] STRUCT unpacked kind_flag=1 size=8 vlen=5 > >>>> x1 type_id=3 bitfield_size=1 bits_offset=0 > >>>> x2 type_id=3 bitfield_size=3 bits_offset=1 > >>>> x3 type_id=3 bitfield_size=3 bits_offset=4 > >>>> y1 type_id=1 bitfield_size=7 bits_offset=7 > >>>> y2 type_id=1 bitfield_size=20 bits_offset=32 > >>>> [5] UNION packed_union kind_flag=0 size=8 vlen=4 > >>>> x1 type_id=3 bits_offset=0 > >>>> y2 type_id=1 bits_offset=0 > >>>> s1 type_id=2 bits_offset=0 > >>>> s2 type_id=4 bits_offset=0 > >>>> [6] UNION unpacked_union kind_flag=0 size=8 vlen=3 > >>>> x1 type_id=3 bits_offset=0 > >>>> y2 type_id=1 bits_offset=0 > >>>> s type_id=4 bits_offset=0 > >>>> -bash-4.4$ > >>>> > >>>> Will send out a patch shortly. > >>>> > >>>>> > >>>>> andriin@devvm$ cat bitfields.c > >>>>> struct unpacked{ > >>>>> char x1: 1; > >>>>> char x2: 3; > >>>>> char x3: 3; > >>>>> int y1: 7; > >>>>> int y2: 20; > >>>>> }; > >>>>> > >>>>> struct packed{ > >>>>> char x1: 1; > >>>>> char x2: 3; > >>>>> char x3: 3; > >>>>> int y1: 7; > >>>>> int y2: 20; > >>>>> } __attribute__((packed)); > >>>>> > >>>>> union packed_union { > >>>>> char x1; > >>>>> int y2; > >>>>> struct packed s1; > >>>>> struct unpacked s2; > >>>>> }; > >>>>> > >>>>> union unpacked_union { > >>>>> char x1; > >>>>> int y2; > >>>>> struct unpacked s; > >>>>> } __attribute__((packed)); > >>>>> > >>>>> int main() { > >>>>> struct packed s1; > >>>>> struct unpacked s2; > >>>>> union packed_union u1; > >>>>> union unpacked_union u2; > >>>>> return 0; > >>>>> } > >>>>> andriin@devvm$ cc -g bitfields.c -o bitfields > >>>>> andriin@devvm$ LLVM_OBJCOPY=objcopy ~/local/pahole/build/pahole -JV bitfields > >>>>> File bitfields: > >>>>> [1] STRUCT unpacked kind_flag=1 size=8 vlen=5 > >>>>> x1 type_id=2 bitfield_size=1 bits_offset=0 > >>>>> x2 type_id=2 bitfield_size=3 bits_offset=1 > >>>>> x3 type_id=2 bitfield_size=3 bits_offset=4 > >>>>> y1 type_id=3 bitfield_size=7 bits_offset=7 > >>>>> y2 type_id=3 bitfield_size=20 bits_offset=32 > >>>>> [2] INT char size=1 bit_offset=0 nr_bits=8 encoding=(none) > >>>>> [3] INT int size=4 bit_offset=0 nr_bits=32 encoding=SIGNED > >>>>> [4] STRUCT packed kind_flag=1 size=5 vlen=5 > >>>>> x1 type_id=2 bitfield_size=1 bits_offset=0 > >>>>> x2 type_id=2 bitfield_size=3 bits_offset=1 > >>>>> x3 type_id=2 bitfield_size=3 bits_offset=4 > >>>>> y1 type_id=3 bitfield_size=7 bits_offset=7 > >>>>> y2 type_id=3 bitfield_size=255 bits_offset=16776974 > >>>>> [5] UNION packed_union kind_flag=0 size=8 vlen=4 > >>>>> x1 type_id=2 bits_offset=0 > >>>>> y2 type_id=3 bits_offset=0 > >>>>> s1 type_id=4 bits_offset=0 > >>>>> s2 type_id=1 bits_offset=0 > >>>>> [6] UNION unpacked_union kind_flag=0 size=8 vlen=3 > >>>>> x1 type_id=2 bits_offset=0 > >>>>> y2 type_id=3 bits_offset=0 > >>>>> s type_id=1 bits_offset=0 > >>>>> andriin@devvm$ readelf -wi bitfields > >>>>> Contents of the .debug_info section: > >>>>> > >>>>> ... > >>>>> > >>>>> <1><2d>: Abbrev Number: 2 (DW_TAG_structure_type) > >>>>> <2e> DW_AT_name : (indirect string, offset: 0x4e): unpacked > >>>>> <32> DW_AT_byte_size : 8 > >>>>> <33> DW_AT_decl_file : 1 > >>>>> <34> DW_AT_decl_line : 1 > >>>>> <35> DW_AT_sibling : <0x80> > >>>>> <2><39>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <3a> DW_AT_name : x1 > >>>>> <3d> DW_AT_decl_file : 1 > >>>>> <3e> DW_AT_decl_line : 2 > >>>>> <3f> DW_AT_type : <0x80> > >>>>> <43> DW_AT_byte_size : 1 > >>>>> <44> DW_AT_bit_size : 1 > >>>>> <45> DW_AT_bit_offset : 7 > >>>>> <46> DW_AT_data_member_location: 0 > >>>>> <2><47>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <48> DW_AT_name : x2 > >>>>> <4b> DW_AT_decl_file : 1 > >>>>> <4c> DW_AT_decl_line : 3 > >>>>> <4d> DW_AT_type : <0x80> > >>>>> <51> DW_AT_byte_size : 1 > >>>>> <52> DW_AT_bit_size : 3 > >>>>> <53> DW_AT_bit_offset : 4 > >>>>> <54> DW_AT_data_member_location: 0 > >>>>> <2><55>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <56> DW_AT_name : x3 > >>>>> <59> DW_AT_decl_file : 1 > >>>>> <5a> DW_AT_decl_line : 4 > >>>>> <5b> DW_AT_type : <0x80> > >>>>> <5f> DW_AT_byte_size : 1 > >>>>> <60> DW_AT_bit_size : 3 > >>>>> <61> DW_AT_bit_offset : 1 > >>>>> <62> DW_AT_data_member_location: 0 > >>>>> <2><63>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <64> DW_AT_name : y1 > >>>>> <67> DW_AT_decl_file : 1 > >>>>> <68> DW_AT_decl_line : 5 > >>>>> <69> DW_AT_type : <0x87> > >>>>> <6d> DW_AT_byte_size : 4 > >>>>> <6e> DW_AT_bit_size : 7 > >>>>> <6f> DW_AT_bit_offset : 18 > >>>>> <70> DW_AT_data_member_location: 0 > >>>>> <2><71>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <72> DW_AT_name : y2 > >>>>> <75> DW_AT_decl_file : 1 > >>>>> <76> DW_AT_decl_line : 6 > >>>>> <77> DW_AT_type : <0x87> > >>>>> <7b> DW_AT_byte_size : 4 > >>>>> <7c> DW_AT_bit_size : 20 > >>>>> <7d> DW_AT_bit_offset : 12 > >>>>> <7e> DW_AT_data_member_location: 4 > >>>>> <2><7f>: Abbrev Number: 0 > >>>>> <1><80>: Abbrev Number: 4 (DW_TAG_base_type) > >>>>> <81> DW_AT_byte_size : 1 > >>>>> <82> DW_AT_encoding : 6 (signed char) > >>>>> <83> DW_AT_name : (indirect string, offset: 0xb3): char > >>>>> <1><87>: Abbrev Number: 5 (DW_TAG_base_type) > >>>>> <88> DW_AT_byte_size : 4 > >>>>> <89> DW_AT_encoding : 5 (signed) > >>>>> <8a> DW_AT_name : int > >>>>> <1><8e>: Abbrev Number: 2 (DW_TAG_structure_type) > >>>>> <8f> DW_AT_name : (indirect string, offset: 0x50): packed > >>>>> <93> DW_AT_byte_size : 5 > >>>>> <94> DW_AT_decl_file : 1 > >>>>> <95> DW_AT_decl_line : 9 > >>>>> <96> DW_AT_sibling : <0xe1> > >>>>> <2><9a>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <9b> DW_AT_name : x1 > >>>>> <9e> DW_AT_decl_file : 1 > >>>>> <9f> DW_AT_decl_line : 10 > >>>>> <a0> DW_AT_type : <0x80> > >>>>> <a4> DW_AT_byte_size : 1 > >>>>> <a5> DW_AT_bit_size : 1 > >>>>> <a6> DW_AT_bit_offset : 7 > >>>>> <a7> DW_AT_data_member_location: 0 > >>>>> <2><a8>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <a9> DW_AT_name : x2 > >>>>> <ac> DW_AT_decl_file : 1 > >>>>> <ad> DW_AT_decl_line : 11 > >>>>> <ae> DW_AT_type : <0x80> > >>>>> <b2> DW_AT_byte_size : 1 > >>>>> <b3> DW_AT_bit_size : 3 > >>>>> <b4> DW_AT_bit_offset : 4 > >>>>> <b5> DW_AT_data_member_location: 0 > >>>>> <2><b6>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <b7> DW_AT_name : x3 > >>>>> <ba> DW_AT_decl_file : 1 > >>>>> <bb> DW_AT_decl_line : 12 > >>>>> <bc> DW_AT_type : <0x80> > >>>>> <c0> DW_AT_byte_size : 1 > >>>>> <c1> DW_AT_bit_size : 3 > >>>>> <c2> DW_AT_bit_offset : 1 > >>>>> <c3> DW_AT_data_member_location: 0 > >>>>> <2><c4>: Abbrev Number: 3 (DW_TAG_member) > >>>>> <c5> DW_AT_name : y1 > >>>>> <c8> DW_AT_decl_file : 1 > >>>>> <c9> DW_AT_decl_line : 13 > >>>>> <ca> DW_AT_type : <0x87> > >>>>> <ce> DW_AT_byte_size : 4 > >>>>> <cf> DW_AT_bit_size : 7 > >>>>> <d0> DW_AT_bit_offset : 18 > >>>>> <d1> DW_AT_data_member_location: 0 > >>>>> <2><d2>: Abbrev Number: 6 (DW_TAG_member) > >>>>> <d3> DW_AT_name : y2 > >>>>> <d6> DW_AT_decl_file : 1 > >>>>> <d7> DW_AT_decl_line : 14 > >>>>> <d8> DW_AT_type : <0x87> > >>>>> <dc> DW_AT_byte_size : 4 > >>>>> <dd> DW_AT_bit_size : 20 > >>>>> <de> DW_AT_bit_offset : -2 > >>>>> <df> DW_AT_data_member_location: 0 > >>>>> <2><e0>: Abbrev Number: 0 > >>>>> > >>>>> ... > >>>>> > >>> > > -- - Arnaldo