Switch from Makefile to GN

GN makes it easier for us to have a modular build where we can define
tests and reuse code without having to hack on Makefiles. It also has
tools to analyze the build and comes with extensive documentation.

Change-Id: Ib28bc7b68d429e3c3193784c7a80d05ee35c6295
diff --git a/build/image/extract_offsets.py b/build/image/extract_offsets.py
new file mode 100644
index 0000000..cf4f5c7
--- /dev/null
+++ b/build/image/extract_offsets.py
@@ -0,0 +1,47 @@
+#!/usr/bin/env python
+
+"""Extract embedded offsets from an object file.
+
+We let the compiler calculate the offsets it is going to use and have those
+emitted into and object file. This is the next pass which extracts those offsets
+and stores them in a header file for the assembly to include and use.
+"""
+
+import argparse
+import os
+import re
+import subprocess
+import sys
+
+def Main():
+  parser = argparse.ArgumentParser()
+  parser.add_argument("--tool_prefix", required=True)
+  parser.add_argument("--input", required=True)
+  parser.add_argument("--output", required=True)
+  args = parser.parse_args()
+  raw = subprocess.check_output([
+      "{}objdump".format(args.tool_prefix),
+      "--disassemble-all",
+      "--section",
+      ".rodata",
+      args.input])
+  lines = raw.split('\n')
+  with open(args.output, 'w') as header:
+    header.write('#pragma once\n\n')
+    for n in range(len(lines)):
+      # Find a defined offset
+      match = re.match('.+DEFINE_OFFSET__([^>]+)', lines[n])
+      if not match:
+        continue
+      name = match.group(1)
+      # The next line tells the offset
+      if "..." in lines[n + 1]:
+        offset = 0
+      else:
+        offset = re.match('.+\.[\S]+\s+(.+)$', lines[n + 1]).group(1)
+      # Write the offset to the header
+      header.write("#define {} {}\n".format(name, offset))
+  return 0
+
+if __name__ == "__main__":
+  sys.exit(Main())