75 lines
2.6 KiB
Python
Executable File
75 lines
2.6 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import fileinput
|
|
import re
|
|
import sys
|
|
|
|
# Linker address generation validity checker. By default, GNU ld is
|
|
# broken when faced with sections where the load address (i.e. the
|
|
# spot in the XIP program binary where initialized data lives) differs
|
|
# from the virtual address (i.e. the location in RAM where that data
|
|
# will live at runtime. We need to be sure we're using the
|
|
# ALIGN_WITH_INPUT feature correctly everywhere, which is hard --
|
|
# especially so given that many of these bugs are semi-invisible at
|
|
# runtime (most initialized data is still a bunch of zeros and often
|
|
# "works" even if it's wrong).
|
|
#
|
|
# This quick test just checks the offsets between sequential segments
|
|
# with separate VMA/LMA addresses and verifies that the size deltas
|
|
# are identical.
|
|
#
|
|
# Note that this is assuming that the address generation is always
|
|
# in-order and that there is only one "ROM" LMA block. It's possible
|
|
# to write a valid linker script that will fail this script, but we
|
|
# don't have such a use case and one isn't forseen.
|
|
|
|
section_re = re.compile(r'(?x)' # (allow whitespace)
|
|
r'^([a-zA-Z0-9_\.]+) \s+' # name
|
|
r' (0x[0-9a-f]+) \s+' # addr
|
|
r' (0x[0-9a-f]+)\s*') # size
|
|
|
|
load_addr_re = re.compile('load address (0x[0-9a-f]+)')
|
|
|
|
in_prologue = True
|
|
lma = 0
|
|
last_sec = None
|
|
|
|
for line in fileinput.input():
|
|
# Skip the header junk
|
|
if line.find("Linker script and memory map") >= 0:
|
|
in_prologue = False
|
|
continue
|
|
|
|
match = section_re.match(line.rstrip())
|
|
if match:
|
|
sec = match.group(1)
|
|
vma = int(match.group(2), 16)
|
|
size = int(match.group(3), 16)
|
|
|
|
if sec == "bss":
|
|
# Make sure we don't compare the last section of kernel data
|
|
# with the first section of application data, the kernel's bss
|
|
# and noinit are in between.
|
|
last_sec = None
|
|
continue
|
|
|
|
lmatch = load_addr_re.search(line.rstrip())
|
|
if lmatch:
|
|
lma = int(lmatch.group(1), 16)
|
|
else:
|
|
last_sec = None
|
|
continue
|
|
|
|
if last_sec is not None:
|
|
dv = vma - last_vma
|
|
dl = lma - last_lma
|
|
if dv != dl:
|
|
sys.stderr.write("ERROR: section %s is %d bytes "
|
|
"in the virtual/runtime address space, "
|
|
"but only %d in the loaded/XIP section!\n"
|
|
% (last_sec, dv, dl))
|
|
sys.exit(1)
|
|
|
|
last_sec = sec
|
|
last_vma = vma
|
|
last_lma = lma
|