This is an archive of the discontinued LLVM Phabricator instance.

[yaml2obj] - Allocate the file space for SHT_NOBITS sections in some cases.
ClosedPublic

Authored by grimar on May 27 2020, 6:16 AM.

Details

Summary

This teaches yaml2obj to allocate file space for a no-bits section
when there is a non-nobits section in the same segment that follows it.

It was discussed in D78005 thread and matches GNU linkers and LLD behavior.

Diff Detail

Event Timeline

grimar created this revision.May 27 2020, 6:16 AM
MaskRay added a comment.EditedMay 27 2020, 8:55 PM

This behavior seems reasonable.

It was discussed in D78005 thread and matches GNU linkers behavior.

Matches GNU linkers and LLD. Checked with:

% cat a.s
.section .data,"aw"
.byte 0

.section .dataa,"aw",@nobits
.byte 0

.section .datab,"aw",@nobits
.byte 0

.section .datac,"aw"
.byte 0

% cat a.x
SECTIONS {
  .data : { *(.data) }
  .dataa : { *(.dataa) }
  .datab : { *(.datab) }
  .datac : { *(.datac) }
  .bss : { *(.bss) }
}

% ld.lld -T a.x a.o -o a
llvm/lib/ObjectYAML/ELFEmitter.cpp
1094

Inlining getChunksAfter can avoid the cost constructing a vector.

This behavior seems reasonable.

It was discussed in D78005 thread and matches GNU linkers behavior.

Matches GNU linkers and LLD.

Thanks! I've not tested LLD. Nice that it is consistent.

grimar edited the summary of this revision. (Show Details)May 28 2020, 2:21 AM
grimar updated this revision to Diff 266810.May 28 2020, 4:12 AM
grimar marked 2 inline comments as done.
  • Addressed review comments.
llvm/lib/ObjectYAML/ELFEmitter.cpp
1094

I think the cost was very low: there is no much output sections usually, and the case when there are non-nobits sections after a nobit section is also probably rare. But it made the final code to be much shorter.

grimar marked an inline comment as done.May 29 2020, 1:39 AM
grimar added inline comments.
llvm/lib/ObjectYAML/ELFEmitter.cpp
1094

Perhaps my comment is not very clear: inlining made the code shorter.

jhenderson added inline comments.May 29 2020, 1:40 AM
llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
2

then -> them
have -> has

23

has the non-nobits -> has a non-nobits

25

.nobits.2 isn't in any segment, so I think this test case isn't quite right. .nobits.2 needs to be in the same segment as .nobits.1, with a non-nobits segment in between.

Also, I think you need a test-case for two trailing .nobits sections to show neither has file space allocated.

grimar marked an inline comment as done.May 29 2020, 5:59 AM
grimar added inline comments.
llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
25

.nobits.2 isn't in any segment, so I think this test case isn't quite right. .nobits.2 needs to be in the same segment as .nobits.1, with a non-nobits segment in between.

Well. I think it is reasonable to have both then. I'll add "Case D" with the scenario you described.

Also, I think you need a test-case for two trailing .nobits sections to show neither has file space allocated.

We need to land D78005 first (which is on hold, waits for this one) to do something like this.
We have the issue with the calculation of segment size in this case.

grimar updated this revision to Diff 267217.May 29 2020, 6:24 AM
grimar marked 3 inline comments as done.
  • Addressed review comments.
MaskRay added inline comments.May 29 2020, 10:37 AM
llvm/lib/ObjectYAML/ELFEmitter.cpp
1094

Inlining does seem shorter:)

Another thing about the previous approach: the worst case time complexity did not change but allocating vector worsened the expected time complexity (SHT_NOBITS is usually followed by a non-SHT_NOBITS) I know that in some places we have quadratic complexity but introducing a new one when it can be easily avoided is not very great.

1103

This comment should mention that this behavior matches linkers.

llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
115

Is -NEXT: applicable?

jhenderson accepted this revision.Jun 1 2020, 12:41 AM

LGTM, with nits and @MaskRay's comments addressed.

llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
101

a one -> one

106

Here and above, it's slightly offputting seeing a mixture of short and long options. I'd either go one or the other (i.e. -S -l or --sections --segments).

This revision is now accepted and ready to land.Jun 1 2020, 12:41 AM
grimar updated this revision to Diff 267574.Jun 1 2020, 3:40 AM
grimar marked 9 inline comments as done.
  • Addressed review comments.
llvm/lib/ObjectYAML/ELFEmitter.cpp
1094

Not sure I understood this point. A SHT_NOBITS section is often followed by a non-allocatable non-SHT_NOBITS (e.g. .comment might follow .bss), but the previous version returned getChunksAfter for a given program header. We usually include only allocatable sections to a PT_LOADs (which might contain a SHT_NOBITS section normally), so in 99% cases the returned vector was just empty I believe.

So. I believe that shorter code was the only real (but important one) benefit here.

llvm/test/tools/yaml2obj/ELF/program-header-nobits.yaml
106

I've used the long version.

115

Yes. Done.

This revision was automatically updated to reflect the committed changes.

This is causing the 32-bit ARM bots to fail test tools/obj2yaml/ELF/program-headers.yaml. It looks like an out of memory error, but it has been happening consistently for a large number of builds now, and looks related to this change.

