Rust: llvm-objcopy produces 160MB binary. It used to be 74KB

Created on 10 Jun 2020  路  16Comments  路  Source: rust-lang/rust

I'm developing a platform for TockOS. They upgraded the nightly version from 03-06 to 06-03, and now llvm-objcopy produces a 160MB binary instead of a 74KB binary. I also tried on the latest nightly (06-09), and the result is the same.

I tried this code with the same .elf file:

~/.rustup/toolchains/nightly-2020-06-03-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-objcopy --output-target=binary ./edu-ciaa.elf ./edu-ciaa.06-03.bin

~/.rustup/toolchains/nightly-2020-03-06-x86_64-unknown-linux-gnu/lib/rustlib/x86_64-unknown-linux-gnu/bin/llvm-objcopy --output-target=binary ./edu-ciaa.elf ./edu-ciaa.03-06.bin

I expected to see both binaries have roughly the same size, since both are applied to the same elf file. (which can be found here: https://github.com/dc740/tock/blob/fd6517da9f22d088a30d6b7cb767e42ab820814f/boards/ciaa/edu-ciaa/sample-edu-ciaa.elf )

Instead, the produced binary from nightly 03-06 is 74KB and the one produced by the newer nightly versions 06-03 and 06-19 is 160MB.

Meta

rustc --version --verbose:

rustc 1.46.0-nightly (feb3536eb 2020-06-09)
binary: rustc
commit-hash: feb3536eba10c2e4585d066629598f03d5ddc7c6
commit-date: 2020-06-09
host: x86_64-unknown-linux-gnu
release: 1.46.0-nightly
LLVM version: 10.0
A-LLVM C-bug E-needs-bisection I-heavy ICEBreaker-Cleanup-Crew ICEBreaker-LLVM T-compiler regression-from-stable-to-nightly

Most helpful comment

I haven't tested this directly, but this change looks relevant:
https://github.com/llvm/llvm-project/commit/d28c6d51d1547d9cd7cd5b7e36b4c03f38ef7c67
https://reviews.llvm.org/D71035

So that would imply that the bug is coming from LLVM-upstream?

Yes, although I hesitate to call it a bug. From the manpage:

If binary is used as the value for --output-target, the output file will be a raw binary file, containing the memory image of the input file. Symbols and relocation information will be discarded. The image will start at the address of the first loadable section in the output.

Since the virtual addresses really do have a large span, 161M does seem like an appropriate memory image. The old 76K size had those loaded segments adjacent, which doesn't match memory.

All 16 comments

@rustbot ping llvm

Does anyone know what's going on here?

Hey LLVM ICE-breakers! This bug has been identified as a good
"LLVM ICE-breaking candidate". In case it's useful, here are some
[instructions] for tackling these sorts of bugs. Maybe take a look?
Thanks! <3

cc @camelid @comex @cuviper @DutchGhost @dyncat @hanna-kruppe @hdhoang @heyrutvik @JOE1994 @jryans @mmilenko @nagisa @nikic @Noah-Kennedy @SiavoshZarrasvand @spastorino @vertexclique

It appears that the LLVM version shipped with rustc is used. There has been a bump in LLVM version in the time range, which is most suspect here.

@rustbot ping cleanup

It would be nice to find where this has regressed, as @nagisa noted, likely to be in an LLVM bump.

Hey Cleanup Crew ICE-breakers! This bug has been identified as a good
"Cleanup ICE-breaking candidate". In case it's useful, here are some
[instructions] for tackling these sorts of bugs. Maybe take a look?
Thanks! <3

cc @AminArria @camelid @chrissimpkins @contrun @DutchGhost @elshize @ethanboxx @h-michael @HallerPatrick @hdhoang @hellow554 @imtsuki @kanru @KarlK90 @LeSeulArtichaut @MAdrianMattocks @matheus-consoli @mental32 @nmccarty @Noah-Kennedy @pard68 @PeytonT @pierreN @Redblueflame @RobbieClarken @RobertoSnap @robjtede @SarthakSingh31 @senden9 @shekohex @sinato @spastorino @turboladen @woshilapin @yerke

Assigning P-high as discussed as part of the Prioritization Working Group process and removing I-prioritize.

Regression happened between nightly-2020-05-17 and nightly-2020-05-23, continuing bisection.

I can reproduce this with vanilla LLVM tools on Fedora 32.

  • The input file is 2.0MB (2069404).
  • With llvm-objcopy from llvm-10.0.0-1.fc32.x86_64, the output is 161M (167849124).
  • With llvm-objcopy-9.0 from llvm9.0-9.0.1-8.fc32.x86_64, the output is 76K (76964).
  • With llvm-objcopy-8.0 from llvm8.0-8.0.0-11.fc32.x86_64, the output is 76K (76964).

Here are the section and program headers:

$ eu-readelf -lS sample-edu-ciaa.elf
There are 23 section headers, starting at offset 0x1f9004:

Section Headers:
[Nr] Name                 Type         Addr     Off    Size   ES Flags Lk Inf Al
[ 0]                      NULL         00000000 000000 000000  0        0   0  0
[ 1] .stack               NOBITS       10000000 000114 001000  0 WA     0   0  1
[ 2] .text                PROGBITS     1a000000 000200 0112f8  0 AXM    0   0 16
[ 3] .ARM.exidx           ARM_EXIDX    1a0112f8 0114f8 000010  0 AL     2   0  4
[ 4] .storage             PROGBITS     1a011308 011508 0000f8  0 A      0   0  1
[ 5] .apps                PROGBITS     1a040000 011600 000000  0 A      0   0  1
[ 6] .relocate            PROGBITS     10001000 011600 0018a4  0 WA     0   0  4
[ 7] .sram                NOBITS       100028a4 012ea4 00575c  0 WA     0   0  4
[ 8] .debug_str           PROGBITS     00000000 012ea4 067400  1 MS     0   0  1
[ 9] .debug_loc           PROGBITS     00000000 07a2a4 043b4e  0        0   0  1
[10] .debug_abbrev        PROGBITS     00000000 0bddf2 001125  0        0   0  1
[11] .debug_info          PROGBITS     00000000 0bef17 09c23b  0        0   0  1
[12] .debug_aranges       PROGBITS     00000000 15b158 0017e8  0        0   0  8
[13] .debug_ranges        PROGBITS     00000000 15c940 00f678  0        0   0  1
[14] .debug_pubnames      PROGBITS     00000000 16bfb8 026ec5  0        0   0  1
[15] .debug_pubtypes      PROGBITS     00000000 192e7d 037bca  0        0   0  1
[16] .ARM.attributes      ARM_ATTRIBUTES 00000000 1caa47 000030  0        0   0  1
[17] .debug_frame         PROGBITS     00000000 1caa78 003018  0        0   0  4
[18] .debug_line          PROGBITS     00000000 1cda90 01da06  0        0   0  1
[19] .comment             PROGBITS     00000000 1eb496 000093  1 MS     0   0  1
[20] .symtab              SYMTAB       00000000 1eb52c 003ec0 16       22 972  4
[21] .shstrtab            STRTAB       00000000 1ef3ec 0000f1  0        0   0  1
[22] .strtab              STRTAB       00000000 1ef4dd 009b27  0        0   0  1

Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz  MemSiz   Flg Align
  LOAD           0x000200 0x1a000000 0x1a000000 0x011400 0x011400 R E 0x200
  LOAD           0x011600 0x10001000 0x1a011400 0x0018a4 0x0018a4 RW  0x200
  GNU_STACK      0x000000 0x00000000 0x00000000 0x000000 0x000000 RW  0x0
  ARM_EXIDX      0x0114f8 0x1a0112f8 0x1a0112f8 0x000010 0x000010 R   0x4

 Section to Segment mapping:
  Segment Sections...
   00      [RO: .text .ARM.exidx .storage]
   01      .relocate
   02
   03      [RO: .ARM.exidx]

I notice that adding the sizes of the two load sections, 0x011400 + 0x0018a4 is 76964, precisely matching the former llvm-objcopy output size. I haven't figured out the exact match for the 161M (167849124), but it's pretty close to the virtual address range of those load segments, 0x10001000..0x1a011400 is 167838720 bytes.

@cuviper So that would imply that the bug is coming from LLVM-upstream?

From my testing, the regression happened in nightly-2020-05-22. @nagisa does that correspond to a LLVM bump?

Regression happened between nightly-2020-05-17 and nightly-2020-05-23, continuing bisection.

The upgrade to LLVM 10 merged on 2020-05-20: https://github.com/rust-lang/rust/pull/67759#event-3359046557
(GitHub shows that as 7:55PM PDT, which would have missed the nightly on 05-21 UTC.)

I haven't tested this directly, but this change looks relevant:
https://github.com/llvm/llvm-project/commit/d28c6d51d1547d9cd7cd5b7e36b4c03f38ef7c67
https://reviews.llvm.org/D71035

So that would imply that the bug is coming from LLVM-upstream?

Yes, although I hesitate to call it a bug. From the manpage:

If binary is used as the value for --output-target, the output file will be a raw binary file, containing the memory image of the input file. Symbols and relocation information will be discarded. The image will start at the address of the first loadable section in the output.

Since the virtual addresses really do have a large span, 161M does seem like an appropriate memory image. The old 76K size had those loaded segments adjacent, which doesn't match memory.

I think we should close this issue as intended LLVM behavior given @cuviper comments. At least removing P-high label for now. @dc740 thoughts?.

To be honest, right now I don't have the knowledge to either decline or accept this change in behavior as a bug. I will be doing some research so I can understand what's going on, and what would be the right way to generate the .elf file with the correct virtual addresses, which, as I understand, is the culprit of the problem. Is that the right approach? Did I understand that correctly? I'd really appreciate if anyone wants to jump in and explain where to start looking, since this is currently out of my comfort zone, but feel free to close the bug report. I don't want to cause any more inconvenience.

Thanks everyone for the time and responses.

Ok, I'm going to close this issue, maybe @cuviper can explain it a bit better if it's not a problem for them.

I don't have experience using binary objcopy -- I just inferred what I could from the information provided. I suppose it would work if you can affect the virtual addresses of your input file. Another possibility is to use objcopy --only-section=... with just the sections you actually need for your target. I suspect you don't actually need everything, if you were working well enough without the virtual memory addressing before. For instance, --only-section=.text gives me a 69K file.

Was this page helpful?
0 / 5 - 0 ratings