summaryrefslogtreecommitdiffstatshomepage
path: root/tools/mpy_ld.py
diff options
context:
space:
mode:
authorDamien George <damien.p.george@gmail.com>2020-02-27 15:36:53 +1100
committerDamien George <damien.p.george@gmail.com>2020-02-28 10:33:03 +1100
commit69661f3343bedf86e514337cff63d96cc42f8859 (patch)
treeaf5dfb380ffdb75dda84828f63cf9d840d992f0f /tools/mpy_ld.py
parent3f39d18c2b884d32f0443e2e8114ff9d7a14d718 (diff)
downloadmicropython-69661f3343bedf86e514337cff63d96cc42f8859.tar.gz
micropython-69661f3343bedf86e514337cff63d96cc42f8859.zip
all: Reformat C and Python source code with tools/codeformat.py.
This is run with uncrustify 0.70.1, and black 19.10b0.
Diffstat (limited to 'tools/mpy_ld.py')
-rwxr-xr-xtools/mpy_ld.py683
1 files changed, 400 insertions, 283 deletions
diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py
index 31c3912991..32bc176cb7 100755
--- a/tools/mpy_ld.py
+++ b/tools/mpy_ld.py
@@ -31,7 +31,7 @@ Link .o files to .mpy
import sys, os, struct, re
from elftools.elf import elffile
-sys.path.append(os.path.dirname(__file__) + '/../py')
+sys.path.append(os.path.dirname(__file__) + "/../py")
import makeqstrdata as qstrutil
# MicroPython constants
@@ -70,8 +70,8 @@ R_386_GOTPC = 10
R_ARM_THM_CALL = 10
R_XTENSA_DIFF32 = 19
R_XTENSA_SLOT0_OP = 20
-R_ARM_BASE_PREL = 25 # aka R_ARM_GOTPC
-R_ARM_GOT_BREL = 26 # aka R_ARM_GOT32
+R_ARM_BASE_PREL = 25 # aka R_ARM_GOTPC
+R_ARM_GOT_BREL = 26 # aka R_ARM_GOT32
R_ARM_THM_JUMP24 = 30
R_X86_64_REX_GOTPCRELX = 42
R_386_GOT32X = 43
@@ -79,25 +79,29 @@ R_386_GOT32X = 43
################################################################################
# Architecture configuration
+
def asm_jump_x86(entry):
- return struct.pack('<BI', 0xe9, entry - 5)
+ return struct.pack("<BI", 0xE9, entry - 5)
+
def asm_jump_arm(entry):
b_off = entry - 4
if b_off >> 11 == 0 or b_off >> 11 == -1:
# Signed value fits in 12 bits
- b0 = 0xe000 | (b_off >> 1 & 0x07ff)
+ b0 = 0xE000 | (b_off >> 1 & 0x07FF)
b1 = 0
else:
# Use large jump
- b0 = 0xf000 | (b_off >> 12 & 0x07ff)
- b1 = 0xb800 | (b_off >> 1 & 0x7ff)
- return struct.pack('<HH', b0, b1)
+ b0 = 0xF000 | (b_off >> 12 & 0x07FF)
+ b1 = 0xB800 | (b_off >> 1 & 0x7FF)
+ return struct.pack("<HH", b0, b1)
+
def asm_jump_xtensa(entry):
jump_offset = entry - 4
jump_op = jump_offset << 6 | 6
- return struct.pack('<BH', jump_op & 0xff, jump_op >> 8)
+ return struct.pack("<BH", jump_op & 0xFF, jump_op >> 8)
+
class ArchData:
def __init__(self, name, mpy_feature, qstr_entry_size, word_size, arch_got, asm_jump):
@@ -107,83 +111,117 @@ class ArchData:
self.word_size = word_size
self.arch_got = arch_got
self.asm_jump = asm_jump
- self.separate_rodata = name == 'EM_XTENSA' and qstr_entry_size == 4
+ self.separate_rodata = name == "EM_XTENSA" and qstr_entry_size == 4
+
ARCH_DATA = {
- 'x86': ArchData(
- 'EM_386',
- MP_NATIVE_ARCH_X86 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE,
- 2, 4, (R_386_PC32, R_386_GOT32, R_386_GOT32X), asm_jump_x86,
+ "x86": ArchData(
+ "EM_386",
+ MP_NATIVE_ARCH_X86 << 2
+ | MICROPY_PY_BUILTINS_STR_UNICODE
+ | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE,
+ 2,
+ 4,
+ (R_386_PC32, R_386_GOT32, R_386_GOT32X),
+ asm_jump_x86,
),
- 'x64': ArchData(
- 'EM_X86_64',
- MP_NATIVE_ARCH_X64 << 2 | MICROPY_PY_BUILTINS_STR_UNICODE | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE,
- 2, 8, (R_X86_64_REX_GOTPCRELX,), asm_jump_x86,
+ "x64": ArchData(
+ "EM_X86_64",
+ MP_NATIVE_ARCH_X64 << 2
+ | MICROPY_PY_BUILTINS_STR_UNICODE
+ | MICROPY_OPT_CACHE_MAP_LOOKUP_IN_BYTECODE,
+ 2,
+ 8,
+ (R_X86_64_REX_GOTPCRELX,),
+ asm_jump_x86,
),
- 'armv7m': ArchData(
- 'EM_ARM',
+ "armv7m": ArchData(
+ "EM_ARM",
MP_NATIVE_ARCH_ARMV7M << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
- 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm,
+ 2,
+ 4,
+ (R_ARM_GOT_BREL,),
+ asm_jump_arm,
),
- 'armv7emsp': ArchData(
- 'EM_ARM',
+ "armv7emsp": ArchData(
+ "EM_ARM",
MP_NATIVE_ARCH_ARMV7EMSP << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
- 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm,
+ 2,
+ 4,
+ (R_ARM_GOT_BREL,),
+ asm_jump_arm,
),
- 'armv7emdp': ArchData(
- 'EM_ARM',
+ "armv7emdp": ArchData(
+ "EM_ARM",
MP_NATIVE_ARCH_ARMV7EMDP << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
- 2, 4, (R_ARM_GOT_BREL,), asm_jump_arm,
+ 2,
+ 4,
+ (R_ARM_GOT_BREL,),
+ asm_jump_arm,
),
- 'xtensa': ArchData(
- 'EM_XTENSA',
+ "xtensa": ArchData(
+ "EM_XTENSA",
MP_NATIVE_ARCH_XTENSA << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
- 2, 4, (R_XTENSA_32, R_XTENSA_PLT), asm_jump_xtensa,
+ 2,
+ 4,
+ (R_XTENSA_32, R_XTENSA_PLT),
+ asm_jump_xtensa,
),
- 'xtensawin': ArchData(
- 'EM_XTENSA',
+ "xtensawin": ArchData(
+ "EM_XTENSA",
MP_NATIVE_ARCH_XTENSAWIN << 2 | MICROPY_PY_BUILTINS_STR_UNICODE,
- 4, 4, (R_XTENSA_32, R_XTENSA_PLT), asm_jump_xtensa,
+ 4,
+ 4,
+ (R_XTENSA_32, R_XTENSA_PLT),
+ asm_jump_xtensa,
),
}
################################################################################
# Helper functions
+
def align_to(value, align):
return (value + align - 1) & ~(align - 1)
+
def unpack_u24le(data, offset):
return data[offset] | data[offset + 1] << 8 | data[offset + 2] << 16
+
def pack_u24le(data, offset, value):
- data[offset] = value & 0xff
- data[offset + 1] = value >> 8 & 0xff
- data[offset + 2] = value >> 16 & 0xff
+ data[offset] = value & 0xFF
+ data[offset + 1] = value >> 8 & 0xFF
+ data[offset + 2] = value >> 16 & 0xFF
+
def xxd(text):
for i in range(0, len(text), 16):
- print('{:08x}:'.format(i), end='')
+ print("{:08x}:".format(i), end="")
for j in range(4):
off = i + j * 4
if off < len(text):
- d = int.from_bytes(text[off:off + 4], 'little')
- print(' {:08x}'.format(d), end='')
+ d = int.from_bytes(text[off : off + 4], "little")
+ print(" {:08x}".format(d), end="")
print()
+
# Smaller numbers are enabled first
LOG_LEVEL_1 = 1
LOG_LEVEL_2 = 2
LOG_LEVEL_3 = 3
log_level = LOG_LEVEL_1
+
def log(level, msg):
if level <= log_level:
print(msg)
+
################################################################################
# Qstr extraction
+
def extract_qstrs(source_files):
def read_qstrs(f):
with open(f) as f:
@@ -191,21 +229,21 @@ def extract_qstrs(source_files):
objs = set()
for line in f:
while line:
- m = re.search(r'MP_OBJ_NEW_QSTR\((MP_QSTR_[A-Za-z0-9_]*)\)', line)
+ m = re.search(r"MP_OBJ_NEW_QSTR\((MP_QSTR_[A-Za-z0-9_]*)\)", line)
if m:
objs.add(m.group(1))
else:
- m = re.search(r'MP_QSTR_[A-Za-z0-9_]*', line)
+ m = re.search(r"MP_QSTR_[A-Za-z0-9_]*", line)
if m:
vals.add(m.group())
if m:
s = m.span()
- line = line[:s[0]] + line[s[1]:]
+ line = line[: s[0]] + line[s[1] :]
else:
- line = ''
+ line = ""
return vals, objs
- static_qstrs = ['MP_QSTR_' + qstrutil.qstr_escape(q) for q in qstrutil.static_qstr_list]
+ static_qstrs = ["MP_QSTR_" + qstrutil.qstr_escape(q) for q in qstrutil.static_qstr_list]
qstr_vals = set()
qstr_objs = set()
@@ -217,12 +255,15 @@ def extract_qstrs(source_files):
return static_qstrs, qstr_vals, qstr_objs
+
################################################################################
# Linker
+
class LinkError(Exception):
pass
+
class Section:
def __init__(self, name, data, alignment, filename=None):
self.filename = filename
@@ -237,6 +278,7 @@ class Section:
assert elfsec.header.sh_addr == 0
return Section(elfsec.name, elfsec.data(), elfsec.data_alignment, filename)
+
class GOTEntry:
def __init__(self, name, sym, link_addr=0):
self.name = name
@@ -245,60 +287,67 @@ class GOTEntry:
self.link_addr = link_addr
def isexternal(self):
- return self.sec_name.startswith('.external')
+ return self.sec_name.startswith(".external")
def istext(self):
- return self.sec_name.startswith('.text')
+ return self.sec_name.startswith(".text")
def isrodata(self):
- return self.sec_name.startswith(('.rodata', '.data.rel.ro'))
+ return self.sec_name.startswith((".rodata", ".data.rel.ro"))
def isbss(self):
- return self.sec_name.startswith('.bss')
+ return self.sec_name.startswith(".bss")
+
class LiteralEntry:
def __init__(self, value, offset):
self.value = value
self.offset = offset
+
class LinkEnv:
def __init__(self, arch):
self.arch = ARCH_DATA[arch]
- self.sections = [] # list of sections in order of output
+ self.sections = [] # list of sections in order of output
self.literal_sections = [] # list of literal sections (xtensa only)
- self.known_syms = {} # dict of symbols that are defined
- self.unresolved_syms = [] # list of unresolved symbols
- self.mpy_relocs = [] # list of relocations needed in the output .mpy file
+ self.known_syms = {} # dict of symbols that are defined
+ self.unresolved_syms = [] # list of unresolved symbols
+ self.mpy_relocs = [] # list of relocations needed in the output .mpy file
def check_arch(self, arch_name):
if arch_name != self.arch.name:
- raise LinkError('incompatible arch')
+ raise LinkError("incompatible arch")
def print_sections(self):
- log(LOG_LEVEL_2, 'sections:')
+ log(LOG_LEVEL_2, "sections:")
for sec in self.sections:
- log(LOG_LEVEL_2, ' {:08x} {} size={}'.format(sec.addr, sec.name, len(sec.data)))
+ log(LOG_LEVEL_2, " {:08x} {} size={}".format(sec.addr, sec.name, len(sec.data)))
def find_addr(self, name):
if name in self.known_syms:
s = self.known_syms[name]
- return s.section.addr + s['st_value']
- raise LinkError('unknown symbol: {}'.format(name))
+ return s.section.addr + s["st_value"]
+ raise LinkError("unknown symbol: {}".format(name))
+
def build_got_generic(env):
env.got_entries = {}
for sec in env.sections:
for r in sec.reloc:
s = r.sym
- if not (s.entry['st_info']['bind'] == 'STB_GLOBAL' and r['r_info_type'] in env.arch.arch_got):
+ if not (
+ s.entry["st_info"]["bind"] == "STB_GLOBAL"
+ and r["r_info_type"] in env.arch.arch_got
+ ):
continue
- s_type = s.entry['st_info']['type']
- assert s_type in ('STT_NOTYPE', 'STT_FUNC', 'STT_OBJECT'), s_type
+ s_type = s.entry["st_info"]["type"]
+ assert s_type in ("STT_NOTYPE", "STT_FUNC", "STT_OBJECT"), s_type
assert s.name
if s.name in env.got_entries:
continue
env.got_entries[s.name] = GOTEntry(s.name, s)
+
def build_got_xtensa(env):
env.got_entries = {}
env.lit_entries = {}
@@ -311,21 +360,21 @@ def build_got_xtensa(env):
# Look through literal relocations to find any global pointers that should be GOT entries
for r in sec.reloc:
s = r.sym
- s_type = s.entry['st_info']['type']
- assert s_type in ('STT_NOTYPE', 'STT_FUNC', 'STT_OBJECT', 'STT_SECTION'), s_type
- assert r['r_info_type'] in env.arch.arch_got
- assert r['r_offset'] % env.arch.word_size == 0
+ s_type = s.entry["st_info"]["type"]
+ assert s_type in ("STT_NOTYPE", "STT_FUNC", "STT_OBJECT", "STT_SECTION"), s_type
+ assert r["r_info_type"] in env.arch.arch_got
+ assert r["r_offset"] % env.arch.word_size == 0
# This entry is a global pointer
- existing = struct.unpack_from('<I', sec.data, r['r_offset'])[0]
- if s_type == 'STT_SECTION':
- assert r['r_addend'] == 0
+ existing = struct.unpack_from("<I", sec.data, r["r_offset"])[0]
+ if s_type == "STT_SECTION":
+ assert r["r_addend"] == 0
name = "{}+0x{:x}".format(s.section.name, existing)
else:
assert existing == 0
name = s.name
- if r['r_addend'] != 0:
- name = "{}+0x{:x}".format(name, r['r_addend'])
- idx = '{}+0x{:x}'.format(sec.filename, r['r_offset'])
+ if r["r_addend"] != 0:
+ name = "{}+0x{:x}".format(name, r["r_addend"])
+ idx = "{}+0x{:x}".format(sec.filename, r["r_offset"])
env.xt_literals[idx] = name
if name in env.got_entries:
# Deduplicate GOT entries
@@ -334,30 +383,35 @@ def build_got_xtensa(env):
# Go through all literal entries finding those that aren't global pointers so must be actual literals
for i in range(0, len(sec.data), env.arch.word_size):
- idx = '{}+0x{:x}'.format(sec.filename, i)
+ idx = "{}+0x{:x}".format(sec.filename, i)
if idx not in env.xt_literals:
# This entry is an actual literal
- value = struct.unpack_from('<I', sec.data, i)[0]
+ value = struct.unpack_from("<I", sec.data, i)[0]
env.xt_literals[idx] = value
if value in env.lit_entries:
# Deduplicate literals
continue
- env.lit_entries[value] = LiteralEntry(value, len(env.lit_entries) * env.arch.word_size)
+ env.lit_entries[value] = LiteralEntry(
+ value, len(env.lit_entries) * env.arch.word_size
+ )
+
def populate_got(env):
# Compute GOT destination addresses
for got_entry in env.got_entries.values():
sym = got_entry.sym
- if hasattr(sym, 'resolved'):
+ if hasattr(sym, "resolved"):
sym = sym.resolved
sec = sym.section
- addr = sym['st_value']
+ addr = sym["st_value"]
got_entry.sec_name = sec.name
got_entry.link_addr += sec.addr + addr
# Get sorted GOT, sorted by external, text, rodata, bss so relocations can be combined
- got_list = sorted(env.got_entries.values(),
- key=lambda g: g.isexternal() + 2 * g.istext() + 3 * g.isrodata() + 4 * g.isbss())
+ got_list = sorted(
+ env.got_entries.values(),
+ key=lambda g: g.isexternal() + 2 * g.istext() + 3 * g.isrodata() + 4 * g.isbss(),
+ )
# Layout and populate the GOT
offset = 0
@@ -365,131 +419,154 @@ def populate_got(env):
got_entry.offset = offset
offset += env.arch.word_size
o = env.got_section.addr + got_entry.offset
- env.full_text[o:o + env.arch.word_size] = got_entry.link_addr.to_bytes(env.arch.word_size, 'little')
+ env.full_text[o : o + env.arch.word_size] = got_entry.link_addr.to_bytes(
+ env.arch.word_size, "little"
+ )
# Create a relocation for each GOT entry
for got_entry in got_list:
- if got_entry.name == 'mp_fun_table':
- dest = 'mp_fun_table'
- elif got_entry.name.startswith('mp_fun_table+0x'):
- dest = int(got_entry.name.split('+')[1], 16) // env.arch.word_size
- elif got_entry.sec_name.startswith('.text'):
- dest = '.text'
- elif got_entry.sec_name.startswith('.rodata'):
- dest = '.rodata'
- elif got_entry.sec_name.startswith('.data.rel.ro'):
- dest = '.data.rel.ro'
- elif got_entry.sec_name.startswith('.bss'):
- dest = '.bss'
+ if got_entry.name == "mp_fun_table":
+ dest = "mp_fun_table"
+ elif got_entry.name.startswith("mp_fun_table+0x"):
+ dest = int(got_entry.name.split("+")[1], 16) // env.arch.word_size
+ elif got_entry.sec_name.startswith(".text"):
+ dest = ".text"
+ elif got_entry.sec_name.startswith(".rodata"):
+ dest = ".rodata"
+ elif got_entry.sec_name.startswith(".data.rel.ro"):
+ dest = ".data.rel.ro"
+ elif got_entry.sec_name.startswith(".bss"):
+ dest = ".bss"
else:
assert 0, (got_entry.name, got_entry.sec_name)
- env.mpy_relocs.append(('.text', env.got_section.addr + got_entry.offset, dest))
+ env.mpy_relocs.append((".text", env.got_section.addr + got_entry.offset, dest))
# Print out the final GOT
- log(LOG_LEVEL_2, 'GOT: {:08x}'.format(env.got_section.addr))
+ log(LOG_LEVEL_2, "GOT: {:08x}".format(env.got_section.addr))
for g in got_list:
- log(LOG_LEVEL_2, ' {:08x} {} -> {}+{:08x}'.format(g.offset, g.name, g.sec_name, g.link_addr))
+ log(
+ LOG_LEVEL_2,
+ " {:08x} {} -> {}+{:08x}".format(g.offset, g.name, g.sec_name, g.link_addr),
+ )
+
def populate_lit(env):
- log(LOG_LEVEL_2, 'LIT: {:08x}'.format(env.lit_section.addr))
+ log(LOG_LEVEL_2, "LIT: {:08x}".format(env.lit_section.addr))
for lit_entry in env.lit_entries.values():
value = lit_entry.value
- log(LOG_LEVEL_2, ' {:08x} = {:08x}'.format(lit_entry.offset, value))
+ log(LOG_LEVEL_2, " {:08x} = {:08x}".format(lit_entry.offset, value))
o = env.lit_section.addr + lit_entry.offset
- env.full_text[o:o + env.arch.word_size] = value.to_bytes(env.arch.word_size, 'little')
+ env.full_text[o : o + env.arch.word_size] = value.to_bytes(env.arch.word_size, "little")
+
def do_relocation_text(env, text_addr, r):
# Extract relevant info about symbol that's being relocated
s = r.sym
- s_bind = s.entry['st_info']['bind']
- s_shndx = s.entry['st_shndx']
- s_type = s.entry['st_info']['type']
- r_offset = r['r_offset'] + text_addr
- r_info_type = r['r_info_type']
+ s_bind = s.entry["st_info"]["bind"]
+ s_shndx = s.entry["st_shndx"]
+ s_type = s.entry["st_info"]["type"]
+ r_offset = r["r_offset"] + text_addr
+ r_info_type = r["r_info_type"]
try:
# only for RELA sections
- r_addend = r['r_addend']
+ r_addend = r["r_addend"]
except KeyError:
r_addend = 0
# Default relocation type and name for logging
- reloc_type = 'le32'
+ reloc_type = "le32"
log_name = None
- if (env.arch.name == 'EM_386' and r_info_type in (R_386_PC32, R_386_PLT32)
- or env.arch.name == 'EM_X86_64' and r_info_type in (R_X86_64_PC32, R_X86_64_PLT32)
- or env.arch.name == 'EM_ARM' and r_info_type in (R_ARM_REL32, R_ARM_THM_CALL, R_ARM_THM_JUMP24)
- or s_bind == 'STB_LOCAL' and env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_32 # not GOT
- ):
+ if (
+ env.arch.name == "EM_386"
+ and r_info_type in (R_386_PC32, R_386_PLT32)
+ or env.arch.name == "EM_X86_64"
+ and r_info_type in (R_X86_64_PC32, R_X86_64_PLT32)
+ or env.arch.name == "EM_ARM"
+ and r_info_type in (R_ARM_REL32, R_ARM_THM_CALL, R_ARM_THM_JUMP24)
+ or s_bind == "STB_LOCAL"
+ and env.arch.name == "EM_XTENSA"
+ and r_info_type == R_XTENSA_32 # not GOT
+ ):
# Standard relocation to fixed location within text/rodata
- if hasattr(s, 'resolved'):
+ if hasattr(s, "resolved"):
s = s.resolved
sec = s.section
- if env.arch.separate_rodata and sec.name.startswith('.rodata'):
- raise LinkError('fixed relocation to rodata with rodata referenced via GOT')
+ if env.arch.separate_rodata and sec.name.startswith(".rodata"):
+ raise LinkError("fixed relocation to rodata with rodata referenced via GOT")
- if sec.name.startswith('.bss'):
- raise LinkError('{}: fixed relocation to bss (bss variables can\'t be static)'.format(s.filename))
+ if sec.name.startswith(".bss"):
+ raise LinkError(
+ "{}: fixed relocation to bss (bss variables can't be static)".format(s.filename)
+ )
- if sec.name.startswith('.external'):
- raise LinkError('{}: fixed relocation to external symbol: {}'.format(s.filename, s.name))
+ if sec.name.startswith(".external"):
+ raise LinkError(
+ "{}: fixed relocation to external symbol: {}".format(s.filename, s.name)
+ )
- addr = sec.addr + s['st_value']
+ addr = sec.addr + s["st_value"]
reloc = addr - r_offset + r_addend
if r_info_type in (R_ARM_THM_CALL, R_ARM_THM_JUMP24):
# Both relocations have the same bit pattern to rewrite:
# R_ARM_THM_CALL: bl
# R_ARM_THM_JUMP24: b.w
- reloc_type = 'thumb_b'
-
- elif (env.arch.name == 'EM_386' and r_info_type == R_386_GOTPC
- or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_BASE_PREL
- ):
+ reloc_type = "thumb_b"
+
+ elif (
+ env.arch.name == "EM_386"
+ and r_info_type == R_386_GOTPC
+ or env.arch.name == "EM_ARM"
+ and r_info_type == R_ARM_BASE_PREL
+ ):
# Relocation to GOT address itself
- assert s.name == '_GLOBAL_OFFSET_TABLE_'
+ assert s.name == "_GLOBAL_OFFSET_TABLE_"
addr = env.got_section.addr
reloc = addr - r_offset + r_addend
- elif (env.arch.name == 'EM_386' and r_info_type in (R_386_GOT32, R_386_GOT32X)
- or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_GOT_BREL
- ):
+ elif (
+ env.arch.name == "EM_386"
+ and r_info_type in (R_386_GOT32, R_386_GOT32X)
+ or env.arch.name == "EM_ARM"
+ and r_info_type == R_ARM_GOT_BREL
+ ):
# Relcation pointing to GOT
reloc = addr = env.got_entries[s.name].offset
- elif env.arch.name == 'EM_X86_64' and r_info_type == R_X86_64_REX_GOTPCRELX:
+ elif env.arch.name == "EM_X86_64" and r_info_type == R_X86_64_REX_GOTPCRELX:
# Relcation pointing to GOT
got_entry = env.got_entries[s.name]
addr = env.got_section.addr + got_entry.offset
reloc = addr - r_offset + r_addend
- elif env.arch.name == 'EM_386' and r_info_type == R_386_GOTOFF:
+ elif env.arch.name == "EM_386" and r_info_type == R_386_GOTOFF:
# Relocation relative to GOT
- addr = s.section.addr + s['st_value']
+ addr = s.section.addr + s["st_value"]
reloc = addr - env.got_section.addr + r_addend
- elif env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_SLOT0_OP:
+ elif env.arch.name == "EM_XTENSA" and r_info_type == R_XTENSA_SLOT0_OP:
# Relocation pointing to GOT, xtensa specific
sec = s.section
- if sec.name.startswith('.text'):
+ if sec.name.startswith(".text"):
# it looks like R_XTENSA_SLOT0_OP into .text is already correctly relocated
return
- assert sec.name.startswith('.literal'), sec.name
- lit_idx = '{}+0x{:x}'.format(sec.filename, r_addend)
+ assert sec.name.startswith(".literal"), sec.name
+ lit_idx = "{}+0x{:x}".format(sec.filename, r_addend)
lit_ptr = env.xt_literals[lit_idx]
if isinstance(lit_ptr, str):
addr = env.got_section.addr + env.got_entries[lit_ptr].offset
- log_name = 'GOT {}'.format(lit_ptr)
+ log_name = "GOT {}".format(lit_ptr)
else:
addr = env.lit_section.addr + env.lit_entries[lit_ptr].offset
- log_name = 'LIT'
+ log_name = "LIT"
reloc = addr - r_offset
- reloc_type = 'xtensa_l32r'
+ reloc_type = "xtensa_l32r"
- elif env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_DIFF32:
- if s.section.name.startswith('.text'):
+ elif env.arch.name == "EM_XTENSA" and r_info_type == R_XTENSA_DIFF32:
+ if s.section.name.startswith(".text"):
# it looks like R_XTENSA_DIFF32 into .text is already correctly relocated
return
assert 0
@@ -499,196 +576,216 @@ def do_relocation_text(env, text_addr, r):
assert 0, r_info_type
# Write relocation
- if reloc_type == 'le32':
- existing, = struct.unpack_from('<I', env.full_text, r_offset)
- struct.pack_into('<I', env.full_text, r_offset, (existing + reloc) & 0xffffffff)
- elif reloc_type == 'thumb_b':
- b_h, b_l = struct.unpack_from('<HH', env.full_text, r_offset)
- existing = (b_h & 0x7ff) << 12 | (b_l & 0x7ff) << 1
- if existing >= 0x400000: # 2's complement
+ if reloc_type == "le32":
+ (existing,) = struct.unpack_from("<I", env.full_text, r_offset)
+ struct.pack_into("<I", env.full_text, r_offset, (existing + reloc) & 0xFFFFFFFF)
+ elif reloc_type == "thumb_b":
+ b_h, b_l = struct.unpack_from("<HH", env.full_text, r_offset)
+ existing = (b_h & 0x7FF) << 12 | (b_l & 0x7FF) << 1
+ if existing >= 0x400000: # 2's complement
existing -= 0x800000
new = existing + reloc
- b_h = (b_h & 0xf800) | (new >> 12) & 0x7ff
- b_l = (b_l & 0xf800) | (new >> 1) & 0x7ff
- struct.pack_into('<HH', env.full_text, r_offset, b_h, b_l)
- elif reloc_type == 'xtensa_l32r':
+ b_h = (b_h & 0xF800) | (new >> 12) & 0x7FF
+ b_l = (b_l & 0xF800) | (new >> 1) & 0x7FF
+ struct.pack_into("<HH", env.full_text, r_offset, b_h, b_l)
+ elif reloc_type == "xtensa_l32r":
l32r = unpack_u24le(env.full_text, r_offset)
- assert l32r & 0xf == 1 # RI16 encoded l32r
+ assert l32r & 0xF == 1 # RI16 encoded l32r
l32r_imm16 = l32r >> 8
- l32r_imm16 = (l32r_imm16 + reloc >> 2) & 0xffff
- l32r = l32r & 0xff | l32r_imm16 << 8
+ l32r_imm16 = (l32r_imm16 + reloc >> 2) & 0xFFFF
+ l32r = l32r & 0xFF | l32r_imm16 << 8
pack_u24le(env.full_text, r_offset, l32r)
else:
assert 0, reloc_type
# Log information about relocation
if log_name is None:
- if s_type == 'STT_SECTION':
+ if s_type == "STT_SECTION":
log_name = s.section.name
else:
log_name = s.name
- log(LOG_LEVEL_3, ' {:08x} {} -> {:08x}'.format(r_offset, log_name, addr))
+ log(LOG_LEVEL_3, " {:08x} {} -> {:08x}".format(r_offset, log_name, addr))
+
def do_relocation_data(env, text_addr, r):
s = r.sym
- s_type = s.entry['st_info']['type']
- r_offset = r['r_offset'] + text_addr
- r_info_type = r['r_info_type']
+ s_type = s.entry["st_info"]["type"]
+ r_offset = r["r_offset"] + text_addr
+ r_info_type = r["r_info_type"]
try:
# only for RELA sections
- r_addend = r['r_addend']
+ r_addend = r["r_addend"]
except KeyError:
r_addend = 0
- if (env.arch.name == 'EM_386' and r_info_type == R_386_32
- or env.arch.name == 'EM_X86_64' and r_info_type == R_X86_64_64
- or env.arch.name == 'EM_ARM' and r_info_type == R_ARM_ABS32
- or env.arch.name == 'EM_XTENSA' and r_info_type == R_XTENSA_32):
+ if (
+ env.arch.name == "EM_386"
+ and r_info_type == R_386_32
+ or env.arch.name == "EM_X86_64"
+ and r_info_type == R_X86_64_64
+ or env.arch.name == "EM_ARM"
+ and r_info_type == R_ARM_ABS32
+ or env.arch.name == "EM_XTENSA"
+ and r_info_type == R_XTENSA_32
+ ):
# Relocation in data.rel.ro to internal/external symbol
if env.arch.word_size == 4:
- struct_type = '<I'
+ struct_type = "<I"
elif env.arch.word_size == 8:
- struct_type = '<Q'
+ struct_type = "<Q"
sec = s.section
assert r_offset % env.arch.word_size == 0
- addr = sec.addr + s['st_value'] + r_addend
- if s_type == 'STT_SECTION':
+ addr = sec.addr + s["st_value"] + r_addend
+ if s_type == "STT_SECTION":
log_name = sec.name
else:
log_name = s.name
- log(LOG_LEVEL_3, ' {:08x} -> {} {:08x}'.format(r_offset, log_name, addr))
+ log(LOG_LEVEL_3, " {:08x} -> {} {:08x}".format(r_offset, log_name, addr))
if env.arch.separate_rodata:
data = env.full_rodata
else:
data = env.full_text
- existing, = struct.unpack_from(struct_type, data, r_offset)
- if sec.name.startswith(('.text', '.rodata', '.data.rel.ro', '.bss')):
+ (existing,) = struct.unpack_from(struct_type, data, r_offset)
+ if sec.name.startswith((".text", ".rodata", ".data.rel.ro", ".bss")):
struct.pack_into(struct_type, data, r_offset, existing + addr)
kind = sec.name
- elif sec.name == '.external.mp_fun_table':
+ elif sec.name == ".external.mp_fun_table":
assert addr == 0
kind = s.mp_fun_table_offset
else:
assert 0, sec.name
if env.arch.separate_rodata:
- base = '.rodata'
+ base = ".rodata"
else:
- base = '.text'
+ base = ".text"
env.mpy_relocs.append((base, r_offset, kind))
else:
# Unknown/unsupported relocation
assert 0, r_info_type
+
def load_object_file(env, felf):
- with open(felf, 'rb') as f:
+ with open(felf, "rb") as f:
elf = elffile.ELFFile(f)
- env.check_arch(elf['e_machine'])
+ env.check_arch(elf["e_machine"])
# Get symbol table
- symtab = list(elf.get_section_by_name('.symtab').iter_symbols())
+ symtab = list(elf.get_section_by_name(".symtab").iter_symbols())
# Load needed sections from ELF file
- sections_shndx = {} # maps elf shndx to Section object
+ sections_shndx = {} # maps elf shndx to Section object
for idx, s in enumerate(elf.iter_sections()):
- if s.header.sh_type in ('SHT_PROGBITS', 'SHT_NOBITS'):
+ if s.header.sh_type in ("SHT_PROGBITS", "SHT_NOBITS"):
if s.data_size == 0:
# Ignore empty sections
pass
- elif s.name.startswith(('.literal', '.text', '.rodata', '.data.rel.ro', '.bss')):
+ elif s.name.startswith((".literal", ".text", ".rodata", ".data.rel.ro", ".bss")):
sec = Section.from_elfsec(s, felf)
sections_shndx[idx] = sec
- if s.name.startswith('.literal'):
+ if s.name.startswith(".literal"):
env.literal_sections.append(sec)
else:
env.sections.append(sec)
- elif s.name.startswith('.data'):
- raise LinkError('{}: {} non-empty'.format(felf, s.name))
+ elif s.name.startswith(".data"):
+ raise LinkError("{}: {} non-empty".format(felf, s.name))
else:
# Ignore section
pass
- elif s.header.sh_type in ('SHT_REL', 'SHT_RELA'):
+ elif s.header.sh_type in ("SHT_REL", "SHT_RELA"):
shndx = s.header.sh_info
if shndx in sections_shndx:
sec = sections_shndx[shndx]
sec.reloc_name = s.name
sec.reloc = list(s.iter_relocations())
for r in sec.reloc:
- r.sym = symtab[r['r_info_sym']]
+ r.sym = symtab[r["r_info_sym"]]
# Link symbols to their sections, and update known and unresolved symbols
for sym in symtab:
sym.filename = felf
- shndx = sym.entry['st_shndx']
+ shndx = sym.entry["st_shndx"]
if shndx in sections_shndx:
# Symbol with associated section
sym.section = sections_shndx[shndx]
- if sym['st_info']['bind'] == 'STB_GLOBAL':
+ if sym["st_info"]["bind"] == "STB_GLOBAL":
# Defined global symbol
- if sym.name in env.known_syms and not sym.name.startswith('__x86.get_pc_thunk.'):
- raise LinkError('duplicate symbol: {}'.format(sym.name))
+ if sym.name in env.known_syms and not sym.name.startswith(
+ "__x86.get_pc_thunk."
+ ):
+ raise LinkError("duplicate symbol: {}".format(sym.name))
env.known_syms[sym.name] = sym
- elif sym.entry['st_shndx'] == 'SHN_UNDEF' and sym['st_info']['bind'] == 'STB_GLOBAL':
+ elif sym.entry["st_shndx"] == "SHN_UNDEF" and sym["st_info"]["bind"] == "STB_GLOBAL":
# Undefined global symbol, needs resolving
env.unresolved_syms.append(sym)
+
def link_objects(env, native_qstr_vals_len, native_qstr_objs_len):
# Build GOT information
- if env.arch.name == 'EM_XTENSA':
+ if env.arch.name == "EM_XTENSA":
build_got_xtensa(env)
else:
build_got_generic(env)
# Creat GOT section
got_size = len(env.got_entries) * env.arch.word_size
- env.got_section = Section('GOT', bytearray(got_size), env.arch.word_size)
- if env.arch.name == 'EM_XTENSA':
+ env.got_section = Section("GOT", bytearray(got_size), env.arch.word_size)
+ if env.arch.name == "EM_XTENSA":
env.sections.insert(0, env.got_section)
else:
env.sections.append(env.got_section)
# Create optional literal section
- if env.arch.name == 'EM_XTENSA':
+ if env.arch.name == "EM_XTENSA":
lit_size = len(env.lit_entries) * env.arch.word_size
- env.lit_section = Section('LIT', bytearray(lit_size), env.arch.word_size)
+ env.lit_section = Section("LIT", bytearray(lit_size), env.arch.word_size)
env.sections.insert(1, env.lit_section)
# Create section to contain mp_native_qstr_val_table
- env.qstr_val_section = Section('.text.QSTR_VAL', bytearray(native_qstr_vals_len * env.arch.qstr_entry_size), env.arch.qstr_entry_size)
+ env.qstr_val_section = Section(
+ ".text.QSTR_VAL",
+ bytearray(native_qstr_vals_len * env.arch.qstr_entry_size),
+ env.arch.qstr_entry_size,
+ )
env.sections.append(env.qstr_val_section)
# Create section to contain mp_native_qstr_obj_table
- env.qstr_obj_section = Section('.text.QSTR_OBJ', bytearray(native_qstr_objs_len * env.arch.word_size), env.arch.word_size)
+ env.qstr_obj_section = Section(
+ ".text.QSTR_OBJ", bytearray(native_qstr_objs_len * env.arch.word_size), env.arch.word_size
+ )
env.sections.append(env.qstr_obj_section)
# Resolve unknown symbols
- mp_fun_table_sec = Section('.external.mp_fun_table', b'', 0)
- fun_table = {key: 67 + idx
- for idx, key in enumerate([
- 'mp_type_type',
- 'mp_type_str',
- 'mp_type_list',
- 'mp_type_dict',
- 'mp_type_fun_builtin_0',
- 'mp_type_fun_builtin_1',
- 'mp_type_fun_builtin_2',
- 'mp_type_fun_builtin_3',
- 'mp_type_fun_builtin_var',
- 'mp_stream_read_obj',
- 'mp_stream_readinto_obj',
- 'mp_stream_unbuffered_readline_obj',
- 'mp_stream_write_obj',
- ])
+ mp_fun_table_sec = Section(".external.mp_fun_table", b"", 0)
+ fun_table = {
+ key: 67 + idx
+ for idx, key in enumerate(
+ [
+ "mp_type_type",
+ "mp_type_str",
+ "mp_type_list",
+ "mp_type_dict",
+ "mp_type_fun_builtin_0",
+ "mp_type_fun_builtin_1",
+ "mp_type_fun_builtin_2",
+ "mp_type_fun_builtin_3",
+ "mp_type_fun_builtin_var",
+ "mp_stream_read_obj",
+ "mp_stream_readinto_obj",
+ "mp_stream_unbuffered_readline_obj",
+ "mp_stream_write_obj",
+ ]
+ )
}
for sym in env.unresolved_syms:
- assert sym['st_value'] == 0
- if sym.name == '_GLOBAL_OFFSET_TABLE_':
+ assert sym["st_value"] == 0
+ if sym.name == "_GLOBAL_OFFSET_TABLE_":
pass
- elif sym.name == 'mp_fun_table':
- sym.section = Section('.external', b'', 0)
- elif sym.name == 'mp_native_qstr_val_table':
+ elif sym.name == "mp_fun_table":
+ sym.section = Section(".external", b"", 0)
+ elif sym.name == "mp_native_qstr_val_table":
sym.section = env.qstr_val_section
- elif sym.name == 'mp_native_qstr_obj_table':
+ elif sym.name == "mp_native_qstr_obj_table":
sym.section = env.qstr_obj_section
elif sym.name in env.known_syms:
sym.resolved = env.known_syms[sym.name]
@@ -697,48 +794,53 @@ def link_objects(env, native_qstr_vals_len, native_qstr_objs_len):
sym.section = mp_fun_table_sec
sym.mp_fun_table_offset = fun_table[sym.name]
else:
- raise LinkError('{}: undefined symbol: {}'.format(sym.filename, sym.name))
+ raise LinkError("{}: undefined symbol: {}".format(sym.filename, sym.name))
# Align sections, assign their addresses, and create full_text
- env.full_text = bytearray(env.arch.asm_jump(8)) # dummy, to be filled in later
+ env.full_text = bytearray(env.arch.asm_jump(8)) # dummy, to be filled in later
env.full_rodata = bytearray(0)
env.full_bss = bytearray(0)
for sec in env.sections:
- if env.arch.separate_rodata and sec.name.startswith(('.rodata', '.data.rel.ro')):
+ if env.arch.separate_rodata and sec.name.startswith((".rodata", ".data.rel.ro")):
data = env.full_rodata
- elif sec.name.startswith('.bss'):
+ elif sec.name.startswith(".bss"):
data = env.full_bss
else:
data = env.full_text
sec.addr = align_to(len(data), sec.alignment)
- data.extend(b'\x00' * (sec.addr - len(data)))
+ data.extend(b"\x00" * (sec.addr - len(data)))
data.extend(sec.data)
env.print_sections()
populate_got(env)
- if env.arch.name == 'EM_XTENSA':
+ if env.arch.name == "EM_XTENSA":
populate_lit(env)
# Fill in relocations
for sec in env.sections:
if not sec.reloc:
continue
- log(LOG_LEVEL_3, '{}: {} relocations via {}:'.format(sec.filename, sec.name, sec.reloc_name))
+ log(
+ LOG_LEVEL_3,
+ "{}: {} relocations via {}:".format(sec.filename, sec.name, sec.reloc_name),
+ )
for r in sec.reloc:
- if sec.name.startswith(('.text', '.rodata')):
+ if sec.name.startswith((".text", ".rodata")):
do_relocation_text(env, sec.addr, r)
- elif sec.name.startswith('.data.rel.ro'):
+ elif sec.name.startswith(".data.rel.ro"):
do_relocation_data(env, sec.addr, r)
else:
assert 0, sec.name
+
################################################################################
# .mpy output
+
class MPYOutput:
def open(self, fname):
- self.f = open(fname, 'wb')
+ self.f = open(fname, "wb")
self.prev_base = -1
self.prev_offset = -1
@@ -750,10 +852,10 @@ class MPYOutput:
def write_uint(self, val):
b = bytearray()
- b.insert(0, val & 0x7f)
+ b.insert(0, val & 0x7F)
val >>= 7
while val:
- b.insert(0, 0x80 | (val & 0x7f))
+ b.insert(0, 0x80 | (val & 0x7F))
val >>= 7
self.write_bytes(b)
@@ -761,7 +863,7 @@ class MPYOutput:
if s in qstrutil.static_qstr_list:
self.write_bytes(bytes([0, qstrutil.static_qstr_list.index(s) + 1]))
else:
- s = bytes(s, 'ascii')
+ s = bytes(s, "ascii")
self.write_uint(len(s) << 1)
self.write_bytes(s)
@@ -774,42 +876,41 @@ class MPYOutput:
assert 6 <= dest <= 127
assert n == 1
dest = dest << 1 | need_offset
- assert 0 <= dest <= 0xfe, dest
+ assert 0 <= dest <= 0xFE, dest
self.write_bytes(bytes([dest]))
if need_offset:
- if base == '.text':
+ if base == ".text":
base = 0
- elif base == '.rodata':
+ elif base == ".rodata":
base = 1
self.write_uint(offset << 1 | base)
if n > 1:
self.write_uint(n)
+
def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs):
# Write jump instruction to start of text
jump = env.arch.asm_jump(entry_offset)
- env.full_text[:len(jump)] = jump
+ env.full_text[: len(jump)] = jump
- log(LOG_LEVEL_1, 'arch: {}'.format(env.arch.name))
- log(LOG_LEVEL_1, 'text size: {}'.format(len(env.full_text)))
+ log(LOG_LEVEL_1, "arch: {}".format(env.arch.name))
+ log(LOG_LEVEL_1, "text size: {}".format(len(env.full_text)))
if len(env.full_rodata):
- log(LOG_LEVEL_1, 'rodata size: {}'.format(len(env.full_rodata)))
- log(LOG_LEVEL_1, 'bss size: {}'.format(len(env.full_bss)))
- log(LOG_LEVEL_1, 'GOT entries: {}'.format(len(env.got_entries)))
+ log(LOG_LEVEL_1, "rodata size: {}".format(len(env.full_rodata)))
+ log(LOG_LEVEL_1, "bss size: {}".format(len(env.full_bss)))
+ log(LOG_LEVEL_1, "GOT entries: {}".format(len(env.got_entries)))
- #xxd(env.full_text)
+ # xxd(env.full_text)
out = MPYOutput()
out.open(fmpy)
# MPY: header
- out.write_bytes(bytearray([
- ord('M'),
- MPY_VERSION,
- env.arch.mpy_feature,
- MP_SMALL_INT_BITS,
- QSTR_WINDOW_SIZE,
- ]))
+ out.write_bytes(
+ bytearray(
+ [ord("M"), MPY_VERSION, env.arch.mpy_feature, MP_SMALL_INT_BITS, QSTR_WINDOW_SIZE,]
+ )
+ )
# MPY: kind/len
out.write_uint(len(env.full_text) << 2 | (MP_CODE_NATIVE_VIPER - MP_CODE_BYTECODE))
@@ -854,16 +955,16 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs):
# MPY: relocation information
prev_kind = None
for base, addr, kind in env.mpy_relocs:
- if isinstance(kind, str) and kind.startswith('.text'):
+ if isinstance(kind, str) and kind.startswith(".text"):
kind = 0
- elif kind in ('.rodata', '.data.rel.ro'):
+ elif kind in (".rodata", ".data.rel.ro"):
if env.arch.separate_rodata:
kind = rodata_const_table_idx
else:
kind = 0
- elif isinstance(kind, str) and kind.startswith('.bss'):
+ elif isinstance(kind, str) and kind.startswith(".bss"):
kind = bss_const_table_idx
- elif kind == 'mp_fun_table':
+ elif kind == "mp_fun_table":
kind = 6
else:
kind = 7 + kind
@@ -883,73 +984,88 @@ def build_mpy(env, entry_offset, fmpy, native_qstr_vals, native_qstr_objs):
out.write_reloc(prev_base, prev_offset - prev_n + 1, prev_kind, prev_n)
# MPY: sentinel for end of relocations
- out.write_bytes(b'\xff')
+ out.write_bytes(b"\xff")
out.close()
+
################################################################################
# main
+
def do_preprocess(args):
if args.output is None:
- assert args.files[0].endswith('.c')
- args.output = args.files[0][:-1] + 'config.h'
+ assert args.files[0].endswith(".c")
+ args.output = args.files[0][:-1] + "config.h"
static_qstrs, qstr_vals, qstr_objs = extract_qstrs(args.files)
- with open(args.output, 'w') as f:
- print('#include <stdint.h>\n'
- 'typedef uintptr_t mp_uint_t;\n'
- 'typedef intptr_t mp_int_t;\n'
- 'typedef uintptr_t mp_off_t;', file=f)
+ with open(args.output, "w") as f:
+ print(
+ "#include <stdint.h>\n"
+ "typedef uintptr_t mp_uint_t;\n"
+ "typedef intptr_t mp_int_t;\n"
+ "typedef uintptr_t mp_off_t;",
+ file=f,
+ )
for i, q in enumerate(static_qstrs):
- print('#define %s (%u)' % (q, i + 1), file=f)
+ print("#define %s (%u)" % (q, i + 1), file=f)
for i, q in enumerate(sorted(qstr_vals)):
- print('#define %s (mp_native_qstr_val_table[%d])' % (q, i), file=f)
+ print("#define %s (mp_native_qstr_val_table[%d])" % (q, i), file=f)
for i, q in enumerate(sorted(qstr_objs)):
- print('#define MP_OBJ_NEW_QSTR_%s ((mp_obj_t)mp_native_qstr_obj_table[%d])' % (q, i), file=f)
- if args.arch == 'xtensawin':
- qstr_type = 'uint32_t' # esp32 can only read 32-bit values from IRAM
+ print(
+ "#define MP_OBJ_NEW_QSTR_%s ((mp_obj_t)mp_native_qstr_obj_table[%d])" % (q, i),
+ file=f,
+ )
+ if args.arch == "xtensawin":
+ qstr_type = "uint32_t" # esp32 can only read 32-bit values from IRAM
else:
- qstr_type = 'uint16_t'
- print('extern const {} mp_native_qstr_val_table[];'.format(qstr_type), file=f)
- print('extern const mp_uint_t mp_native_qstr_obj_table[];', file=f)
+ qstr_type = "uint16_t"
+ print("extern const {} mp_native_qstr_val_table[];".format(qstr_type), file=f)
+ print("extern const mp_uint_t mp_native_qstr_obj_table[];", file=f)
+
def do_link(args):
if args.output is None:
- assert args.files[0].endswith('.o')
- args.output = args.files[0][:-1] + 'mpy'
+ assert args.files[0].endswith(".o")
+ args.output = args.files[0][:-1] + "mpy"
native_qstr_vals = []
native_qstr_objs = []
if args.qstrs is not None:
with open(args.qstrs) as f:
for l in f:
- m = re.match(r'#define MP_QSTR_([A-Za-z0-9_]*) \(mp_native_', l)
+ m = re.match(r"#define MP_QSTR_([A-Za-z0-9_]*) \(mp_native_", l)
if m:
native_qstr_vals.append(m.group(1))
else:
- m = re.match(r'#define MP_OBJ_NEW_QSTR_MP_QSTR_([A-Za-z0-9_]*)', l)
+ m = re.match(r"#define MP_OBJ_NEW_QSTR_MP_QSTR_([A-Za-z0-9_]*)", l)
if m:
native_qstr_objs.append(m.group(1))
- log(LOG_LEVEL_2, 'qstr vals: ' + ', '.join(native_qstr_vals))
- log(LOG_LEVEL_2, 'qstr objs: ' + ', '.join(native_qstr_objs))
+ log(LOG_LEVEL_2, "qstr vals: " + ", ".join(native_qstr_vals))
+ log(LOG_LEVEL_2, "qstr objs: " + ", ".join(native_qstr_objs))
env = LinkEnv(args.arch)
try:
for file in args.files:
load_object_file(env, file)
link_objects(env, len(native_qstr_vals), len(native_qstr_objs))
- build_mpy(env, env.find_addr('mpy_init'), args.output, native_qstr_vals, native_qstr_objs)
+ build_mpy(env, env.find_addr("mpy_init"), args.output, native_qstr_vals, native_qstr_objs)
except LinkError as er:
- print('LinkError:', er.args[0])
+ print("LinkError:", er.args[0])
sys.exit(1)
+
def main():
import argparse
- cmd_parser = argparse.ArgumentParser(description='Run scripts on the pyboard.')
- cmd_parser.add_argument('--verbose', '-v', action='count', default=1, help='increase verbosity')
- cmd_parser.add_argument('--arch', default='x64', help='architecture')
- cmd_parser.add_argument('--preprocess', action='store_true', help='preprocess source files')
- cmd_parser.add_argument('--qstrs', default=None, help='file defining additional qstrs')
- cmd_parser.add_argument('--output', '-o', default=None, help='output .mpy file (default to input with .o->.mpy)')
- cmd_parser.add_argument('files', nargs='+', help='input files')
+
+ cmd_parser = argparse.ArgumentParser(description="Run scripts on the pyboard.")
+ cmd_parser.add_argument(
+ "--verbose", "-v", action="count", default=1, help="increase verbosity"
+ )
+ cmd_parser.add_argument("--arch", default="x64", help="architecture")
+ cmd_parser.add_argument("--preprocess", action="store_true", help="preprocess source files")
+ cmd_parser.add_argument("--qstrs", default=None, help="file defining additional qstrs")
+ cmd_parser.add_argument(
+ "--output", "-o", default=None, help="output .mpy file (default to input with .o->.mpy)"
+ )
+ cmd_parser.add_argument("files", nargs="+", help="input files")
args = cmd_parser.parse_args()
global log_level
@@ -960,5 +1076,6 @@ def main():
else:
do_link(args)
-if __name__ == '__main__':
+
+if __name__ == "__main__":
main()