First failing build: http://lab.llvm.org:8011/builders/clang-cmake-armv7-quick/builds/16765

Log:

******************** TEST 'LLVM :: tools/obj2yaml/ELF/program-headers.yaml' FAILED ********************
Script:
--
: 'RUN: at line 5';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp1
: 'RUN: at line 9';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/llvm-readelf --segments /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp1 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=SEGMENT-MAPPING
: 'RUN: at line 37';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp1 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=YAML
: 'RUN: at line 241';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=2 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp2
: 'RUN: at line 242';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp2 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=EMPTY
: 'RUN: at line 331';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=3 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp3
: 'RUN: at line 332';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/llvm-readelf --segments --sections /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp3 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=MISALIGNED-READELF
: 'RUN: at line 333';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp3 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=MISALIGNED-YAML
: 'RUN: at line 373';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=4 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp4
: 'RUN: at line 374';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp4 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=NON-ALLOC
: 'RUN: at line 419';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=5 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp5
: 'RUN: at line 420';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp5 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=NOBITS
: 'RUN: at line 523';   not /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=6 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp6 2>&1 |    /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=UNSORTED --implicit-check-not="error:"
: 'RUN: at line 579';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=7 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp7
: 'RUN: at line 587';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/llvm-readelf -sections /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp7 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=ZERO-SIZE-MAPPING
: 'RUN: at line 597';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp7 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=ZERO-SIZE
: 'RUN: at line 648';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=8 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp8
: 'RUN: at line 649';   /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/obj2yaml /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp8 | /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/FileCheck /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml --check-prefix=BROKEN-VA
--
Exit Code: 134

Command Output (stderr):
--
LLVM ERROR: out of memory
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
Stack dump:
0.	Program arguments: /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=5 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp5 
/home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.script: line 18: 41905 Aborted                 (core dumped) /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/bin/yaml2obj --docnum=5 /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/llvm/llvm/test/tools/obj2yaml/ELF/program-headers.yaml -o /home/tcwg-buildslave/worker/clang-cmake-armv7-quick/stage1/test/tools/obj2yaml/ELF/Output/program-headers.yaml.tmp5

--

********************
grimar added a comment.Jun 4 2020, 3:06 AM

@ostannard, yes, sorry for the breakage. It happens because program-headers.yaml has a test that tries to produce a >4Gb object with this patch.
I am working on a fix. For now, I'll revert this.

grimar reopened this revision.Jun 4 2020, 3:19 AM
This revision is now accepted and ready to land.Jun 4 2020, 3:19 AM
grimar updated this revision to Diff 269817.EditedJun 10 2020, 6:20 AM
  • Updated tools/obj2yaml/ELF/program-headers.yaml.

Now when we have a 10 MB limitation of the output size produced by yaml2obj,
the obj2yaml/ELF/program-headers.yaml test fails.

It has the following case:

  - Name:  .bss
    Type:  SHT_NOBITS
    Flags: [ SHF_WRITE, SHF_ALLOC ]
## Use a size that is larger than the file size.
    Size: 0x00000000FFFFFFFF

With this patch we allocate the file space for it. And
the size value is very large. I've changed the "Size" key to "ShSize" which
just overrides the value of sh_size. It keeps the logic of this test case
untouched and fixes the issue.

This revision is now accepted and ready to land.Jun 10 2020, 6:20 AM
grimar requested review of this revision.Jun 10 2020, 6:20 AM
MaskRay accepted this revision.Jun 10 2020, 8:14 AM

Looks great!

This revision is now accepted and ready to land.Jun 10 2020, 8:14 AM
jhenderson requested changes to this revision.Jun 10 2020, 11:58 PM
jhenderson added inline comments.
llvm/test/tools/obj2yaml/ELF/program-headers.yaml
499–500

Looking at this test, I'm not convinced this is the right fix for the test. My impression is that this test is supposed to be about how segments are created and their file and memory sizes calculated. By using ShSize instead of Size, we are effectively saying (in theory) "ignore the size of this section for segment calculations" when I think what is meant is to ignore it for the calculation of the file size.

I think we need to properly change this test to use a real Size value here, just much smaller than what was chosen previously. Alternatively, we probably don't need this set of tests (nobits + segments) here at all, since we have the new tests you added that highlighted the bug of not allocating file space for nobits sections.

This revision now requires changes to proceed.Jun 10 2020, 11:58 PM
grimar marked an inline comment as done.Jun 11 2020, 12:51 AM
grimar added inline comments.
llvm/test/tools/obj2yaml/ELF/program-headers.yaml
499–500

My impression is that this test is supposed to be about how segments are created and their file and memory sizes calculated.

This is obj2yaml test. It is about how segments are dumped. This change does not change the original behavior, which is described as
"Use a size that is larger than the file size.", i.e. it checks how we dump such situation.

I think we need to properly change this test to use a real Size value here, just much smaller than what was chosen previously.

It just will break the original intention ("Use a size that is larger than the file size.").

jhenderson accepted this revision.Jun 11 2020, 1:20 AM

LGTM.

llvm/test/tools/obj2yaml/ELF/program-headers.yaml
499–500

Oh, I missed that this is an obj2yaml test and not a yaml2obj one, thanks.

This revision is now accepted and ready to land.Jun 11 2020, 1:20 AM
This revision was automatically updated to reflect the committed changes.