jcmvbkbc/crosstool-NG

Weird gaps between symbols in .bss and .rodata

rojer opened this issue · 13 comments

rojer commented

i'm looking closely at my global variable usage using objdump and i see big gaps in between symbols in .bss

3ffeb3f2 g     O .bss 00000002 avg_freqoffset_sta_freqcal
3ffeb3f4 g     O .bss 0000001c DefFreqCalTimer
3ffeb410 g     O .bss 00000002 PktNumInOneChk
3ffebcd0 g     O .bss 00000040 wDevCtrl
3ffebe78 g     O .bss 00000001 NMIIrqIsOn
3ffebe7c g     O .bss 00000004 WdevTimOffSet
3ffef5c8 g     O .bss 00000001 tout_dis_txpwr_track
3ffef5c9 g     O .bss 00000001 sleep_mode_flag

PktNumInOneChk: supposedly 2 bytes, a gap of 2240.
WdevTimOffSet: size 4 bytes, a gap of 14156 (!) before the next symbol, tout_dis_txpwr_track

what could be using space in these gaps? i don't think they are static variables, as i can see my statics in the output.

rojer commented

i see the same thing in .rodata:

here's entire segment, it's short enough to reproduce in full:

3ffe8c40 g       *ABS*  00000000 _rodata_start
3ffe8c40 g     O .rodata  00000101 _ctype_
3ffe8c40 l    d  .rodata  00000000 .rodata
3ffe8d44 g     O .rodata  00000004 _global_impure_ptr
3ffe8d48 l     O .rodata  00000008 year_lengths
3ffe8d50 l     O .rodata  00000060 mon_lengths
3ffe9168 l     O .rodata  00000028 tinytens
3ffe92f4 l     O .rodata  00000010 zeroes$4031
3ffe9304 l     O .rodata  00000010 blanks$4030
3ffe9314 l     O .rodata  00000022 basefix$3944
3ffe9338 l     O .rodata  000000fc _C_time_locale
3ffe9598 l     O .rodata  00000010 zeroes$4046
3ffe95a8 l     O .rodata  00000010 blanks$4045
3ffe95b8 l     O .rodata  0000000c p05$2546
3ffe95c8 g     O .rodata  00000028 __mprec_tinytens
3ffe95f0 g     O .rodata  00000028 __mprec_bigtens
3ffe9618 g     O .rodata  000000c8 __mprec_tens
3ffe96e0 l     O .rodata  00000010 zeroes$3975
3ffe96f0 l     O .rodata  00000010 blanks$3974
3ffe9700 l     O .rodata  00000022 basefix$3444
3ffe9722 l     O .rodata  00000010 zeroes$3989
3ffe9732 l     O .rodata  00000010 blanks$3988
3ffea051 g     O .rodata  00000006 ethzero
3ffea057 g     O .rodata  00000006 ethbroadcast
3ffea060 g     O .rodata  00000004 ip_addr_broadcast
3ffea064 g     O .rodata  00000004 ip_addr_any
3ffea068 g     O .rodata  00000010 ip6_addr_any
3ffea1dc g       *ABS*  00000000 _bss_table_start
3ffea1dc g       *ABS*  00000000 __init_array_end
3ffea1dc g       *ABS*  00000000 __init_array_start
3ffea1dc g       *ABS*  00000000 __XT_EXCEPTION_DESCS__
3ffea1dc g       *ABS*  00000000 __XT_EXCEPTION_DESCS_END__
3ffea1dc g       *ABS*  00000000 __XT_EXCEPTION_TABLE__
3ffea1e4 g       *ABS*  00000000 _bss_table_end
3ffea1e4 g       *ABS*  00000000 _rodata_end

total size is 0x3ffea1e4 - 0x3ffe8c40 = 5540 bytes, but if i objcopy, i only get 3468 bytes.
and again, blanks$3988: supposedly 16 bytes, but there is a gap of 2335 bytes before ethzero.

Any way for me to reproduce it?

rojer commented

install Docker, then:

[rojer@nba ~/cesanta ]$ git clone https://github.com/cesanta/mongoose-os.git
Cloning into 'mongoose-os'...
...
[rojer@nba ~/cesanta ]$ cd mongoose-os/fw/platforms/esp8266
[rojer@nba ~/cesanta/mongoose-os/fw/platforms/esp8266 master]$ make
...
  Built mongoose-os/esp8266 version 2017021306 (20170213-063055/master@a3afc550)
