summaryrefslogtreecommitdiff
path: root/scripts/check_link_map.pl
blob: 3ba45d13f09c50caf5524bf6292749e6336bb53b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#!/usr/bin/perl
use warnings;
use strict;

# 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.

# Skip the header stuff
while(<>) { last if /Linker script and memory map/; }


my ($last_sec, $last_vma, $last_lma);
while(<>) {
	next if ! /^([a-zA-Z0-9_\.]+) \s+  # name
		    (0x[0-9a-f]+)     \s+  # addr
		    (0x[0-9a-f]+)     \s+  # size
		  /x;

	my ($sec, $vma, $sz) = ($1, $2, $3);

	my $lma = "";
	if(/load address (0x[0-9a-f]+)/) {
		$lma = $1;
	} else {
		$last_sec = undef;
		next;
	}

	$vma = eval $vma;
	$lma = eval $lma;

	if(defined $last_sec) {
		my $dv = $vma - $last_vma;
		my $dl = $lma - $last_lma;
		if($dv != $dl) {
			print STDERR
			    "ERROR: section $last_sec is $dv bytes "
			    . "in the virtual/runtime address space, "
			    . "but only $dl in the loaded/XIP section!\n";
			exit 1;
		}
	}

	$last_sec = $sec;
	$last_vma = $vma;
	$last_lma = $lma;
}