Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

minor improvement and a bug fix #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions scripts/asm_template.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,16 @@
{{s}}:
push {r9, lr}
push {r0, r1}
mov r1, #0x1c
ldr r1, [r1]
ldr r1, .L1{{s}}
mov r0, pc
blx r1
mov r9, r0
pop {r0, r1}
bl {{actname}}
pop {r9, pc}

.L1{{s}}:
.word 0
.size {{s}}, . - {{s}}
{% endfor %}

Expand Down
4 changes: 2 additions & 2 deletions scripts/code_before_data.ld
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@ SECTIONS
. = ALIGN(4);
*(.text) /* .text sections (code) */
*(.text*) /* .text* sections (code) */
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
. = ALIGN(4);
} > all

.data :
{
. = ALIGN(4);
*(.rodata) /* .rodata sections (constants, strings, etc.) */
*(.rodata*) /* .rodata* sections (constants, strings, etc.) */
*(.data) /* .data sections */
*(.data*) /* .data* sections */
. = ALIGN(4);
Expand Down
37 changes: 22 additions & 15 deletions scripts/mkmodule
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ def compile(src_name, args, redefine_symbols = True, macros=[]):
extra += " -O0" if args.no_opt else " -Os"
if macros:
extra = extra + " " + " ".join(macros)
if args.include_paths:
for ip in args.include_paths:
extra += " -I" + ip
compile_data = {"input": src_name, "extra": extra, "output": objname}
# Execute compile command
debug("Compiling '%s'" % src_name, args)
Expand All @@ -63,22 +66,25 @@ def compile(src_name, args, redefine_symbols = True, macros=[]):
global_funcs = get_public_functions_in_object(objname)
debug("Generating temporary object files with wrapped symbols '%s'" % ", ".join(global_funcs), args)
temp_obj = os.path.join(path, fname + '.temp.o')
if os.path.isfile(temp_obj):
os.remove(temp_obj)
os.rename(objname, temp_obj)
sym_renames.clear()
sym_renames.update({n: get_wrapped_name(n) for n in global_funcs})
rename_symbols(temp_obj, objname, sym_renames, args)
local_sym_renames = {}
local_sym_renames.update({n: get_wrapped_name(n) for n in global_funcs})
rename_symbols(temp_obj, objname, local_sym_renames, args)
# Generate ASM for prologue
debug("Generating ASM file for public function prologues", args)
loader = FileSystemLoader(os.path.dirname(os.path.abspath(__file__)))
env = Environment(loader = loader)
tmpl = env.get_template("asm_template.tmpl")
data = tmpl.render({"sym_names": sym_renames})
data = tmpl.render({"sym_names": local_sym_renames})
p_fname = os.path.join(path, fname + "_prologue.s")
with open(p_fname, "wt") as f:
f.write(str(data))
# Assemble prologue data
second_obj = assemble(p_fname, args)
os.remove(p_fname)
sym_renames.update(local_sym_renames)
return [objname, second_obj]
else:
return [objname]
Expand Down Expand Up @@ -167,8 +173,8 @@ def process(output, args):
warn("Ingoring unknown symbol '%s' in relocation list" % s)
ignored[s] = True
continue
if t == "R_ARM_THM_CALL": # PC-relative, safe to ignore
debug("Ignoring relocation R_ARM_THM_CALL for symbol '%s' of type '%s'" % (s, syms[s]["type"]), args)
if t == "R_ARM_THM_CALL" or t == "R_ARM_CALL": # PC-relative, safe to ignore
debug("Ignoring relocation R_ARM_(THM)_CALL for symbol '%s' of type '%s'" % (s, syms[s]["type"]), args)
continue
elif t == "R_ARM_GOT_BREL":
if sym_map[s] == "local" or sym_map[s] == "exported":
Expand All @@ -187,7 +193,7 @@ def process(output, args):
# There's a single mapping for any symbol, even if there are multiple relocations for the symbol
reloc_name_to_idx = {}
for e in rlist:
if not reloc_name_to_idx.has_key(e["name"]):
if e["name"] not in reloc_name_to_idx:
reloc_name_to_idx[e["name"]] = lot_entries
lot_entries += 1
total_relocs += 1
Expand All @@ -203,11 +209,11 @@ def process(output, args):
ignored[s] = True
continue
if t == "R_ARM_ABS32":
offset = (offset - len(code_sect)) / 4
offset = (offset - len(code_sect)) // 4
check(offset >= 0, "Offset of R_ARM_ABS32 symbols '%s' should be positive or 0!" % s)
data_relocs.append((s, delta_off + offset, value))
debug("Found data relocation for symbol '%s' (offset is %X, value is %x)" % (s, delta_off + offset, value), args)
if not reloc_name_to_idx.has_key(s):
if s not in reloc_name_to_idx:
reloc_name_to_idx[s] = delta_off + offset
total_relocs += 1
print_list([l["name"] for l in rlist], "Final LOT relocation list:", args)
Expand Down Expand Up @@ -249,9 +255,9 @@ def process(output, args):

set_debug_col('magenta')
debug("%s Building image %s" % ('-' * 10, '-' * 10), args)
img = bytearray("UDLM") # Signature (4b)
img = bytearray(b"UDLM") # Signature (4b)
# The first entry in the symbol table is always the module name
slist = [args.name] + [s for s in sym_map if reloc_name_to_idx.has_key(s) or sym_map[s] == "external" or sym_map[s] == "exported"]
slist = [args.name] + [s for s in sym_map if s in reloc_name_to_idx or sym_map[s] == "external" or sym_map[s] == "exported"]
img += struct.pack("<H", lot_entries) # LOT size (4b)
img += struct.pack("<H", total_relocs) # Total number of relocations (4b)
# Compute len of symbol table in advance (also name to symbol table index mapping (symt_mapping))
Expand Down Expand Up @@ -312,16 +318,16 @@ def process(output, args):
# Pass 2: write actual symbols
for i, s in enumerate(slist):
if i == 0 or sym_map[s] != "local":
img += s + '\0'
img += py3compat.str2bytes(s) + b'\0'
# Round to a multiple of 4
if len(img) % 4 > 0:
img += '\0' * (4 - len(img) % 4)
img += b'\0' * (4 - len(img) % 4)
# And finally append the code
img = img + code_sect + data_sect
bin_name = args.name + ".bin"
with open(bin_name, "wb") as f:
f.write(img)
print "Image written to '%s'." % bin_name
print ("Image written to '%s'." % bin_name)
set_debug_col()
return bin_name

Expand All @@ -340,7 +346,7 @@ def gen_c_header(bin_name, header_path, args):
f.write("static const unsigned char %s_module_data[] = {\n " % fname)
cnt = 0
for idx, c in enumerate(bin_data):
f.write("0x%02X" % ord(c))
f.write("0x%02X" % py3compat.byte2int(c))
if idx < len(bin_data) - 1:
f.write(",")
cnt += 1
Expand All @@ -361,6 +367,7 @@ parser.add_argument("--stop-after-compile", dest="stop_after_compile", action="s
parser.add_argument("--stop-after-link", dest="stop_after_link", action="store_true", help="Stop after linking")
parser.add_argument("--gen-c-header", dest="gen_c_header", action="store_true", help="Generate the C header after processing (default: false)")
parser.add_argument("--header-path", dest="header_path", default=".", help="Path for the generated header (default: current dir)")
parser.add_argument("--include-path", dest="include_paths", action='append', help="Includes paths (can be repeated)")
parser.add_argument("--name", dest="name", default=None, help="Module name (default is inferred from the namae of first source)")
args, rest = parser.parse_known_args()
if len(rest) == 0:
Expand Down
69 changes: 69 additions & 0 deletions scripts/py3compat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
#-------------------------------------------------------------------------------
# py3compat.py
#
# Some Python2&3 compatibility code
#-------------------------------------------------------------------------------
import sys
PY3 = sys.version_info[0] == 3


if PY3:
import io
StringIO = io.StringIO
BytesIO = io.BytesIO

def bchr(i):
""" When iterating over b'...' in Python 2 you get single b'_' chars
and in Python 3 you get integers. Call bchr to always turn this
to single b'_' chars.
"""
return bytes((i,))

def u(s):
return s

def int2byte(i):
return bytes((i,))

def byte2int(b):
return b

def str2bytes(s):
return s.encode("latin-1")

def str2unicode(s):
return s

def bytes2str(b):
return b.decode('latin-1')

def decodebytes(b, encoding):
return bytes(b, encoding)

advance_iterator = next

else:
import cStringIO
StringIO = BytesIO = cStringIO.StringIO

int2byte = chr
byte2int = ord
bchr = lambda i: i

def u(s):
return unicode(s, "unicode_escape")

def str2bytes(s):
return s

def str2unicode(s):
return unicode(s, "unicode_escape")

def bytes2str(b):
return b

def decodebytes(b, encoding):
return b.decode(encoding)

def advance_iterator(it):
return it.next()
8 changes: 5 additions & 3 deletions scripts/udynlink_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os, sys
import argparse
import hashlib
import py3compat
from elftools.elf.elffile import ELFFile
from elftools.elf.relocation import RelocationSection
from elftools.elf.sections import SymbolTableSection
Expand Down Expand Up @@ -39,7 +40,7 @@ def blue(s):

def execute(cmd, args, exit_on_error = True):
if not args.no_verbose:
print "[Executing] " + cmd
print ("[Executing] " + cmd)
res = os.system(cmd)
if (res != 0) and exit_on_error:
sys.exit(1)
Expand All @@ -66,14 +67,15 @@ def change_ext(name, new_ext):
return os.path.join(path, fname + new_ext)

def get_wrapped_name(n):
s = hashlib.md5(n).hexdigest()
nb = py3compat.str2bytes(n)
s = hashlib.md5(nb).hexdigest()
return "__%s__%s" % (s[:9], n)

debug_col = 'blue'
def debug(msg, args, col = None):
if not args.no_debug:
col = col or debug_col
print "%s %s" % (red("[debug]"), bold(msg, col))
print ("%s %s" % (red("[debug]"), bold(msg, col)))

def set_debug_col(col = None):
global debug_col
Expand Down
19 changes: 18 additions & 1 deletion udynlink/udynlink.c
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ static const char * const error_codes[] = {
#define UDYNLINK_LOAD_IS_FOREIGN_RAM(p_mod) ((p_mod->info & UDYNLINK_LOAD_FOREIGN_RAM_MASK) != 0)
#define UDYNLINK_LOAD_SET_FOREIGN_RAM(p_mod) p_mod->info |= UDYNLINK_LOAD_FOREIGN_RAM_MASK
#define UDYNLINK_LOAD_CLR_FOREIGN_RAM(p_mod) p_mod->info &= (uint8_t)~UDYNLINK_LOAD_FOREIGN_RAM_MASK

#define UDYNLINK_ASM_PROLOGUE_LEN 18 // this shall match the preamble code length in bytes
////////////////////////////////////////////////////////////////////////////////
// Helpers - debug

Expand Down Expand Up @@ -409,6 +409,23 @@ udynlink_sym_t *udynlink_lookup_symbol(const udynlink_module_t *p_mod, const cha
return NULL;
}

void udynlink_patch_exported_func(const udynlink_module_t *p_mod) {
uint32_t idx;
udynlink_sym_t sym;
for (uint32_t i = 0; i < UDYNLINK_MAX_HANDLES; i ++) { // iterate through all modules
if ((p_mod == NULL) || (p_mod == module_table + i)) { // but consider only the given one if not NULL
idx = 0;
while (get_sym_at(module_table + i, idx ++, &sym) != NULL) { // iterate through module's symbol table
if (sym.type == UDYNLINK_SYM_TYPE_EXPORTED &&
sym.location == UDYNLINK_SYM_LOCATION_CODE) {
offset_sym(module_table + i, &sym);
(*(uint32_t*) (sym.val + UDYNLINK_ASM_PROLOGUE_LEN)) = (uint32_t)&udynlink_get_lot_base;
}
}
}
}
}

uint32_t udynlink_get_symbol_value(const udynlink_module_t *p_mod, const char *name) {
udynlink_sym_t sym;

Expand Down
3 changes: 3 additions & 0 deletions udynlink/udynlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ udynlink_module_t *udynlink_lookup_module(const char *name);
// Returns p_sym if the symbol is found, false otherwise.
udynlink_sym_t *udynlink_lookup_symbol(const udynlink_module_t *p_mod, const char *name, udynlink_sym_t *p_sym);

// patch the exported functions with the address of the udynlink_get_lot_base function
void udynlink_patch_exported_func(const udynlink_module_t *p_mod);

// Lookup the given symbol. Returns its value if found, 0 otherwise.
uint32_t udynlink_get_symbol_value(const udynlink_module_t *p_mod, const char *name);

Expand Down