arm: Add app data section alignment constraints

This patch adds application data section alignment constraints
to match the region definition requirements for ARM MPUs.  Most MPUs
require a minimum of 32 bytes of alignment for any regions, but some
require power of two alignment to the size of a region.

This requires that the linker align the application data section to
the size of the section.  This requires a linker pass to determine the
size.  Once this is accomplished the correct value is added to a linker
include file that is utilized in subsequent linker operations.

Signed-off-by: Andy Gross <andy.gross@linaro.org>
diff --git a/scripts/gen_alignment_script.py b/scripts/gen_alignment_script.py
new file mode 100755
index 0000000..aaaa1f4
--- /dev/null
+++ b/scripts/gen_alignment_script.py
@@ -0,0 +1,79 @@
+#!/usr/bin/env python3
+#
+# Copyright (c) 2017 Linaro Limited
+#
+# SPDX-License-Identifier: Apache-2.0
+
+import sys
+import argparse
+import pprint
+import os
+import struct
+from distutils.version import LooseVersion
+
+import elftools
+from elftools.elf.elffile import ELFFile
+from elftools.dwarf import descriptions
+from elftools.elf.sections import SymbolTableSection
+
+if LooseVersion(elftools.__version__) < LooseVersion('0.24'):
+    sys.stderr.write("pyelftools is out of date, need version 0.24 or later\n")
+    sys.exit(1)
+
+
+def get_symbols(obj):
+    for section in obj.iter_sections():
+        if isinstance(section, SymbolTableSection):
+            return {sym.name: sym.entry.st_value
+                    for sym in section.iter_symbols()}
+
+    raise LookupError("Could not find symbol table")
+
+
+def parse_args():
+    global args
+
+    parser = argparse.ArgumentParser(
+        description=__doc__,
+        formatter_class=argparse.RawDescriptionHelpFormatter)
+
+    parser.add_argument(
+        "-k", "--kernel", required=True,
+        help="Input zephyr ELF binary")
+    parser.add_argument(
+        "-o", "--output", required=True,
+        help="Output linker file")
+    parser.add_argument(
+        "-v", "--verbose", action="store_true",
+        help="Print extra debugging information")
+    args = parser.parse_args()
+
+
+def main():
+    parse_args()
+
+    bit_len = None
+
+    with open(args.kernel, "rb") as fp:
+        elf = ELFFile(fp)
+        args.little_endian = elf.little_endian
+        syms = get_symbols(elf)
+
+        app_ram_size = syms['__app_last_address_used'] - \
+            syms['__app_ram_start']
+        bit_len = app_ram_size.bit_length()
+
+    if bit_len:
+        align_size = 1 << bit_len
+    else:
+        align_size = 32
+
+    with open(args.output, "w") as fp:
+        fp.write("/***********************************************\n")
+        fp.write(" * Generated file, do not modify\n")
+        fp.write(" **********************************************/\n")
+        fp.write("_app_data_align = " + str(align_size) + ";\n")
+        fp.write(". = ALIGN(_app_data_align);\n")
+
+if __name__ == "__main__":
+    main()