[rojer@nba ~/cesanta/mongoose-os/fw/platforms/esp8266 master]$ xtensa-lx106-elf-objdump -t .build/mongoose-os.elf | sort | grep '\.rodata'
3ffe8c00 g     O .rodata        0000000f SDK_VERSION
3ffe8c00 l    d  .rodata        00000000 .rodata
3ffe8c0f g     O .rodata        00000006 ethzero
3ffe8c15 g     O .rodata        00000006 ethbroadcast
3ffe8c1c g     O .rodata        00000028 memp_sizes
3ffe8c78 g     O .rodata        00000010 tcp_pcb_lists
3ffe8c88 g     O .rodata        00000007 tcp_persist_backoff
3ffe8c8f g     O .rodata        0000000d tcp_backoff
3ffe8c9c g     O .rodata        00000004 ip_addr_broadcast
3ffe8ca0 g     O .rodata        00000004 ip_addr_any
3ffe8ca4 l     O .rodata        00000004 magic_cookie
3ffe8cc8 g     O .rodata        00000101 _ctype_
3ffe8dcc g     O .rodata        00000004 _global_impure_ptr
3ffe8dd0 l     O .rodata        00000008 year_lengths
3ffe8dd8 l     O .rodata        00000060 mon_lengths
3ffe8fb0 l     O .rodata        00000028 tinytens
3ffe9144 l     O .rodata        00000010 zeroes$4039
3ffe9154 l     O .rodata        00000010 blanks$4038
3ffe9164 l     O .rodata        00000022 basefix$3949
3ffe9188 l     O .rodata        000000fc _C_time_locale
3ffe93f0 l     O .rodata        00000010 zeroes$4054
3ffe9400 l     O .rodata        00000010 blanks$4053
3ffe9410 l     O .rodata        0000000c p05$2549
3ffe9420 g     O .rodata        00000028 __mprec_tinytens
3ffe9448 g     O .rodata        00000028 __mprec_bigtens
3ffe9470 g     O .rodata        000000c8 __mprec_tens
3ffe96a4 l     O .rodata        00000010 zeroes$4018
3ffe96b4 l     O .rodata        00000010 blanks$4017
rojer commented

the docker image contains a build of our fork of esp-open-sdk - specifically, cesanta/esp-open-sdk @ 496f44d which is based on crosstool-NG @ ecfc19a.

PktNumInOneChk: supposedly 2 bytes, a gap of 2240.
WdevTimOffSet: size 4 bytes, a gap of 14156 (!) before the next symbol, tout_dis_txpwr_track

what could be using space in these gaps?

Both these symbols come from the Espressif libpp.a, so I've no idea of how they were made.

'supposedly' is the right word here, because the size printed by the objdump is just an arbitrary metainformation associated with the symbol, it does not have to correspond to actual data size.
Here's an illustration:

$ cat size.s
        .data
        .global var1
var1:
        .long 1
        .size var1, 1000
var2:
        .long 2
$ xtensa-lx106-elf-gcc -c size.s
$ xtensa-lx106-elf-objdump -x size.o | grep var
00000004 l       .data  00000000 var2
00000000 g       .data  000003e8 var1

i see the same thing in .rodata:

unfortunately I don't see the same thing. Here's what I see:

3ffe8c00 g     O .rodata        0000000f SDK_VERSION
3ffe8c00 l    d  .rodata        00000000 .rodata
3ffe8c0f g     O .rodata        00000006 ethzero
3ffe8c15 g     O .rodata        00000006 ethbroadcast
3ffe8c1c g     O .rodata        00000028 memp_sizes
3ffe8c64 g     O .rodata        00000010 tcp_pcb_lists
3ffe8c74 g     O .rodata        00000007 tcp_persist_backoff
3ffe8c7b g     O .rodata        0000000d tcp_backoff
3ffe8c9c g     O .rodata        00000004 ip_addr_broadcast
3ffe8ca0 g     O .rodata        00000004 ip_addr_any
3ffe8ca4 l     O .rodata        00000004 magic_cookie
3ffe8cc8 g     O .rodata        00000101 _ctype_
3ffe8dcc g     O .rodata        00000004 _global_impure_ptr
3ffe8dd0 l     O .rodata        00000008 year_lengths
3ffe8dd8 l     O .rodata        00000060 mon_lengths
3ffe8fb0 l     O .rodata        00000028 tinytens
3ffe9144 l     O .rodata        00000010 zeroes$4039
3ffe9154 l     O .rodata        00000010 blanks$4038
3ffe9164 l     O .rodata        00000022 basefix$3949
3ffe9188 l     O .rodata        000000fc _C_time_locale
3ffe93f0 l     O .rodata        00000010 zeroes$4054
3ffe9400 l     O .rodata        00000010 blanks$4053
3ffe9410 l     O .rodata        0000000c p05$2549
3ffe9420 g     O .rodata        00000028 __mprec_tinytens
3ffe9448 g     O .rodata        00000028 __mprec_bigtens
3ffe9470 g     O .rodata        000000c8 __mprec_tens
3ffe96a4 l     O .rodata        00000010 zeroes$4018
3ffe96b4 l     O .rodata        00000010 blanks$4017
3ffe971f l       .rodata        00000000 .LC9

I looked at the first size mismatch, that's

3ffe8c1c g     O .rodata        00000028 memp_sizes
3ffe8c64 g     O .rodata        00000010 tcp_pcb_lists

