blob: 83b220f03b10c0ebe720539dceb2dbf9509d6637 [file] [log] [blame]
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
"""Test various utilities for interaction with compiled binaries.
Specifically, we test the following capabilities:
- querying the size of a binary section
- relocating sections within a binary to new addresses
- reading the contents of a binary section
- querying the address of a symbol in the binary
"""
import tvm
from tvm import te
import subprocess
from tvm.contrib import util
from tvm.contrib import cc
from tvm.contrib.binutil import *
TOOLCHAIN_PREFIX = ""
def make_binary():
prog = "int a = 7; \
int main() { \
int b = 5; \
return 0; \
}"
tmp_dir = util.tempdir()
tmp_source = tmp_dir.relpath("source.c")
tmp_obj = tmp_dir.relpath("obj.obj")
with open(tmp_source, "w") as f:
f.write(prog)
cc.create_executable(tmp_obj, tmp_source, [], cc="{}gcc".format(TOOLCHAIN_PREFIX))
prog_bin = bytearray(open(tmp_obj, "rb").read())
return prog_bin
def test_tvm_callback_get_section_size(binary=None):
if binary is None:
binary = make_binary()
tmp_dir = util.tempdir()
tmp_bin = tmp_dir.relpath("obj.bin")
with open(tmp_bin, "wb") as f:
f.write(binary)
def verify():
print(
"Text section size: %d"
% tvm_callback_get_section_size(tmp_bin, "text", TOOLCHAIN_PREFIX)
)
print(
"Data section size: %d"
% tvm_callback_get_section_size(tmp_bin, "data", TOOLCHAIN_PREFIX)
)
print(
"Bss section size: %d" % tvm_callback_get_section_size(tmp_bin, "bss", TOOLCHAIN_PREFIX)
)
print()
verify()
def test_tvm_callback_relocate_binary():
binary = make_binary()
tmp_dir = util.tempdir()
tmp_bin = tmp_dir.relpath("obj.bin")
with open(tmp_bin, "wb") as f:
f.write(binary)
def verify():
word_size = 8
text_loc = 0x0
rodata_loc = 0x10000
data_loc = 0x20000
bss_loc = 0x30000
stack_end = 0x50000
rel_bin = tvm_callback_relocate_binary(
tmp_bin, word_size, text_loc, rodata_loc, data_loc, bss_loc, stack_end, TOOLCHAIN_PREFIX
)
print("Relocated binary section sizes")
test_tvm_callback_get_section_size(binary=rel_bin)
relf = tmp_dir.relpath("rel.bin")
with open(relf, "wb") as f:
f.write(rel_bin)
nm_proc = subprocess.Popen(
["nm", "-C", "--defined-only", relf], stdout=subprocess.PIPE, stderr=subprocess.STDOUT
)
(out, _) = nm_proc.communicate()
symbol_entries = out.decode("utf-8").split("\n")
for entry in symbol_entries:
if len(entry) == 0:
continue
sym_loc, section, sym_name = entry.split(" ")
sym_loc = int(sym_loc, 16)
if section == "T": # text
assert sym_loc >= text_loc and sym_loc < data_loc
elif section == "D": # data
assert sym_loc >= data_loc and sym_loc < bss_loc
elif section == "B": # bss
assert sym_loc >= bss_loc
verify()
def test_tvm_callback_read_binary_section():
binary = make_binary()
def verify():
text_bin = tvm_callback_read_binary_section(binary, "text", TOOLCHAIN_PREFIX)
data_bin = tvm_callback_read_binary_section(binary, "data", TOOLCHAIN_PREFIX)
bss_bin = tvm_callback_read_binary_section(binary, "bss", TOOLCHAIN_PREFIX)
print("Read text section part of binary? %r" % (text_bin in binary))
print("Read data section part of binary? %r" % (data_bin in binary))
print("Read bss section part of binary? %r" % (bss_bin in binary))
print()
verify()
def test_tvm_callback_get_symbol_map():
binary = make_binary()
tmp_dir = util.tempdir()
tmp_bin = tmp_dir.relpath("obj.bin")
with open(tmp_bin, "wb") as f:
f.write(binary)
def verify():
word_size = 8
text_loc = 0x0
rodata_loc = 0x10000
data_loc = 0x20000
bss_loc = 0x30000
stack_end = 0x50000
rel_bin = tvm_callback_relocate_binary(
tmp_bin, word_size, text_loc, rodata_loc, data_loc, bss_loc, stack_end, TOOLCHAIN_PREFIX
)
symbol_map = tvm_callback_get_symbol_map(rel_bin, TOOLCHAIN_PREFIX)
symbols = set()
for i, line in enumerate(symbol_map.split("\n")):
# Every other line is the value the symbol maps to.
if i % 2 == 0:
symbols.add(line)
assert "a" in symbols
assert "main" in symbols
verify()
if __name__ == "__main__":
test_tvm_callback_get_section_size()
test_tvm_callback_relocate_binary()
test_tvm_callback_read_binary_section()
test_tvm_callback_get_symbol_map()