run.sh (50636B)
1 #!/bin/sh 2 # Driver-level checks for the byte-utility tools: xxd, cmp, hash, disas, mc, 3 # compress. 4 # Self-checking (no golden files): round-trips and known encodings/digests are 5 # asserted inline via the shared kit_* verbs (ok/run_ok/run_fail/contains/ 6 # same_file) recorded over $work. 7 8 set -u 9 10 script_dir=$(cd "$(dirname "$0")" && pwd) 11 repo_root=$(cd "$script_dir/../.." && pwd) 12 13 KIT="${KIT:-$repo_root/build/kit}" 14 15 if [ ! -x "$KIT" ]; then 16 echo "tools: kit binary not found at $KIT" >&2 17 exit 2 18 fi 19 20 work=$(mktemp -d "${TMPDIR:-/tmp}/kit-tools-test.XXXXXX") 21 trap 'rm -rf "$work"' EXIT 22 23 KIT_KIT_DIR="$repo_root/test/lib" 24 . "$repo_root/test/lib/kit_sh_kit.sh" 25 kit_report_init 26 27 expect_status() { # WANT NAME COMMAND... 28 es_want=$1 29 es_name=$2 30 shift 2 31 "$@" > "$work/$es_name.out" 2> "$work/$es_name.err" 32 es_got=$? 33 if [ "$es_got" -eq "$es_want" ]; then 34 ok "$es_name" 35 else 36 printf 'wanted %s, got %s\n' "$es_want" "$es_got" > "$work/$es_name.diag" 37 cat "$work/$es_name.err" >> "$work/$es_name.diag" 38 not_ok "$es_name" "$work/$es_name.diag" 39 fi 40 } 41 42 # A fixture with text, newlines, NUL and high bytes — exercises the ASCII 43 # column and binary round-tripping. 44 printf 'Hello, kit!\nLine two.\n\000\001\377\376' > "$work/data.bin" 45 46 # ---- xxd ------------------------------------------------------------------- 47 "$KIT" xxd "$work/data.bin" > "$work/dump.txt" 2> "$work/xxd.err" 48 "$KIT" xxd -r "$work/dump.txt" > "$work/rt.bin" 2>> "$work/xxd.err" 49 same_file xxd-roundtrip "$work/data.bin" "$work/rt.bin" 50 51 "$KIT" xxd -p "$work/data.bin" > "$work/p.txt" 2>> "$work/xxd.err" 52 "$KIT" xxd -r -p "$work/p.txt" > "$work/rtp.bin" 2>> "$work/xxd.err" 53 same_file xxd-plain-roundtrip "$work/data.bin" "$work/rtp.bin" 54 55 "$KIT" xxd -i "$work/data.bin" > "$work/inc.txt" 2>> "$work/xxd.err" 56 contains xxd-include-array "$work/inc.txt" "unsigned char" 57 contains xxd-include-len "$work/inc.txt" "_len = 26" 58 59 # ---- cmp ------------------------------------------------------------------- 60 cp "$work/data.bin" "$work/data2.bin" 61 run_ok cmp-identical "$KIT" cmp "$work/data.bin" "$work/data2.bin" 62 63 printf 'Hello, kit!\nLine TWO.\n\000\001\377\376' > "$work/diff.bin" 64 run_fail cmp-differ-exit "$KIT" cmp "$work/data.bin" "$work/diff.bin" 65 "$KIT" cmp "$work/data.bin" "$work/diff.bin" > "$work/cmp.out" 2>&1 66 contains cmp-differ-message "$work/cmp.out" "differ: char" 67 run_fail cmp-silent-exit "$KIT" cmp -s "$work/data.bin" "$work/diff.bin" 68 69 # GNU-compatible count/skip spellings, checked overflow, -- paths, and the 70 # operational-vs-usage status split. 71 printf 'abc' > "$work/cmp-short" 72 printf 'zabcX' > "$work/cmp-prefixed" 73 run_ok cmp-ignore-initial-long "$KIT" cmp --ignore-initial=0:1 --bytes=3 \ 74 "$work/cmp-short" "$work/cmp-prefixed" 75 run_ok cmp-ignore-initial-short "$KIT" cmp -i0:1 -n3 \ 76 "$work/cmp-short" "$work/cmp-prefixed" 77 expect_status 1 cmp-missing-operational "$KIT" cmp "$work/missing" \ 78 "$work/cmp-short" 79 expect_status 1 cmp-silent-missing-operational "$KIT" cmp -s \ 80 "$work/missing" "$work/cmp-short" 81 contains cmp-silent-missing-diagnostic \ 82 "$work/cmp-silent-missing-operational.err" "failed to read" 83 if [ ! -s "$work/cmp-silent-missing-operational.out" ]; then 84 ok cmp-silent-missing-stdout-empty 85 else 86 not_ok cmp-silent-missing-stdout-empty \ 87 "$work/cmp-silent-missing-operational.out" 88 fi 89 expect_status 2 cmp-count-overflow "$KIT" cmp --bytes=18446744073709551616 \ 90 "$work/cmp-short" "$work/cmp-short" 91 cp "$work/cmp-short" "$work/-cmp-input" 92 (cd "$work" && "$KIT" cmp -- -cmp-input cmp-short) \ 93 > "$work/cmp-dash.out" 2> "$work/cmp-dash.err" 94 if [ "$?" -eq 0 ]; then ok cmp-double-dash; else 95 not_ok cmp-double-dash "$work/cmp-dash.err" 96 fi 97 98 # ---- hash (CLI smoke; vectors covered by the test-hash unit test) ---------- 99 printf '123456789' > "$work/crc.in" 100 "$KIT" hash -a crc32 "$work/crc.in" > "$work/crc.out" 2>&1 101 contains hash-crc32 "$work/crc.out" "cbf43926" 102 printf 'abc' | "$KIT" hash -a sha256 > "$work/sha.out" 2>&1 103 contains hash-sha256 "$work/sha.out" \ 104 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" 105 106 # Standard-named aliases pin the algorithm and match `hash -a` exactly. 107 printf 'abc' | "$KIT" sha256sum > "$work/sha256sum.out" 2>&1 108 contains alias-sha256sum "$work/sha256sum.out" \ 109 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad -" 110 printf 'abc' | "$KIT" b2sum > "$work/b2sum.out" 2>&1 111 printf 'abc' | "$KIT" hash -a blake2b > "$work/b2ref.out" 2>&1 112 same_file alias-b2sum-matches-hash "$work/b2sum.out" "$work/b2ref.out" 113 "$KIT" crc32 "$work/crc.in" > "$work/crc32.out" 2>&1 114 contains alias-crc32 "$work/crc32.out" "cbf43926" 115 # A pinned alias rejects -a (its algorithm is fixed). 116 run_fail alias-sha256sum-no-a "$KIT" sha256sum -a blake2b "$work/crc.in" 117 118 # Check manifests use the same generic hashing path, enforce exact 256-bit 119 # widths, and preserve the 0/1/2 contract. 120 printf 'manifest payload\n' > "$work/check payload.bin" 121 "$KIT" sha256sum "$work/check payload.bin" > "$work/sha256.manifest" 122 expect_status 0 sha256-check-ok "$KIT" sha256sum -c "$work/sha256.manifest" 123 contains sha256-check-ok-row "$work/sha256-check-ok.out" ": OK" 124 expect_status 0 sha256-check-manifest-stdin sh -c \ 125 '"$1" sha256sum -c - < "$2"' sh "$KIT" "$work/sha256.manifest" 126 sed 's/ / */' "$work/sha256.manifest" > "$work/sha256.binary.manifest" 127 expect_status 0 sha256-check-binary-mode "$KIT" sha256sum -c \ 128 "$work/sha256.binary.manifest" 129 expect_status 0 sha256-check-quiet "$KIT" sha256sum -c --quiet \ 130 "$work/sha256.manifest" 131 if [ ! -s "$work/sha256-check-quiet.out" ]; then ok sha256-check-quiet-empty; 132 else not_ok sha256-check-quiet-empty "$work/sha256-check-quiet.out"; fi 133 printf 'changed\n' > "$work/check payload.bin" 134 expect_status 1 sha256-check-mismatch "$KIT" sha256sum --check \ 135 "$work/sha256.manifest" 136 contains sha256-check-failed-row "$work/sha256-check-mismatch.out" ": FAILED" 137 expect_status 1 sha256-check-status "$KIT" sha256sum -c --status \ 138 "$work/sha256.manifest" 139 if [ ! -s "$work/sha256-check-status.out" ]; then ok sha256-check-status-empty; 140 else not_ok sha256-check-status-empty "$work/sha256-check-status.out"; fi 141 printf 'not a manifest\n' > "$work/malformed.manifest" 142 expect_status 1 sha256-check-malformed "$KIT" sha256sum -c \ 143 "$work/malformed.manifest" 144 printf '%063d %s\n' 0 "$work/check payload.bin" > "$work/short.manifest" 145 expect_status 1 sha256-check-exact-width "$KIT" sha256sum -c \ 146 "$work/short.manifest" 147 sed 's#check payload\.bin#missing-payload.bin#' "$work/sha256.manifest" \ 148 > "$work/unreadable.manifest" 149 expect_status 1 sha256-check-unreadable "$KIT" sha256sum -c \ 150 "$work/unreadable.manifest" 151 expect_status 2 crc32-check-rejected "$KIT" crc32 -c "$work/sha256.manifest" 152 153 printf 'manifest payload\n' > "$work/check payload.bin" 154 "$KIT" b2sum "$work/check payload.bin" > "$work/b2.manifest" 155 expect_status 0 b2-check-ok "$KIT" b2sum -c "$work/b2.manifest" 156 printf '%0128d %s\n' 0 "$work/check payload.bin" > "$work/b2-512.manifest" 157 expect_status 1 b2-check-reject-512 "$KIT" b2sum -c "$work/b2-512.manifest" 158 contains b2-check-reject-512-message "$work/b2-check-reject-512.err" \ 159 "BLAKE2b-512 manifest is incompatible" 160 161 sha_stdin=$("$KIT" sha256sum "$work/check payload.bin" | sed 's/ .*//') 162 printf '%s -\n' "$sha_stdin" > "$work/stdin.manifest" 163 expect_status 1 sha256-check-dual-stdin sh -c \ 164 '"$1" sha256sum -c - < "$2"' sh "$KIT" "$work/stdin.manifest" 165 contains sha256-check-dual-message "$work/sha256-check-dual-stdin.err" \ 166 "manifest and payload cannot both read standard input" 167 168 # Installed multicall aliases exercise argv[0] routing as well as `kit TOOL`. 169 ln -s "$KIT" "$work/sha256sum" 170 expect_status 0 sha256-check-installed "$work/sha256sum" -c \ 171 "$work/sha256.manifest" 172 173 # Shared bounded suggestions stay on stderr, retain usage status, and never 174 # autocorrect the input. 175 expect_status 2 suggest-command "$KIT" objdmp 176 contains suggest-command-value "$work/suggest-command.err" "did you mean 'objdump'" 177 if [ ! -s "$work/suggest-command.out" ]; then ok suggest-command-stdout-empty; 178 else not_ok suggest-command-stdout-empty "$work/suggest-command.out"; fi 179 expect_status 2 suggest-cc-option "$KIT" cc --hlep 180 contains suggest-cc-option-value "$work/suggest-cc-option.err" "did you mean '--help'" 181 expect_status 2 suggest-target "$KIT" cc -target aarch65-none-elf -c missing.c 182 contains suggest-target-value "$work/suggest-target.err" "did you mean" 183 expect_status 2 suggest-target-discovery "$KIT" cc -target aardvark-none-elf \ 184 -c missing.c 185 contains suggest-target-discovery-value "$work/suggest-target-discovery.err" \ 186 "kit targets" 187 expect_status 2 suggest-language "$KIT" build-obj -x see missing.c 188 contains suggest-language-value "$work/suggest-language.err" "did you mean" 189 190 # Canonical version output and all help routes agree; version remains internal 191 # (the install aliases are tested by the install suite). 192 "$KIT" --version > "$work/version-top" 193 "$KIT" version > "$work/version-command" 194 same_file version-command-identical "$work/version-top" "$work/version-command" 195 expect_status 0 version-help-route "$KIT" help version 196 expect_status 0 version-short-help "$KIT" version -h 197 expect_status 0 version-long-help "$KIT" version --help 198 expect_status 2 version-not-installable "$KIT" install \ 199 "$work/version aliases" version 200 if [ ! -e "$work/version aliases/version" ]; then ok version-alias-absent; 201 else not_ok version-alias-absent; fi 202 203 # Raw assembler stdin uses a stable synthetic source name. Exercise direct and 204 # installed argv[0] dispatch, plus `--` for a leading-dash source pathname. 205 run_ok conventional-install-aliases "$KIT" install \ 206 "$work/tool aliases" as cc 207 mkdir -p "$work/dash paths" 208 printf '.text\n.globl _start\n_start:\n ret\n' | \ 209 "$KIT" as -target x86_64-none-elf -o "$work/stdin-direct.o" - \ 210 > "$work/as-stdin-direct.out" 2> "$work/as-stdin-direct.err" 211 if [ "$?" -eq 0 ]; then ok as-stdin-direct; else 212 not_ok as-stdin-direct "$work/as-stdin-direct.err" 213 fi 214 printf '.text\n.globl _start\n_start:\n ret\n' | \ 215 "$work/tool aliases/as" -target x86_64-none-elf \ 216 -o "$work/stdin-alias.o" - \ 217 > "$work/as-stdin-alias.out" 2> "$work/as-stdin-alias.err" 218 if [ "$?" -eq 0 ]; then ok as-stdin-installed; else 219 not_ok as-stdin-installed "$work/as-stdin-alias.err" 220 fi 221 same_file as-stdin-direct-installed "$work/stdin-direct.o" \ 222 "$work/stdin-alias.o" 223 printf 'definitely_not_an_instruction\n' | \ 224 "$KIT" as -target x86_64-none-elf -o "$work/stdin-bad.o" - \ 225 > "$work/as-stdin-bad.out" 2> "$work/as-stdin-bad.err" 226 as_bad_rc=$? 227 if [ "$as_bad_rc" -eq 1 ]; then ok as-stdin-error-status; else 228 printf 'status=%s\n' "$as_bad_rc" > "$work/as-stdin-bad.diag" 229 not_ok as-stdin-error-status "$work/as-stdin-bad.diag" 230 fi 231 contains as-stdin-diagnostic-name "$work/as-stdin-bad.err" "<stdin>" 232 printf '.text\n.globl dash_source\ndash_source:\n ret\n' \ 233 > "$work/dash paths/-source.s" 234 (cd "$work/dash paths" && "$KIT" as -target x86_64-none-elf \ 235 -o dash-source.o -- -source.s) \ 236 > "$work/as-dash.out" 2> "$work/as-dash.err" 237 if [ "$?" -eq 0 ]; then ok as-double-dash; else 238 not_ok as-double-dash "$work/as-dash.err" 239 fi 240 241 # Every supported compiler-to-linker spelling must produce the same linked 242 # image. The script lives at a path containing spaces and a leading-dash 243 # basename so comma forwarding and argv pairing are both exercised. 244 mkdir -p "$work/link scripts" 245 link_script="$work/link scripts/-layout script.lds" 246 cat > "$link_script" <<'EOF' 247 ENTRY(_start) 248 SECTIONS { 249 . = 0x10000; 250 .text : ALIGN(1) { *(.text .text.*) } 251 /DISCARD/ : { *(.note.*) *(.comment) *(.eh_frame) } 252 } 253 EOF 254 link_common='-target x86_64-none-elf -nostdlib -static -no-pie' 255 # shellcheck disable=SC2086 -- intentionally expand the fixed common argv. 256 run_ok link-flags-separate "$KIT" cc $link_common -T "$link_script" \ 257 -e _start "$work/stdin-direct.o" -o "$work/link-separate.elf" 258 # shellcheck disable=SC2086 259 run_ok link-flags-joined "$KIT" cc $link_common -T"$link_script" \ 260 -e_start "$work/stdin-direct.o" -o "$work/link-joined.elf" 261 # shellcheck disable=SC2086 262 run_ok link-flags-equal "$KIT" cc $link_common --script="$link_script" \ 263 --entry=_start "$work/stdin-direct.o" -o "$work/link-equal.elf" 264 # shellcheck disable=SC2086 265 run_ok link-flags-wl "$KIT" cc $link_common \ 266 "-Wl,-T,$link_script,-e,_start" "$work/stdin-direct.o" \ 267 -o "$work/link-wl.elf" 268 # shellcheck disable=SC2086 269 run_ok link-flags-xlinker "$KIT" cc $link_common \ 270 -Xlinker -T -Xlinker "$link_script" -Xlinker -e -Xlinker _start \ 271 "$work/stdin-direct.o" -o "$work/link-xlinker.elf" 272 # shellcheck disable=SC2086 273 run_ok link-flags-installed "$work/tool aliases/cc" $link_common \ 274 "-Wl,-T,$link_script,-e,_start" "$work/stdin-direct.o" \ 275 -o "$work/link-installed.elf" 276 for linked in joined equal wl xlinker installed; do 277 same_file "link-flags-identical-$linked" "$work/link-separate.elf" \ 278 "$work/link-$linked.elf" 279 done 280 281 # `--` is shared by the file-oriented byte utilities, including argv[0] 282 # multicall aliases and leading-dash paths in a directory containing spaces. 283 mkdir -p "$work/dash paths" 284 printf 'printable payload\n' > "$work/dash paths/-payload.bin" 285 (cd "$work/dash paths" && "$KIT" strings -- -payload.bin) \ 286 > "$work/strings-dash.out" 2> "$work/strings-dash.err" 287 contains strings-double-dash "$work/strings-dash.out" "printable payload" 288 ln -s "$KIT" "$work/strings" 289 (cd "$work/dash paths" && "$work/strings" -- -payload.bin) \ 290 > "$work/strings-alias-dash.out" 2> "$work/strings-alias-dash.err" 291 contains strings-alias-double-dash "$work/strings-alias-dash.out" \ 292 "printable payload" 293 (cd "$work/dash paths" && "$KIT" xxd -p -- -payload.bin) \ 294 > "$work/xxd-dash.out" 2> "$work/xxd-dash.err" 295 contains xxd-double-dash "$work/xxd-dash.out" "7072696e7461626c65207061796c6f6164" 296 printf '\303' > "$work/dash paths/-code.bin" 297 (cd "$work/dash paths" && "$KIT" disas -target x86_64 -- -code.bin) \ 298 > "$work/disas-dash.out" 2> "$work/disas-dash.err" 299 contains disas-double-dash "$work/disas-dash.out" "ret" 300 301 # ---- disas ----------------------------------------------------------------- 302 "$KIT" disas -target aarch64 -x "1f 20 03 d5" > "$work/d-aa64.out" 2>&1 303 contains disas-aa64-nop "$work/d-aa64.out" "nop" 304 "$KIT" disas -target x86_64 -x "c3" > "$work/d-x64.out" 2>&1 305 contains disas-x64-ret "$work/d-x64.out" "ret" 306 run_fail disas-bad-hex "$KIT" disas -target aarch64 -x "zz" 307 308 # ---- mc -------------------------------------------------------------------- 309 "$KIT" mc -target aarch64 "add x0, x1, x2" > "$work/mc.out" 2>&1 310 contains mc-aa64-encoding "$work/mc.out" "encoding: [0x20,0x00,0x02,0x8b]" 311 312 # mc -p (raw hex) piped back through disas must recover the mnemonic. 313 "$KIT" mc -target aarch64 -p "add x0, x1, x2" > "$work/mc.hex" 2>&1 314 "$KIT" disas -target aarch64 -x "$(cat "$work/mc.hex")" > "$work/mc-rt.out" 2>&1 315 contains mc-disas-roundtrip "$work/mc-rt.out" "add x0, x1, x2" 316 317 # A branch to an undefined symbol should surface a relocation, not an error. 318 "$KIT" mc -target aarch64 "b somewhere" > "$work/mc-rel.out" 2>&1 319 contains mc-reloc "$work/mc-rel.out" "reloc" 320 321 # ---- compress -------------------------------------------------------------- 322 # gzip + LZ4-frame round-trips (text, empty, binary), -o files, auto-detect, 323 # error exits, and interop with the system gzip/lz4 CLIs when present. 324 printf 'hello compression world\nthe quick brown fox jumps\n' > "$work/cz.txt" 325 : > "$work/cz.empty" 326 head -c 200000 "$KIT" > "$work/cz.bin" # a real, varied, deterministic blob 327 328 cz_roundtrip() { # FMT LABEL FILE : compress | decompress | compare original 329 "$KIT" compress -z "$1" "$3" 2> "$work/cz.err" \ 330 | "$KIT" compress -d 2>> "$work/cz.err" > "$work/cz.rt" 331 same_file "compress-roundtrip-$2" "$3" "$work/cz.rt" 332 } 333 for f in txt empty bin; do 334 cz_roundtrip gzip "gzip-$f" "$work/cz.$f" 335 cz_roundtrip lz4 "lz4-$f" "$work/cz.$f" 336 done 337 338 # File input + -o output, then decode. 339 "$KIT" compress -z gzip -o "$work/cz.gz" "$work/cz.txt" 340 "$KIT" compress -d -o "$work/cz.ungz" "$work/cz.gz" 341 same_file compress-file-out-gzip "$work/cz.txt" "$work/cz.ungz" 342 343 # Auto-detect on decompress (no -z) from the container magic bytes. 344 for fmt in gzip lz4; do 345 "$KIT" compress -z "$fmt" "$work/cz.txt" | "$KIT" compress -d > "$work/cz.det" 346 same_file "compress-autodetect-$fmt" "$work/cz.txt" "$work/cz.det" 347 done 348 349 # Default format is gzip. 350 "$KIT" compress "$work/cz.txt" | "$KIT" compress -d > "$work/cz.def" 351 same_file compress-default-gzip "$work/cz.txt" "$work/cz.def" 352 353 # Standard-named aliases: gzip/gunzip and lz4 round-trip through each other and 354 # through the generic tool; gunzip is just `compress -d` pinned to gzip. 355 "$KIT" gzip "$work/cz.txt" | "$KIT" gunzip > "$work/cz.gzalias" 356 same_file alias-gzip-gunzip "$work/cz.txt" "$work/cz.gzalias" 357 "$KIT" gzip "$work/cz.txt" | "$KIT" compress -d > "$work/cz.gz2generic" 358 same_file alias-gzip-to-generic "$work/cz.txt" "$work/cz.gz2generic" 359 "$KIT" lz4 "$work/cz.txt" | "$KIT" lz4 -d > "$work/cz.lz4alias" 360 same_file alias-lz4-roundtrip "$work/cz.txt" "$work/cz.lz4alias" 361 "$KIT" lz4c "$work/cz.txt" | "$KIT" lz4 -d > "$work/cz.lz4calias" 362 same_file alias-lz4c-roundtrip "$work/cz.txt" "$work/cz.lz4calias" 363 # gzip -d flips direction; the common gzip flags (-c, level -9) are no-ops. 364 "$KIT" gzip -9 -c "$work/cz.txt" | "$KIT" gzip -d > "$work/cz.compat" 365 same_file alias-gzip-compat-flags "$work/cz.txt" "$work/cz.compat" 366 # A pinned alias rejects -z, and gunzip will not auto-detect a foreign container. 367 run_fail alias-gzip-no-z "$KIT" gzip -z lz4 "$work/cz.txt" 368 "$KIT" lz4 "$work/cz.txt" > "$work/cz.lz4only" 369 run_fail alias-gunzip-wrong-format "$KIT" gunzip "$work/cz.lz4only" 370 371 # Error exits: bad format / two inputs / missing file all exit non-zero. 372 run_fail compress-err-bad-format "$KIT" compress -z bogus "$work/cz.txt" 373 expect_status 2 compress-format-suggestion "$KIT" compress -z gzi "$work/cz.txt" 374 contains compress-format-suggestion-value "$work/compress-format-suggestion.err" \ 375 "did you mean 'gzip'" 376 run_fail compress-err-two-inputs "$KIT" compress "$work/cz.txt" "$work/cz.empty" 377 run_fail compress-err-missing-file "$KIT" compress "$work/cz.nope" 378 if printf 'plain text not compressed' | "$KIT" compress -d >/dev/null 2>&1; then 379 not_ok compress-err-undetectable 380 else 381 ok compress-err-undetectable 382 fi 383 384 # Interop with the system tools, both directions; skip cleanly when absent. 385 if command -v gzip >/dev/null 2>&1 && command -v gunzip >/dev/null 2>&1; then 386 "$KIT" compress -z gzip "$work/cz.bin" | gunzip 2>/dev/null > "$work/cz.gunzip" 387 same_file compress-interop-kit-to-gunzip "$work/cz.bin" "$work/cz.gunzip" 388 gzip -c "$work/cz.bin" | "$KIT" compress -d > "$work/cz.fromgzip" 389 same_file compress-interop-gzip-to-kit "$work/cz.bin" "$work/cz.fromgzip" 390 else 391 kit_skip_na compress-interop-gzip "system gzip/gunzip not found" 392 fi 393 if command -v lz4 >/dev/null 2>&1; then 394 "$KIT" compress -z lz4 "$work/cz.bin" | lz4 -d 2>/dev/null > "$work/cz.unlz4" 395 same_file compress-interop-kit-to-lz4 "$work/cz.bin" "$work/cz.unlz4" 396 lz4 -c "$work/cz.bin" 2>/dev/null | "$KIT" compress -d > "$work/cz.fromlz4" 397 same_file compress-interop-lz4-to-kit "$work/cz.bin" "$work/cz.fromlz4" 398 else 399 kit_skip_na compress-interop-lz4 "system lz4 not found" 400 fi 401 402 # ---- image --------------------------------------------------------------- 403 expect_status 2 image-format-suggestion "$KIT" image --format bing missing.o 404 contains image-format-suggestion-value "$work/image-format-suggestion.err" \ 405 "did you mean 'bin'" 406 cat > "$work/kernel.s" <<'EOF' 407 .globl _start 408 .section .text 409 _start: 410 ret 411 .section .rodata 412 .byte 0x11, 0x22, 0x33, 0x44 413 EOF 414 415 run_ok image-build-elf "$KIT" build-exe -target x86_64-none-elf \ 416 -nostdlib -static -no-pie -e _start "$work/kernel.s" -o "$work/kernel.elf" 417 run_ok image-bin "$KIT" image --format bin "$work/kernel.elf" \ 418 -o "$work/kernel.bin" 419 cp "$work/kernel.elf" "$work/-kernel.elf" 420 (cd "$work" && "$KIT" image --format bin -o kernel.dash.bin -- -kernel.elf) \ 421 > "$work/image-dash.out" 2> "$work/image-dash.err" 422 if [ "$?" -eq 0 ]; then ok image-double-dash; else 423 not_ok image-double-dash "$work/image-dash.err" 424 fi 425 same_file image-double-dash-bytes "$work/kernel.bin" "$work/kernel.dash.bin" 426 cp "$work/kernel.elf" "$work/-size.elf" 427 (cd "$work" && "$KIT" size -- -size.elf) \ 428 > "$work/size-dash.out" 2> "$work/size-dash.err" 429 if [ "$?" -eq 0 ] && grep -q 'text' "$work/size-dash.out"; then 430 ok size-double-dash 431 else 432 not_ok size-double-dash "$work/size-dash.err" 433 fi 434 ln -s "$KIT" "$work/size" 435 (cd "$work" && ./size -- -size.elf) \ 436 > "$work/size-alias-dash.out" 2> "$work/size-alias-dash.err" 437 if [ "$?" -eq 0 ] && grep -q 'text' "$work/size-alias-dash.out"; then 438 ok size-alias-double-dash 439 else 440 not_ok size-alias-double-dash "$work/size-alias-dash.err" 441 fi 442 run_ok image-paddr "$KIT" image --format bin --addr paddr "$work/kernel.elf" \ 443 -o "$work/kernel.paddr.bin" 444 same_file image-paddr-matches-vaddr "$work/kernel.bin" "$work/kernel.paddr.bin" 445 run_ok objcopy-binary "$KIT" objcopy -O binary "$work/kernel.elf" \ 446 "$work/kernel.objcopy.bin" 447 same_file image-objcopy-binary "$work/kernel.bin" "$work/kernel.objcopy.bin" 448 449 # Linked Mach-O and PE inputs must take the loader-segment path. Keep the 450 # segment-selected output beside an explicitly section-selected output: the 451 # former includes loader-owned bytes/alignment and is therefore observably 452 # larger than the logical text section. Default objcopy raw output is required 453 # to agree byte-for-byte with the image command over the same linked image. 454 cat > "$work/linked-cross.c" <<'EOF' 455 volatile unsigned long linked_data = 0x11223344UL; 456 const unsigned char linked_rodata[] = { 0x55, 0x66, 0x77, 0x88 }; 457 void _start(void) { 458 linked_data += linked_rodata[0]; 459 for (;;) {} 460 } 461 EOF 462 463 run_ok image-linked-macho-build "$KIT" cc -target x86_64-macos \ 464 -ffreestanding -fno-stack-protector -nostdlib -Wl,-e,_start \ 465 "$work/linked-cross.c" -o "$work/linked.macho" 466 run_ok image-linked-macho "$KIT" image --format bin \ 467 --metadata "$work/linked.macho.json" "$work/linked.macho" \ 468 -o "$work/linked.macho.bin" 469 contains image-linked-macho-source "$work/linked.macho.json" \ 470 '"source": "segments"' 471 contains image-linked-macho-format "$work/linked.macho.json" \ 472 '"object_format": "macho"' 473 run_ok image-linked-macho-objcopy "$KIT" objcopy -O binary \ 474 "$work/linked.macho" "$work/linked.macho.objcopy.bin" 475 same_file image-linked-macho-objcopy-bytes "$work/linked.macho.bin" \ 476 "$work/linked.macho.objcopy.bin" 477 run_ok image-linked-macho-text-segment "$KIT" image --format bin \ 478 --segment __TEXT --metadata "$work/linked.macho.text.json" \ 479 "$work/linked.macho" -o "$work/linked.macho.text.bin" 480 contains image-linked-macho-text-selection "$work/linked.macho.text.json" \ 481 '"selection": ["__TEXT"]' 482 contains image-linked-macho-text-load-address \ 483 "$work/linked.macho.text.json" '"base_is_load_address": true' 484 run_ok image-linked-macho-text-section "$KIT" image --format bin \ 485 --only-section __TEXT,__text "$work/linked.macho" \ 486 -o "$work/linked.macho.section.bin" 487 macho_segment_size=$(wc -c < "$work/linked.macho.text.bin" | tr -d ' ') 488 macho_section_size=$(wc -c < "$work/linked.macho.section.bin" | tr -d ' ') 489 if [ "$macho_segment_size" -gt "$macho_section_size" ]; then 490 ok image-linked-macho-segment-span 491 else 492 printf 'segment=%s section=%s\n' "$macho_segment_size" \ 493 "$macho_section_size" > "$work/image-linked-macho-segment-span.diag" 494 not_ok image-linked-macho-segment-span \ 495 "$work/image-linked-macho-segment-span.diag" 496 fi 497 head -c 4 "$work/linked.macho.text.bin" > "$work/linked.macho.magic" 498 "$KIT" xxd -p "$work/linked.macho.magic" > "$work/linked.macho.magic.hex" 499 contains image-linked-macho-segment-header "$work/linked.macho.magic.hex" \ 500 "cffaedfe" 501 502 run_ok image-linked-pe-build "$KIT" cc -target x86_64-windows \ 503 -ffreestanding -fno-stack-protector -nostdlib -Wl,-e,_start \ 504 "$work/linked-cross.c" -o "$work/linked.exe" 505 run_ok image-linked-pe "$KIT" image --format bin \ 506 --metadata "$work/linked.pe.json" "$work/linked.exe" \ 507 -o "$work/linked.pe.bin" 508 contains image-linked-pe-source "$work/linked.pe.json" \ 509 '"source": "segments"' 510 contains image-linked-pe-format "$work/linked.pe.json" \ 511 '"object_format": "coff"' 512 run_ok image-linked-pe-objcopy "$KIT" objcopy -O binary \ 513 "$work/linked.exe" "$work/linked.pe.objcopy.bin" 514 same_file image-linked-pe-objcopy-bytes "$work/linked.pe.bin" \ 515 "$work/linked.pe.objcopy.bin" 516 run_ok image-linked-pe-text-segment "$KIT" image --format bin \ 517 --segment .text --metadata "$work/linked.pe.text.json" \ 518 "$work/linked.exe" -o "$work/linked.pe.text.bin" 519 contains image-linked-pe-text-selection "$work/linked.pe.text.json" \ 520 '"selection": [".text"]' 521 contains image-linked-pe-text-load-address "$work/linked.pe.text.json" \ 522 '"base_is_load_address": true' 523 run_ok image-linked-pe-text-section "$KIT" image --format bin \ 524 --only-section .text "$work/linked.exe" \ 525 -o "$work/linked.pe.section.bin" 526 pe_segment_size=$(wc -c < "$work/linked.pe.text.bin" | tr -d ' ') 527 pe_section_size=$(wc -c < "$work/linked.pe.section.bin" | tr -d ' ') 528 if [ "$pe_segment_size" -gt "$pe_section_size" ]; then 529 ok image-linked-pe-segment-span 530 else 531 printf 'segment=%s section=%s\n' "$pe_segment_size" \ 532 "$pe_section_size" > "$work/image-linked-pe-segment-span.diag" 533 not_ok image-linked-pe-segment-span \ 534 "$work/image-linked-pe-segment-span.diag" 535 fi 536 537 run_ok image-ihex "$KIT" image --format ihex "$work/kernel.elf" \ 538 -o "$work/kernel.hex" 539 run_ok objcopy-ihex "$KIT" objcopy -O ihex "$work/kernel.elf" \ 540 "$work/kernel.objcopy.hex" 541 same_file image-objcopy-ihex "$work/kernel.hex" "$work/kernel.objcopy.hex" 542 contains image-ihex-eof "$work/kernel.hex" ":00000001FF" 543 run_ok image-srec "$KIT" image --format srec "$work/kernel.elf" \ 544 -o "$work/kernel.srec" 545 run_ok objcopy-srec "$KIT" objcopy -O srec "$work/kernel.elf" \ 546 "$work/kernel.objcopy.srec" 547 same_file image-objcopy-srec "$work/kernel.srec" "$work/kernel.objcopy.srec" 548 contains image-srec-header "$work/kernel.srec" "S00600004B495411" 549 if [ -s "$work/kernel.bin" ]; then 550 ok image-bin-nonempty 551 else 552 not_ok image-bin-nonempty 553 fi 554 555 image_size=$(wc -c < "$work/kernel.bin" | tr -d ' ') 556 pad_size=$((image_size + 16)) 557 run_ok image-pad-fill "$KIT" image --format bin --pad-to "$pad_size" \ 558 --fill 0xaa "$work/kernel.elf" -o "$work/kernel.pad.bin" 559 pad_got=$(wc -c < "$work/kernel.pad.bin" | tr -d ' ') 560 if [ "$pad_got" = "$pad_size" ]; then 561 ok image-pad-size 562 else 563 echo "got $pad_got want $pad_size" > "$work/image-pad-size.diag" 564 not_ok image-pad-size "$work/image-pad-size.diag" 565 fi 566 tail -c 16 "$work/kernel.pad.bin" > "$work/kernel.pad.tail" 567 "$KIT" xxd -p "$work/kernel.pad.tail" > "$work/kernel.pad.hex" 568 contains image-pad-fill-byte "$work/kernel.pad.hex" \ 569 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 570 run_fail image-max-size "$KIT" image --format bin --max-size 1 \ 571 "$work/kernel.elf" -o "$work/kernel.too-small.bin" 572 573 # Text image formats must carry full 32-bit addresses. This fixture is placed 574 # above 16 MiB so Intel HEX needs a non-trivial extended-linear-address record; 575 # the checksum pins the full 16-bit high address (0x0102), not just its low byte. 576 cat > "$work/highaddr.s" <<'EOF' 577 .globl _start 578 .section .text 579 _start: 580 ret 581 .byte 0x11, 0x22, 0x33, 0x44 582 EOF 583 cat > "$work/highaddr.lds" <<'EOF' 584 ENTRY(_start) 585 SECTIONS { 586 . = 0x010203f0; 587 .text : ALIGN(1) { *(.text .text.*) } 588 /DISCARD/ : { *(.note.*) *(.comment) *(.eh_frame) } 589 } 590 EOF 591 run_ok image-text-high-build "$KIT" build-exe -target x86_64-none-elf \ 592 -nostdlib -static -no-pie -e _start -T "$work/highaddr.lds" \ 593 "$work/highaddr.s" -o "$work/highaddr.elf" 594 run_ok image-ihex-high "$KIT" image --format ihex "$work/highaddr.elf" \ 595 -o "$work/highaddr.hex" 596 contains image-ihex-high-ela "$work/highaddr.hex" ":020000040102F7" 597 run_ok objcopy-ihex-high "$KIT" objcopy -O ihex "$work/highaddr.elf" \ 598 "$work/highaddr.objcopy.hex" 599 same_file image-objcopy-ihex-high "$work/highaddr.hex" \ 600 "$work/highaddr.objcopy.hex" 601 run_ok image-srec-high "$KIT" image --format srec "$work/highaddr.elf" \ 602 -o "$work/highaddr.srec" 603 contains image-srec-high-address "$work/highaddr.srec" "010203F0" 604 run_ok objcopy-srec-high "$KIT" objcopy -O srec "$work/highaddr.elf" \ 605 "$work/highaddr.objcopy.srec" 606 same_file image-objcopy-srec-high "$work/highaddr.srec" \ 607 "$work/highaddr.objcopy.srec" 608 609 cat > "$work/over32.lds" <<'EOF' 610 ENTRY(_start) 611 SECTIONS { 612 . = 0x100010000; 613 .text : ALIGN(1) { *(.text .text.*) } 614 /DISCARD/ : { *(.note.*) *(.comment) *(.eh_frame) } 615 } 616 EOF 617 run_ok image-text-over32-build "$KIT" build-exe -target x86_64-none-elf \ 618 -nostdlib -static -no-pie -e _start -T "$work/over32.lds" \ 619 "$work/highaddr.s" -o "$work/over32.elf" 620 run_fail image-ihex-over32 "$KIT" image --format ihex "$work/over32.elf" \ 621 -o "$work/over32.hex" 622 run_fail image-srec-over32 "$KIT" image --format srec "$work/over32.elf" \ 623 -o "$work/over32.srec" 624 625 # A signed bias applies to records and the declared entry alike. Rebasing this 626 # image down by exactly 4 GiB makes both text formats representable; pin their 627 # entry records as well as the data-address path. 628 run_ok image-ihex-negative-bias "$KIT" image --format ihex \ 629 --bias -4294967296 --metadata "$work/biased.json" "$work/over32.elf" \ 630 -o "$work/biased.hex" 631 contains image-ihex-biased-ela "$work/biased.hex" ":020000040001F9" 632 contains image-ihex-biased-entry "$work/biased.hex" ":0400000500010000F6" 633 contains image-meta-original-base "$work/biased.json" \ 634 '"original_base": "0x100010000"' 635 contains image-meta-emitted-base "$work/biased.json" \ 636 '"emitted_base": "0x10000"' 637 contains image-meta-original-entry "$work/biased.json" \ 638 '"original_entry": "0x100010000"' 639 contains image-meta-emitted-entry "$work/biased.json" \ 640 '"emitted_entry": "0x10000"' 641 run_ok image-srec-negative-bias "$KIT" image --format srec \ 642 --bias -4294967296 "$work/over32.elf" -o "$work/biased.srec" 643 contains image-srec-biased-entry "$work/biased.srec" "S804010000FA" 644 expect_status 2 image-ihex-base-rejected "$KIT" image --format ihex \ 645 --base 0 "$work/highaddr.elf" -o "$work/base.hex" 646 contains image-ihex-base-hint "$work/image-ihex-base-rejected.err" \ 647 "rebase IHEX/SREC addresses" 648 run_fail image-negative-bias-underflow "$KIT" image --format ihex \ 649 --bias -9223372036854775808 "$work/kernel.elf" -o "$work/underflow.hex" 650 if [ ! -e "$work/underflow.hex" ]; then ok image-underflow-transaction; 651 else not_ok image-underflow-transaction "$work/underflow.hex"; fi 652 653 # The top 32-bit byte is representable; a two-byte range at the same address 654 # crosses the boundary and must fail before an output transaction commits. 655 cat > "$work/boundary.s" <<'EOF' 656 .globl _start 657 .section .text 658 _start: 659 ret 660 EOF 661 cat > "$work/boundary.lds" <<'EOF' 662 ENTRY(_start) 663 SECTIONS { 664 . = 0xffffffff; 665 .text : ALIGN(1) { *(.text .text.*) } 666 /DISCARD/ : { *(.note.*) *(.comment) *(.eh_frame) } 667 } 668 EOF 669 run_ok image-text-boundary-build "$KIT" build-exe -target x86_64-none-elf \ 670 -nostdlib -static -no-pie -e _start -T "$work/boundary.lds" \ 671 "$work/boundary.s" -o "$work/boundary.elf" 672 run_ok image-ihex-boundary "$KIT" image --format ihex "$work/boundary.elf" \ 673 -o "$work/boundary.hex" 674 contains image-ihex-boundary-entry "$work/boundary.hex" \ 675 ":04000005FFFFFFFFFB" 676 run_ok image-srec-boundary "$KIT" image --format srec "$work/boundary.elf" \ 677 -o "$work/boundary.srec" 678 contains image-srec-boundary-entry "$work/boundary.srec" "S705FFFFFFFFFE" 679 cat > "$work/boundary-cross.s" <<'EOF' 680 .globl _start 681 .section .text 682 _start: 683 ret 684 nop 685 EOF 686 run_ok image-text-boundary-cross-build "$KIT" build-exe \ 687 -target x86_64-none-elf -nostdlib -static -no-pie -e _start \ 688 -T "$work/boundary.lds" "$work/boundary-cross.s" \ 689 -o "$work/boundary-cross.elf" 690 run_fail image-ihex-boundary-cross "$KIT" image --format ihex \ 691 "$work/boundary-cross.elf" -o "$work/boundary-cross.hex" 692 run_fail image-srec-boundary-cross "$KIT" image --format srec \ 693 "$work/boundary-cross.elf" -o "$work/boundary-cross.srec" 694 if [ ! -e "$work/boundary-cross.hex" ] && \ 695 [ ! -e "$work/boundary-cross.srec" ]; then 696 ok image-boundary-cross-transaction 697 else 698 not_ok image-boundary-cross-transaction 699 fi 700 701 # Relocatable objects use allocated section contents. Sections retain their 702 # addresses, later selected overlaps win, filters apply before layout, and no 703 # synthetic entry record is invented. The same library path backs objcopy. 704 cat > "$work/raw-rel.s" <<'EOF' 705 .globl raw_entry 706 .section .text 707 raw_entry: 708 ret 709 .section .data 710 .byte 0x42 711 EOF 712 run_ok image-rel-build "$KIT" as -target x86_64-none-elf \ 713 "$work/raw-rel.s" -o "$work/raw-rel.o" 714 run_ok objcopy-rel-binary "$KIT" objcopy -O binary "$work/raw-rel.o" \ 715 "$work/raw-rel.bin" 716 "$KIT" xxd -p "$work/raw-rel.bin" > "$work/raw-rel.hexbytes" 717 contains image-rel-overlap-later-wins "$work/raw-rel.hexbytes" "42" 718 run_ok objcopy-rel-only-text "$KIT" objcopy --only-section .text -O binary \ 719 "$work/raw-rel.o" "$work/raw-rel.text.bin" 720 "$KIT" xxd -p "$work/raw-rel.text.bin" > "$work/raw-rel.text.hexbytes" 721 contains image-rel-only-text-byte "$work/raw-rel.text.hexbytes" "c3" 722 run_ok objcopy-rel-remove-data "$KIT" objcopy --remove-section .data \ 723 -O binary "$work/raw-rel.o" "$work/raw-rel.nodata.bin" 724 same_file image-rel-remove-matches-only "$work/raw-rel.text.bin" \ 725 "$work/raw-rel.nodata.bin" 726 run_ok objcopy-rel-ihex "$KIT" objcopy -O ihex "$work/raw-rel.o" \ 727 "$work/raw-rel.ihex" 728 if ! grep -q '^:04000005' "$work/raw-rel.ihex"; then 729 ok image-rel-ihex-no-entry 730 else 731 not_ok image-rel-ihex-no-entry "$work/raw-rel.ihex" 732 fi 733 run_ok objcopy-rel-srec "$KIT" objcopy -O srec "$work/raw-rel.o" \ 734 "$work/raw-rel.srec" 735 if ! grep -q '^S[789]' "$work/raw-rel.srec"; then 736 ok image-rel-srec-no-entry 737 else 738 not_ok image-rel-srec-no-entry "$work/raw-rel.srec" 739 fi 740 741 # Reject an unapplied relocation in a selected allocated section. 742 cat > "$work/raw-reloc.s" <<'EOF' 743 .globl raw_reloc 744 .section .text 745 raw_reloc: 746 call missing_target 747 EOF 748 run_ok image-reloc-build "$KIT" as -target x86_64-none-elf \ 749 "$work/raw-reloc.s" -o "$work/raw-reloc.o" 750 run_fail objcopy-reloc-rejected "$KIT" objcopy -O binary \ 751 "$work/raw-reloc.o" "$work/raw-reloc.bin" 752 if [ ! -e "$work/raw-reloc.bin" ]; then ok image-reloc-transaction; 753 else not_ok image-reloc-transaction "$work/raw-reloc.bin"; fi 754 755 # Object-format conversions remain format-neutral at the image API boundary. 756 run_ok image-rel-macho-build "$KIT" objcopy -O mach-o "$work/raw-rel.o" \ 757 "$work/raw-rel.macho" 758 run_ok image-rel-macho "$KIT" objcopy --only-section __TEXT,__text -O binary \ 759 "$work/raw-rel.macho" "$work/raw-rel.macho.bin" 760 same_file image-rel-macho-bytes "$work/raw-rel.text.bin" \ 761 "$work/raw-rel.macho.bin" 762 run_ok image-rel-coff-build "$KIT" objcopy -O coff "$work/raw-rel.o" \ 763 "$work/raw-rel.coff" 764 run_ok image-rel-coff "$KIT" objcopy --only-section .text -O binary \ 765 "$work/raw-rel.coff" "$work/raw-rel.coff.bin" 766 same_file image-rel-coff-bytes "$work/raw-rel.text.bin" \ 767 "$work/raw-rel.coff.bin" 768 run_ok image-rel-wasm "$KIT" objcopy --only-section code -O binary \ 769 "$repo_root/test/objdump/wasm/cases/add.wasm" "$work/raw-rel.wasm.bin" 770 if [ -s "$work/raw-rel.wasm.bin" ]; then ok image-rel-wasm-nonempty; 771 else not_ok image-rel-wasm-nonempty "$work/raw-rel.wasm.bin"; fi 772 773 # ---- image: --format sections --------------------------------------------- 774 # Concatenate named sections in DECLARED order. The fixture's .text is a lone 775 # `ret` (0xc3) and .rodata is 0x11223344, so the concatenation and its reverse 776 # are exact, checkable byte strings. 777 run_ok image-sections "$KIT" image --format sections \ 778 --section .text --section .rodata "$work/kernel.elf" -o "$work/sec.bin" 779 "$KIT" xxd -p "$work/sec.bin" > "$work/sec.hex" 780 contains image-sections-order "$work/sec.hex" "c311223344" 781 run_ok image-sections-rev "$KIT" image --format sections \ 782 --section .rodata --section .text "$work/kernel.elf" -o "$work/sec.rev.bin" 783 "$KIT" xxd -p "$work/sec.rev.bin" > "$work/sec.rev.hex" 784 contains image-sections-rev-order "$work/sec.rev.hex" "11223344c3" 785 # Determinism: same input + options twice is byte-identical. 786 run_ok image-sections-again "$KIT" image --format sections \ 787 --section .text --section .rodata "$work/kernel.elf" -o "$work/sec.again.bin" 788 same_file image-sections-deterministic "$work/sec.bin" "$work/sec.again.bin" 789 # A missing named section is a hard error. 790 run_fail image-sections-missing "$KIT" image --format sections \ 791 --section .nope "$work/kernel.elf" -o "$work/sec.miss.bin" 792 # --section is rejected for the plain bin format. 793 run_fail image-section-needs-format "$KIT" image --format bin \ 794 --section .text "$work/kernel.elf" -o "$work/sec.bad.bin" 795 796 # ---- image: --format rom -------------------------------------------------- 797 # ROM is a fixed-size flat binary; it requires an explicit --pad-to. Driving it 798 # from the 5-byte section concatenation gives a small, exact payload to pad. 799 run_fail image-rom-needs-size "$KIT" image --format rom \ 800 --section .text --section .rodata "$work/kernel.elf" -o "$work/rom.bad.bin" 801 run_ok image-rom "$KIT" image --format rom --section .text --section .rodata \ 802 --pad-to 16 --fill 0xff "$work/kernel.elf" -o "$work/rom.bin" 803 rom_got=$(wc -c < "$work/rom.bin" | tr -d ' ') 804 if [ "$rom_got" = "16" ]; then 805 ok image-rom-size 806 else 807 echo "got $rom_got want 16" > "$work/image-rom-size.diag" 808 not_ok image-rom-size "$work/image-rom-size.diag" 809 fi 810 "$KIT" xxd -p "$work/rom.bin" > "$work/rom.hex" 811 contains image-rom-payload-and-fill "$work/rom.hex" "c311223344ffffffffffffffffffffff" 812 # Determinism: identical bytes on a second run. 813 run_ok image-rom-again "$KIT" image --format rom --section .text \ 814 --section .rodata --pad-to 16 --fill 0xff "$work/kernel.elf" \ 815 -o "$work/rom.again.bin" 816 same_file image-rom-deterministic "$work/rom.bin" "$work/rom.again.bin" 817 # Payload larger than the requested size fails (5 payload bytes, pad-to 4). 818 run_fail image-rom-overflow "$KIT" image --format rom --section .text \ 819 --section .rodata --pad-to 4 "$work/kernel.elf" -o "$work/rom.of.bin" 820 821 # ---- image: --metadata sidecar -------------------------------------------- 822 # Deterministic JSON: stable keys, no host paths/timestamps. Assert presence, 823 # a few stable fields, and byte-identical re-emission. 824 run_ok image-metadata "$KIT" image --format bin \ 825 --metadata "$work/meta.json" "$work/kernel.elf" -o "$work/meta.bin" 826 assert_file_exists image-metadata-file "$work/meta.json" 827 contains image-metadata-format "$work/meta.json" '"format": "bin"' 828 contains image-metadata-objfmt "$work/meta.json" '"object_format": "elf"' 829 contains image-metadata-buildid "$work/meta.json" '"build_id":' 830 run_ok image-metadata-again "$KIT" image --format bin \ 831 --metadata "$work/meta2.json" "$work/kernel.elf" -o "$work/meta2.bin" 832 same_file image-metadata-deterministic "$work/meta.json" "$work/meta2.json" 833 # Section-source metadata records the section selection and marks the base as 834 # not a load address. 835 run_ok image-metadata-sections "$KIT" image --format sections \ 836 --section .text --section .rodata --metadata "$work/meta.sec.json" \ 837 "$work/kernel.elf" -o "$work/meta.sec.bin" 838 contains image-metadata-sections-source "$work/meta.sec.json" '"source": "sections"' 839 contains image-metadata-sections-base "$work/meta.sec.json" \ 840 '"base_is_load_address": false' 841 842 # ---- image: validation flags ---------------------------------------------- 843 # The fixture is a static -no-pie ELF with an _start entry and a .text section. 844 run_ok image-require-entry-ok "$KIT" image --require-entry --format bin \ 845 "$work/kernel.elf" -o "$work/req.bin" 846 run_ok image-require-symbol-ok "$KIT" image --require-symbol _start \ 847 --format bin "$work/kernel.elf" -o "$work/req.bin" 848 run_fail image-require-symbol-missing "$KIT" image \ 849 --require-symbol no_such_symbol --format bin "$work/kernel.elf" \ 850 -o "$work/req.bad.bin" 851 run_ok image-require-section-ok "$KIT" image --require-section .text \ 852 --format bin "$work/kernel.elf" -o "$work/req.bin" 853 run_fail image-require-section-missing "$KIT" image \ 854 --require-section .nope --format bin "$work/kernel.elf" -o "$work/req.bad.bin" 855 # A static, non-dynamic image passes --no-dynamic. 856 run_ok image-no-dynamic-ok "$KIT" image --no-dynamic --format bin \ 857 "$work/kernel.elf" -o "$work/nd.bin" 858 # --format elf is deferred to objcopy/strip and reports so. 859 run_fail image-format-elf-deferred "$KIT" image --format elf \ 860 "$work/kernel.elf" -o "$work/elf.bin" 861 862 # ==== BEGIN kernel-FZ Bug 10: metadata selection mirrors the emitter ========= 863 # The sidecar `selection` must list exactly the segments that contributed bytes. 864 # The emitter strips a leading PT_ and folds case (PT_LOAD == load == LOAD), so a 865 # selection written with exact-byte matching would diverge: --segment PT_LOAD and 866 # --segment load both select the loadable segment yet must not yield an empty 867 # list. (Regression guard for the hand-rolled-vs-emitter policy drift.) 868 run_ok image-meta-seg-ptload "$KIT" image --format bin --segment PT_LOAD \ 869 --metadata "$work/meta.ptload.json" "$work/kernel.elf" -o "$work/sel.ptload.bin" 870 contains image-meta-seg-ptload-selected "$work/meta.ptload.json" '"selection": ["LOAD"' 871 run_ok image-meta-seg-lowerload "$KIT" image --format bin --segment load \ 872 --metadata "$work/meta.load.json" "$work/kernel.elf" -o "$work/sel.load.bin" 873 contains image-meta-seg-lowerload-selected "$work/meta.load.json" '"selection": ["LOAD"' 874 # The default-ELF (no --segment) selection also lists the loadable segment(s). 875 run_ok image-meta-default-sel "$KIT" image --format bin \ 876 --metadata "$work/meta.def.json" "$work/kernel.elf" -o "$work/sel.def.bin" 877 contains image-meta-default-selected "$work/meta.def.json" '"selection": ["LOAD"' 878 # Explicit section filters switch to allocated-section ranges; an empty 879 # keep-set is a hard failure and cannot leave misleading metadata/output. 880 run_fail image-meta-remove-all "$KIT" image --format bin \ 881 --only-section .nope --metadata "$work/meta.rm.json" "$work/kernel.elf" \ 882 -o "$work/sel.rm.bin" 883 # ==== END kernel-FZ Bug 10 =================================================== 884 885 # ---- image: flat-kernel Image header (--image-header) ---------------------- 886 # A freestanding kernel whose first 64 bytes are an Image header AREA: an entry 887 # branch in the first 8 bytes (code0/code1) and 56 reserved bytes the emitter 888 # fills. A 4 KiB .bss makes the in-memory span exceed the file bytes, so a 889 # correct image_size must count BSS. The skeleton leaves the metadata zero so a 890 # plain `--format bin` (raw) is a witness that the emitter, not the author, 891 # wrote the magic and size. 892 cat > "$work/khdr_a64.S" <<'EOF' 893 .section .text, "ax" 894 .globl _start 895 _start: 896 b kstart /* 0x00 code0: branch over the header */ 897 .long 0 /* 0x04 code1 */ 898 .quad 0 /* 0x08 text_offset (kit fills) */ 899 .quad 0 /* 0x10 image_size (kit fills) */ 900 .quad 0 /* 0x18 flags (kit fills) */ 901 .quad 0 /* 0x20 res2 */ 902 .quad 0 /* 0x28 res3 */ 903 .quad 0 /* 0x30 res4 */ 904 .long 0 /* 0x38 magic (kit fills) */ 905 .long 0 /* 0x3c res5 */ 906 kstart: 907 ret 908 .section .data, "aw" 909 .byte 0x42 910 .section .bss, "aw", %nobits 911 .balign 16 912 .skip 4096 913 EOF 914 cat > "$work/khdr_a64.lds" <<'EOF' 915 ENTRY(_start) 916 SECTIONS { 917 . = 0x40080000; 918 .text : ALIGN(8) { *(.text .text.*) } 919 .data : ALIGN(8) { *(.data .data.*) } 920 .bss : ALIGN(16) { *(.bss .bss.*) } 921 _end = .; 922 /DISCARD/ : { *(.note.*) *(.comment) *(.eh_frame) } 923 } 924 EOF 925 run_ok image-hdr-a64-build "$KIT" build-exe -target aarch64-none-elf \ 926 -nostdlib -nostartfiles -static -no-pie -e _start -T "$work/khdr_a64.lds" \ 927 "$work/khdr_a64.S" -o "$work/khdr_a64.elf" 928 run_ok image-hdr-a64 "$KIT" image --format bin --image-header=arm64 \ 929 --metadata "$work/khdr_a64.json" "$work/khdr_a64.elf" -o "$work/khdr_a64.img" 930 # Plain bin is the witness for code0/code1, total size, and the empty skeleton. 931 run_ok image-hdr-a64-raw "$KIT" image --format bin "$work/khdr_a64.elf" \ 932 -o "$work/khdr_a64.raw" 933 # The entry branch (code0/code1) is preserved verbatim. 934 head -c 8 "$work/khdr_a64.img" > "$work/a64.code0" 935 head -c 8 "$work/khdr_a64.raw" > "$work/a64.code0.raw" 936 same_file image-hdr-a64-code0-preserved "$work/a64.code0.raw" "$work/a64.code0" 937 # Overlay, not prepend: same length as plain bin. 938 if [ "$(wc -c < "$work/khdr_a64.img")" = "$(wc -c < "$work/khdr_a64.raw")" ]; then 939 ok image-hdr-a64-overlay-size 940 else 941 not_ok image-hdr-a64-overlay-size 942 fi 943 # arm64 magic "ARM\x64" lands at offset 56; the skeleton (raw) is still zero 944 # there, proving the emitter synthesized it. 945 tail -c +57 "$work/khdr_a64.img" | head -c 4 | "$KIT" xxd -p > "$work/a64.magic" 946 contains image-hdr-a64-magic "$work/a64.magic" "41524d64" 947 tail -c +57 "$work/khdr_a64.raw" | head -c 4 | "$KIT" xxd -p > "$work/a64.rawmagic" 948 contains image-hdr-a64-skeleton-zero "$work/a64.rawmagic" "00000000" 949 # image_size (header offset 16) is written and counts the 4 KiB BSS: it exceeds 950 # the file image and the metadata mirrors it. 951 tail -c +17 "$work/khdr_a64.img" | head -c 8 | "$KIT" xxd -p > "$work/a64.szf.hex" 952 if [ "$(cat "$work/a64.szf.hex")" != "0000000000000000" ]; then 953 ok image-hdr-a64-size-written 954 else 955 not_ok image-hdr-a64-size-written 956 fi 957 a64_imgsz=$(grep '"image_size"' "$work/khdr_a64.json" | tr -dc '0-9') 958 a64_filesz=$(wc -c < "$work/khdr_a64.img" | tr -d ' ') 959 if [ "$a64_imgsz" -ge 4096 ] && [ "$a64_imgsz" -gt "$a64_filesz" ]; then 960 ok image-hdr-a64-size-counts-bss 961 else 962 echo "image_size=$a64_imgsz file=$a64_filesz" > "$work/a64sz.diag" 963 not_ok image-hdr-a64-size-counts-bss "$work/a64sz.diag" 964 fi 965 # Determinism: identical bytes on a second run. 966 run_ok image-hdr-a64-again "$KIT" image --format bin --image-header=arm64 \ 967 "$work/khdr_a64.elf" -o "$work/khdr_a64.img2" 968 same_file image-hdr-a64-deterministic "$work/khdr_a64.img" "$work/khdr_a64.img2" 969 970 # riscv64: same shape, exercised through AUTO arch inference (bare flag). The 971 # riscv tail differs — version 2 at offset 32 and magic2 "RSC\x05" at 56. 972 cat > "$work/khdr_rv.S" <<'EOF' 973 .section .text, "ax" 974 .globl _start 975 _start: 976 j kstart /* 0x00 code0 */ 977 .long 0 /* 0x04 code1 */ 978 .quad 0 /* 0x08 text_offset */ 979 .quad 0 /* 0x10 image_size */ 980 .quad 0 /* 0x18 flags */ 981 .long 0 /* 0x20 version (kit fills) */ 982 .long 0 /* 0x24 res1 */ 983 .quad 0 /* 0x28 res2 */ 984 .quad 0 /* 0x30 deprecated magic */ 985 .long 0 /* 0x38 magic2 (kit fills) */ 986 .long 0 /* 0x3c res3 */ 987 kstart: 988 ret 989 .section .data, "aw" 990 .byte 0x42 991 .section .bss, "aw", %nobits 992 .balign 16 993 .skip 8192 994 EOF 995 cat > "$work/khdr_rv.lds" <<'EOF' 996 ENTRY(_start) 997 SECTIONS { 998 . = 0x80200000; 999 .text : ALIGN(8) { *(.text .text.*) } 1000 .data : ALIGN(8) { *(.data .data.*) } 1001 .bss : ALIGN(16) { *(.bss .bss.*) } 1002 _end = .; 1003 /DISCARD/ : { *(.note.*) *(.comment) *(.eh_frame) } 1004 } 1005 EOF 1006 run_ok image-hdr-rv-build "$KIT" build-exe -target riscv64-none-elf \ 1007 -nostdlib -nostartfiles -static -no-pie -e _start -T "$work/khdr_rv.lds" \ 1008 "$work/khdr_rv.S" -o "$work/khdr_rv.elf" 1009 run_ok image-hdr-rv-auto "$KIT" image --format bin --image-header \ 1010 --metadata "$work/khdr_rv.json" "$work/khdr_rv.elf" -o "$work/khdr_rv.img" 1011 contains image-hdr-rv-auto-detected "$work/khdr_rv.json" '"image_header": "riscv"' 1012 tail -c +57 "$work/khdr_rv.img" | head -c 4 | "$KIT" xxd -p > "$work/rv.magic" 1013 contains image-hdr-rv-magic2 "$work/rv.magic" "52534305" 1014 tail -c +33 "$work/khdr_rv.img" | head -c 4 | "$KIT" xxd -p > "$work/rv.ver" 1015 contains image-hdr-rv-version "$work/rv.ver" "02000000" 1016 rv_imgsz=$(grep '"image_size"' "$work/khdr_rv.json" | tr -dc '0-9') 1017 if [ "$rv_imgsz" -ge 8192 ]; then 1018 ok image-hdr-rv-size-counts-bss 1019 else 1020 echo "image_size=$rv_imgsz" > "$work/rvsz.diag" 1021 not_ok image-hdr-rv-size-counts-bss "$work/rvsz.diag" 1022 fi 1023 1024 # Pass-through: an author who writes the full header keeps it byte-exact through 1025 # a plain `--format bin` (no --image-header). image_size = _end - _start and the 1026 # magic are the author's own bytes, untouched by the emitter. 1027 cat > "$work/khdr_pt.S" <<'EOF' 1028 .section .text, "ax" 1029 .globl _start 1030 _start: 1031 b kstart 1032 .long 0 1033 .quad 0x80000 /* text_offset */ 1034 .quad 0x4000 /* image_size (author-written constant) */ 1035 .quad 0xa /* flags: 4K, LE */ 1036 .quad 0 1037 .quad 0 1038 .quad 0 1039 .ascii "ARM\x64" /* magic */ 1040 .long 0 1041 kstart: 1042 ret 1043 .section .bss, "aw", %nobits 1044 .balign 16 1045 .skip 256 1046 EOF 1047 run_ok image-hdr-pt-build "$KIT" build-exe -target aarch64-none-elf \ 1048 -nostdlib -nostartfiles -static -no-pie -e _start -T "$work/khdr_a64.lds" \ 1049 "$work/khdr_pt.S" -o "$work/khdr_pt.elf" 1050 run_ok image-hdr-pt-bin "$KIT" image --format bin "$work/khdr_pt.elf" \ 1051 -o "$work/khdr_pt.bin" 1052 tail -c +57 "$work/khdr_pt.bin" | head -c 4 | "$KIT" xxd -p > "$work/pt.magic" 1053 contains image-hdr-pt-magic-preserved "$work/pt.magic" "41524d64" 1054 tail -c +17 "$work/khdr_pt.bin" | head -c 8 | "$KIT" xxd -p > "$work/pt.sz.hex" 1055 if [ "$(cat "$work/pt.sz.hex")" != "0000000000000000" ]; then 1056 ok image-hdr-pt-size-preserved 1057 else 1058 not_ok image-hdr-pt-size-preserved 1059 fi 1060 run_ok image-hdr-pt-again "$KIT" image --format bin "$work/khdr_pt.elf" \ 1061 -o "$work/khdr_pt.bin2" 1062 same_file image-hdr-pt-deterministic "$work/khdr_pt.bin" "$work/khdr_pt.bin2" 1063 1064 # Negative: a section source has no memory model, AUTO needs a known arch, the 1065 # page-size flag is arm64-only, and the header sub-options need --image-header. 1066 run_fail image-hdr-rejects-sections "$KIT" image --format sections \ 1067 --section .text --image-header=arm64 "$work/kernel.elf" -o "$work/h.bad.bin" 1068 run_fail image-hdr-auto-unknown-arch "$KIT" image --format bin --image-header \ 1069 "$work/kernel.elf" -o "$work/h.bad.bin" 1070 run_fail image-hdr-page-size-riscv "$KIT" image --format bin --image-header=riscv \ 1071 --image-page-size 16k "$work/khdr_rv.elf" -o "$work/h.bad.bin" 1072 run_fail image-hdr-opts-need-header "$KIT" image --format bin \ 1073 --image-text-offset 0x80000 "$work/kernel.elf" -o "$work/h.bad.bin" 1074 1075 kit_summary tools-driver 1076 kit_exit