and I've found jump table right before the tcp_pcb_lists. Here's the code that uses it:

00000000 <tcp_close_shutdown-0x54>:
...
                        14: R_XTENSA_32 .rodata
...
00000054 <tcp_close_shutdown>:
...
 12c:   ffba21          l32r    a2, 14 <tcp_close_shutdown-0x40>
                        12c: R_XTENSA_SLOT0_OP  .text.tcp_close_shutdown+0x14
 12f:   a02320          addx4   a2, a3, a2
 132:   0228            l32i.n  a2, a2, 0
 134:   0002a0          jx      a2

and the relocations for it, pointing back to tcp_close_shutdown :

Relocation section '.rela.rodata' at offset 0x1c344 contains 12 entries:
 Offset     Info    Type            Sym.Value  Sym. Name + Addend
00000000  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
00000004  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
00000008  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
0000000c  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
00000010  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
00000014  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
00000018  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
0000001c  00001d01 R_XTENSA_32       00000000   .text.tcp_close_shutdo + 0
00000020  0000e101 R_XTENSA_32       00000004   tcp_listen_pcbs + 0
00000024  0000dc01 R_XTENSA_32       00000004   tcp_bound_pcbs + 0
00000028  0000f801 R_XTENSA_32       00000004   tcp_active_pcbs + 0
0000002c  0000fc01 R_XTENSA_32       00000004   tcp_tw_pcbs + 0
rojer commented

there are small discrepancies, those could be jump tables. but there are also big ones.
how about mon_lengths (from your output):

3ffe8dd8 l     O .rodata        00000060 mon_lengths
3ffe8fb0 l     O .rodata        00000028 tinytens

96 bytes size -> 472 bytes gap

The corresponding part of the link map looks like this:

 .rodata        0x000000003ffe8dd0       0x68 /opt/Espressif/esp-open-sdk/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.5/../../../../xtensa-lx106-elf/lib/libc.a(lib_a-mktm_r.o)
 .rodata        0x000000003ffe8e38      0x158 /opt/Espressif/esp-open-sdk/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.5/../../../../xtensa-lx106-elf/lib/libc.a(lib_a-strftime.o)
 .rodata        0x000000003ffe8f90       0x48 /opt/Espressif/esp-open-sdk/xtensa-lx106-elf/lib/gcc/xtensa-lx106-elf/4.8.5/../../../../xtensa-lx106-elf/lib/libc.a(lib_a-strtod.o)

mon_lengths is in the lib_a-mktm_r.o, tinytens is in the lib_a-strtod.o. lib_a-strftime.o between them adds 0x158 byte jump table, again:

00000000 <strftime-0x118>:
...
                        1c: R_XTENSA_32 .rodata
...
 1e8:   ff8d31          l32r    a3, 1c <strftime-0xfc>
                        1e8: R_XTENSA_SLOT0_OP  .text.strftime+0x1c
 1eb:   a02230          addx4   a2, a2, a3
 1ee:   0228            l32i.n  a2, a2, 0
 1f0:   0002a0          jx      a2
Relocation section '.rela.rodata' at offset 0x557c contains 86 entries:
 Offset     Info    Type            Sym.Value  Sym. Name + Addend
00000000  00000801 R_XTENSA_32       00000000   .text.strftime + 0
00000004  00000801 R_XTENSA_32       00000000   .text.strftime + 0
00000008  00000801 R_XTENSA_32       00000000   .text.strftime + 0
0000000c  00000801 R_XTENSA_32       00000000   .text.strftime + 0
00000010  00000801 R_XTENSA_32       00000000   .text.strftime + 0
00000014  00000801 R_XTENSA_32       00000000   .text.strftime + 0
...

Plus 0x1c byte sized table in lib_a-strftime.o with exactly the same pattern.

rojer commented

ok, so the gaps are filled with various ancillary data inserted by compiler. since it's code, can it perhaps be pushed onto flash?

since it's code, can it perhaps be pushed onto flash?

It's not actually code, it's data, likely with relocations against it.
As is it can be pushed to flash as a part of .rodata with linker script. This may not always be desirable, depending on the nature of other data in the .rodata.

With -fpic option given to the compiler these jump tables become a part of the .text of the function that uses them. The resulting code is slightly less efficient though.

The compiler uses JUMP_TABLES_IN_TEXT_SECTION macro (in the compiler backend code) to decide whether it should put jump tables into .text or .rodata. For xtensa it's defined as flag_pic, i.e. it puts tables to .text iff it's invoked with -fpic.

rojer commented

hm... yeah, -fPIC is not a good idea - code is larger and memory footprint increases as well.
ok, so that;s .rodata gaps, they are filled with jumptables.
any ideas what the .bss gaps are?

any ideas what the .bss gaps are?

Do you see any .bss gaps between/adjacent to symbols from object files compiled with gcc?

rojer commented

examining the link map and poking around convinced me that these are just static from SDK libs.
sorry for raising the noise. but - i have learned about linker maps :)