You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
74 lines
2.6 KiB
74 lines
2.6 KiB
#!/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('(?x)' # (allow whitespace) |
|
'^([a-zA-Z0-9_\.]+) \s+' # name |
|
' (0x[0-9a-f]+) \s+' # addr |
|
' (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
|
|
|