summaryrefslogtreecommitdiff
path: root/tools/mpy_ld.py
diff options
context:
space:
mode:
Diffstat (limited to 'tools/mpy_ld.py')
-rwxr-xr-xtools/mpy_ld.py140
1 files changed, 84 insertions, 56 deletions
diff --git a/tools/mpy_ld.py b/tools/mpy_ld.py
index 54295208f..44a76bdee 100755
--- a/tools/mpy_ld.py
+++ b/tools/mpy_ld.py
@@ -30,6 +30,7 @@ Link .o files to .mpy
import sys, os, struct, re
from elftools.elf import elffile
+import ar_util
sys.path.append(os.path.dirname(__file__) + "/../py")
import makeqstrdata as qstrutil
@@ -664,7 +665,7 @@ def do_relocation_text(env, text_addr, r):
R_XTENSA_PDIFF32,
R_XTENSA_ASM_EXPAND,
):
- if s.section.name.startswith(".text"):
+ if not hasattr(s, "section") or s.section.name.startswith(".text"):
# it looks like R_XTENSA_[P]DIFF32 into .text is already correctly relocated,
# and expand relaxations cannot occur in non-executable sections.
return
@@ -1075,59 +1076,59 @@ def process_riscv32_relocation(env, text_addr, r):
return addr, value
-def load_object_file(env, felf):
- with open(felf, "rb") as f:
- elf = elffile.ELFFile(f)
- env.check_arch(elf["e_machine"])
-
- # Get symbol table
- symtab = list(elf.get_section_by_name(".symtab").iter_symbols())
-
- # Load needed sections from ELF file
- 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.data_size == 0:
- # Ignore empty sections
- pass
- 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"):
- env.literal_sections.append(sec)
- else:
- env.sections.append(sec)
- elif s.name.startswith(".data"):
- raise LinkError("{}: {} non-empty".format(felf, s.name))
+def load_object_file(env, f, felf):
+ elf = elffile.ELFFile(f)
+ env.check_arch(elf["e_machine"])
+
+ # Get symbol table
+ symtab = list(elf.get_section_by_name(".symtab").iter_symbols())
+
+ # Load needed sections from ELF file
+ 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.data_size == 0:
+ # Ignore empty sections
+ pass
+ 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"):
+ env.literal_sections.append(sec)
else:
- # Ignore section
- pass
- 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"]]
-
- # Link symbols to their sections, and update known and unresolved symbols
- for sym in symtab:
- sym.filename = felf
- shndx = sym.entry["st_shndx"]
+ env.sections.append(sec)
+ 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"):
+ shndx = s.header.sh_info
if shndx in sections_shndx:
- # Symbol with associated section
- sym.section = sections_shndx[shndx]
- if sym["st_info"]["bind"] in ("STB_GLOBAL", "STB_WEAK"):
- # 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))
- env.known_syms[sym.name] = sym
- elif sym.entry["st_shndx"] == "SHN_UNDEF" and sym["st_info"]["bind"] == "STB_GLOBAL":
- # Undefined global symbol, needs resolving
- env.unresolved_syms.append(sym)
+ 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"]]
+
+ # Link symbols to their sections, and update known and unresolved symbols
+ dup_errors = []
+ for sym in symtab:
+ sym.filename = felf
+ shndx = sym.entry["st_shndx"]
+ if shndx in sections_shndx:
+ # Symbol with associated section
+ sym.section = sections_shndx[shndx]
+ if sym["st_info"]["bind"] in ("STB_GLOBAL", "STB_WEAK"):
+ # Defined global symbol
+ if sym.name in env.known_syms and not sym.name.startswith("__x86.get_pc_thunk."):
+ dup_errors.append("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":
+ # Undefined global symbol, needs resolving
+ env.unresolved_syms.append(sym)
+ if len(dup_errors):
+ raise LinkError("\n".join(dup_errors))
def link_objects(env, native_qstr_vals_len):
@@ -1188,6 +1189,8 @@ def link_objects(env, native_qstr_vals_len):
]
)
}
+
+ undef_errors = []
for sym in env.unresolved_syms:
assert sym["st_value"] == 0
if sym.name == "_GLOBAL_OFFSET_TABLE_":
@@ -1205,7 +1208,10 @@ def link_objects(env, native_qstr_vals_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))
+ undef_errors.append("{}: undefined symbol: {}".format(sym.filename, sym.name))
+
+ if len(undef_errors):
+ raise LinkError("\n".join(undef_errors))
# Align sections, assign their addresses, and create full_text
env.full_text = bytearray(env.arch.asm_jump(8)) # dummy, to be filled in later
@@ -1446,8 +1452,27 @@ def do_link(args):
log(LOG_LEVEL_2, "qstr vals: " + ", ".join(native_qstr_vals))
env = LinkEnv(args.arch)
try:
- for file in args.files:
- load_object_file(env, file)
+ # Load object files
+ for fn in args.files:
+ with open(fn, "rb") as f:
+ load_object_file(env, f, fn)
+
+ if args.libs:
+ # Load archive info
+ archives = []
+ for item in args.libs:
+ archives.extend(ar_util.load_archive(item))
+ # List symbols to look for
+ syms = set(sym.name for sym in env.unresolved_syms)
+ # Resolve symbols from libs
+ lib_objs, _ = ar_util.resolve(archives, syms)
+ # Load extra object files from libs
+ for ar, obj in lib_objs:
+ obj_name = ar.fn + ":" + obj
+ log(LOG_LEVEL_2, "using " + obj_name)
+ with ar.open(obj) as f:
+ load_object_file(env, f, obj_name)
+
link_objects(env, len(native_qstr_vals))
build_mpy(env, env.find_addr("mpy_init"), args.output, native_qstr_vals)
except LinkError as er:
@@ -1458,7 +1483,7 @@ def do_link(args):
def main():
import argparse
- cmd_parser = argparse.ArgumentParser(description="Run scripts on the pyboard.")
+ cmd_parser = argparse.ArgumentParser(description="Link native object files into a MPY bundle.")
cmd_parser.add_argument(
"--verbose", "-v", action="count", default=1, help="increase verbosity"
)
@@ -1466,6 +1491,9 @@ def main():
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(
+ "--libs", "-l", dest="libs", action="append", help="static .a libraries to link"
+ )
+ 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")