#!/usr/bin/env python3 """Position-independence lint: the two link-time facts that let the identical image run from any slot, asserted from the built ELF. 1. No absolute jmp/call — -mrelax normally guarantees it, but a branch that grows out of relaxation range would break it silently. 2. The info block within the image's first 256 bytes: 'b' rebuilds its address as (running slot high byte : link address low byte). Usage: check_pi.py """ import re import subprocess import sys def main(): objdump, nm, elf, text_start = sys.argv[1:] text_start = int(text_start, 0) listing = subprocess.run([objdump, "-d", elf], capture_output=True, text=True, check=True).stdout absolute = [ line for line in listing.splitlines() if re.search(r"\t(jmp|call)\t", line) ] if absolute: print("FAIL: absolute control flow in the image:") print("\n".join(absolute)) sys.exit(1) symbols = subprocess.run([nm, "-C", elf], capture_output=True, text=True, check=True).stdout info = [line for line in symbols.splitlines() if "flash_table" in line and "::storage" in line] if len(info) != 1: print(f"FAIL: expected one info-block storage symbol, found {len(info)}") sys.exit(1) address = int(info[0].split()[0], 16) offset = address - text_start if not 0 <= offset < 256: print(f"FAIL: info block at image offset {offset:#x}, must sit in the first 256 bytes") sys.exit(1) print(f"PI lint: control flow PC-relative, info block at offset {offset:#x}") if __name__ == "__main__": main()