Add COFF objects whose .bss has no bytes in the file - #184
Conversation
ad219a1 to
2b03694
Compare
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS Validation record for head
Correcting the recorded command, not the fixture. An earlier line here said Correcting the survey total, 2026-09-06. That survey first reported 731,580 objects. It listed The message of commit Merge order. This commit introduces the conflict with angr/binaries 223, and did not inherit it: Caveats: no test was run here; the regressions that consume these objects live in angr/cle#764. The rebuild used the workspace's pinned toolchain, so it shows the recipe is faithful rather than that any gcc 15.3.0 build reproduces it. |
|
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS The three objects read back with cle at master ( the reproducerimport os
import struct
import cle
BIN = os.environ["BINARIES"]
for name in ("coff_bss.obj", "coff_huge_bss.obj", "coff_bss_no_flag.obj"):
path = os.path.join(BIN, "tests", "x86", name)
print(f"== {name}")
try:
data = open(path, "rb").read()
except FileNotFoundError as error:
print(f" {type(error).__name__}: {error}")
continue
print(f" file size: {len(data)} bytes")
machine, nsec, _, _, _, optsz, _ = struct.unpack_from("<HHLLLHH", data, 0)
print(" raw COFF section headers (name, SizeOfRawData, PointerToRawData, uninit flag):")
for i in range(nsec):
sec = struct.unpack_from("<8sLLLLLLHHL", data, 20 + optsz + 40 * i)
print(f" {sec[0].rstrip(chr(0).encode()).decode('latin1'):<10} "
f"SizeOfRawData {sec[3]:#010x} PointerToRawData {sec[4]:#010x} "
f"{'uninit' if sec[9] & 0x80 else ' -- '}")
ld = cle.Loader(path, main_opts={"backend": "COFF"})
print(" cle places them at:")
for s in ld.main_object.sections:
print(f" {s.name:<10} vaddr {s.vaddr:#010x} memsize {s.memsize:#010x}")Before — none of the three is in the repository: angr/binaries at
|
A COFF section holding no bytes in the file states PointerToRawData 0 while SizeOfRawData still states its length. No object here has one: both fauxware.obj builds put every section in the file and the hand-assembled coff_*.obj fixtures have no .bss, so cle's COFF loader has nothing to test that placement against. tests/x86/coff_bss.obj is 580 bytes with a 0x1000-byte .bss and a 0x40-byte .text at file offset 0xb4, so the .bss spans the file header and the whole of .text. tests_src/coff/coff_bss.c is the source and records the command. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2b03694 to
1a11cbb
Compare
Brings the branch up to date with master so cle pull requests that resolve this branch also get the mipsn32, ppc64, riscv64 UEFI and s390x fixtures their tests load. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
SizeOfRawData is 32 bits wide, and for a section with no bytes in the file nothing else in the file bounds it. coff_bss.obj states 0x1000 bytes, which a loader can honour. Before this commit nothing here stated a size the file cannot stand behind, and nothing had a section with no bytes in the file that does not claim to be uninitialized data -- the two shapes a loader has to tell apart. tests/x86/coff_huge_bss.obj is 580 bytes and its .bss states 0x20000000 at PointerToRawData 0: half a gigabyte of zero fill asked for by a file of a few hundred bytes. tests_src/coff/coff_huge_bss.c is coff_bss.c with a buffer 0x20000 times the size and the matching index mask, built by the same command line, so the two objects differ in 20 bytes. tests/x86/coff_bss_no_flag.obj is 120 bytes and states PointerToRawData 0 with SizeOfRawData 0x4000000 while marking itself code rather than uninitialized data. A survey of 731,580 COFF objects found 1,480 sections with no bytes in the file and every one sets the uninitialized-data flag, so this shape is assembled by build_coff_objects.py, whose docstring now names it alongside the others it owns. Its writer gained one optional section argument to express a section that states a size it does not carry; the six objects it already owned rebuild byte for byte. coff_bss.c's recorded command was missing -fzero-call-used-regs=used-gpr, so it rebuilt to 9e1199e7... rather than the committed 8794bf26.... The command is corrected here; the object is unchanged and was always reproducible from the compiler the comment names. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
cle's tests on master now load tests/aarch64/langdetect_go.macho and tests/aarch64/relocatable_object.macho, which #193 and #224 added after this branch was cut. angr/cle#764 and angr/cle#804 name this pull request in their sync: lines, so CI checks this branch out instead of master; once either is rebased onto current cle master those two files would be missing and the macOS job would fail. Merging master in supplies them and leaves this branch's own three objects and build script untouched.
THIS MESSAGE WAS GENERATED BY AN AUTOMATED PROCESS
Problem
A COFF section that holds no bytes in the file states
PointerToRawData0 andstill states its length in
SizeOfRawData. No object here has one. Scanning thefiles tracked under
tests/at this pull request's merge base finds 8 COFFobjects and 0 sections shaped that way: both
fauxware.objbuilds put everysection in the file, and the hand-assembled
coff_*.objfixtures have no.bssat all. So there is nothing here to test that placement against, nothing to test a
bound against --
SizeOfRawDatais 32 bits wide and, for a section with no bytesin the file, nothing else in the file bounds it -- and nothing to test the
distinction the format draws between a section that claims to be uninitialized
data and one that does not.
Root cause
The existing COFF objects were added for symbol and relocation coverage and were
compiled from sources with no uninitialised data, so the zero-offset section shape
never entered the repository at all.
Fix
Three objects, so the same scan at this head finds 11 COFF objects and 3 such
sections, two with
IMAGE_SCN_CNT_UNINITIALIZED_DATAset and one with it clear.tests/x86/coff_bss.obj, 580 bytes,.bssSizeOfRawData0x1000atPointerToRawData0 with the flag set -- larger than the whole file, so the span aloader gives it covers the file header and the whole of
.text.tests/x86/coff_huge_bss.obj, 580 bytes, the same object with.bssstating0x20000000: half a gigabyte of zero-filled space asked for by a file of a fewhundred bytes.
tests/x86/coff_bss_no_flag.obj, 120 bytes, statesPointerToRawData0 withSizeOfRawData0x4000000while its characteristics mark it code rather thanuninitialized data. It is hand-assembled: a survey of 731,573 COFF objects found
1,480 sections with no bytes in the file and every one of them sets the
uninitialized-data flag, so nothing there produced this shape.
tests_src/coff/coff_bss.candcoff_huge_bss.care the sources for the firsttwo; the second is the first with a buffer 0x20000 times the size and the matching
index mask, under a header comment of its own. Both are built by the same
i686-w64-mingw32-gccline and both rebuild byte for byte from it. That line iscorrected here: it was missing
-fzero-call-used-regs=used-gpr, so as recorded itproduced a different object. The committed
coff_bss.objis unchanged and alwayswas reproducible from the compiler its comment names.
coff_bss_no_flag.objcomes fromtests_src/coff/build_coff_objects.py, whosedocstring now names this shape beside the others it owns, and whose writer gained
one optional section argument to express a section that states a size it does not
carry. The six objects that script already owned rebuild byte for byte.
Testing
Read back with cle at master, all three load through the
COFFbackend asX86and each
.bssis given a span starting at the image base, over.text:[0x400000, 0x401000)for the first,[0x400000, 0x20400000)for the second outof a 580-byte file, and
[0x400000, 0x4400000)for the third out of 120 bytes.angr/cle#764 consumes all three, one test per object, and those tests cannot run
without them.
This commit introduces a conflict with binaries 223: the two heads merged clean
before it, and now collide in one place, the module docstring of
build_coff_objects.py, where both pull requests describe what the scriptassembles. Every code hunk merges clean -- both builder functions and both
OBJECTSentries. 223 rewrites that paragraph into two, so the resolution is totake its two paragraphs and carry this clause into the first, not to concatenate
the two versions. Land 223 first and rebase this over it.
Validation: #184 (comment)
session: sharpen