summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTrygve Laugstøl <trygvis@inamo.no>2016-07-01 22:57:09 +0200
committerTrygve Laugstøl <trygvis@inamo.no>2016-07-01 22:57:09 +0200
commitc09d293d2b34d15e8bf609466d55555c74587845 (patch)
treeeebf4c9db5d0809cd2ba35ef7d7660bc3c66fbd7
parent3bf71c66f63f33471b172570a3a20710d6fe6b72 (diff)
downloadintel-quark-d2000-playground-c09d293d2b34d15e8bf609466d55555c74587845.tar.gz
intel-quark-d2000-playground-c09d293d2b34d15e8bf609466d55555c74587845.tar.bz2
intel-quark-d2000-playground-c09d293d2b34d15e8bf609466d55555c74587845.tar.xz
intel-quark-d2000-playground-c09d293d2b34d15e8bf609466d55555c74587845.zip
o Adding elfinfo tool from the stm32 playground.
-rw-r--r--apps/accel/CMakeLists.txt1
-rw-r--r--cmake/elfinfo/.gitignore1
-rw-r--r--cmake/elfinfo/CMakeLists.txt13
-rw-r--r--cmake/elfinfo/elfinfo.cpp260
-rw-r--r--cmake/intel-quark-d2000.toolchain.cmake79
5 files changed, 336 insertions, 18 deletions
diff --git a/apps/accel/CMakeLists.txt b/apps/accel/CMakeLists.txt
index 91f1497..35948ae 100644
--- a/apps/accel/CMakeLists.txt
+++ b/apps/accel/CMakeLists.txt
@@ -1,3 +1,4 @@
add_executable(accel main.c)
set_target_properties(accel PROPERTIES CHIP QUARK_D2000)
toolchain_target(accel)
+add_extra_commands(accel)
diff --git a/cmake/elfinfo/.gitignore b/cmake/elfinfo/.gitignore
new file mode 100644
index 0000000..485dee6
--- /dev/null
+++ b/cmake/elfinfo/.gitignore
@@ -0,0 +1 @@
+.idea
diff --git a/cmake/elfinfo/CMakeLists.txt b/cmake/elfinfo/CMakeLists.txt
new file mode 100644
index 0000000..82efcdf
--- /dev/null
+++ b/cmake/elfinfo/CMakeLists.txt
@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(elfinfo CXX ASM)
+
+add_executable(elfinfo elfinfo.cpp)
+target_compile_options(elfinfo PUBLIC "--std=c++14")
+target_link_libraries(elfinfo elf)
+
+INSTALL(TARGETS elfinfo
+ RUNTIME DESTINATION bin
+ LIBRARY DESTINATION lib
+ ARCHIVE DESTINATION lib
+)
diff --git a/cmake/elfinfo/elfinfo.cpp b/cmake/elfinfo/elfinfo.cpp
new file mode 100644
index 0000000..05a847a
--- /dev/null
+++ b/cmake/elfinfo/elfinfo.cpp
@@ -0,0 +1,260 @@
+#include <cctype>
+#include <cstdlib>
+#include <gelf.h>
+#include <err.h>
+#include <sysexits.h>
+#include <fcntl.h>
+#include <cstdio>
+#include <cstring>
+#include <vector>
+#include <algorithm>
+#include <getopt.h>
+#include <inttypes.h>
+#include <elf.h>
+
+using std::vector;
+
+enum class SectionType {
+ TEXT, DATA
+};
+
+const char *to_str(const SectionType &type) {
+ switch (type) {
+ case SectionType::TEXT:
+ return "text";
+ case SectionType::DATA:
+ return "data";
+ }
+}
+
+struct Section {
+ SectionType type;
+ const Elf64_Addr start;
+ const Elf64_Addr end;
+ const Elf64_Xword size;
+ Elf64_Addr used;
+
+ Section(SectionType type, Elf64_Addr start, Elf64_Xword size) : type(type), start(start), size(size),
+ end(start + size), used(0) {
+ }
+
+ bool contains(Elf64_Addr address, Elf64_Xword size) const {
+ return contains(address) && contains(address + size);
+ }
+
+ bool contains(Elf64_Addr address) const {
+ return start <= address && address < end;
+ }
+};
+
+vector<Section> sections;
+
+char *filename = NULL;
+
+char *program;
+
+__attribute__((noreturn))
+void usage(const char *reason = NULL) {
+ if (reason != NULL) {
+ fprintf(stderr, "%s\n", reason);
+ }
+ fprintf(stderr, "usage: %s -f file [-t start:size] [-d start:size]\n", program);
+ fprintf(stderr, " -t/-d/-b: add text/data section\n");
+ fprintf(stderr, "At least one section has to be specified\n");
+ exit(EX_USAGE);
+}
+
+void parse_start_size(char *input, Elf64_Addr &start, Elf64_Xword &size) {
+ char *str_size = strchr(input, ':');
+
+ if (str_size == NULL) {
+ usage("bad section specification, missing ':'");
+ }
+
+ *str_size = '\0';
+ str_size++;
+
+ if (sscanf(input, "%" SCNi64, &start) != 1) {
+ usage("bad section specification, could not parse start number");
+ }
+
+ size_t str_size_len = strlen(str_size);
+
+ if (str_size_len < 1) {
+ usage("bad section specification");
+ }
+
+ char suffix = str_size[str_size_len - 1];
+ int modifier;
+
+ if (!isdigit(suffix)) {
+ switch (suffix) {
+ case 'k':
+ case 'K':
+ modifier = 1024;
+ break;
+ case 'm':
+ case 'M':
+ modifier = 1024 * 1024;
+ break;
+ default:
+ usage("bad size modifier, only 'k' and 'M' are allowed");
+ }
+ } else {
+ modifier = 1;
+ }
+
+ if (sscanf(str_size, "%" SCNi64, &size) != 1) {
+ usage("bad section specification, could not parse size number");
+ }
+ size = size * modifier;
+}
+
+bool debug = false;
+
+void parse_args(int argc, char **argv) {
+ int c;
+
+ while ((c = getopt(argc, argv, "Df:t:d:")) != -1) {
+ switch (c) {
+ case 'D':
+ debug = true;
+ break;
+ case 't':
+ case 'd': {
+ Elf64_Addr start;
+ Elf64_Xword size;
+ parse_start_size(optarg, start, size);
+ SectionType type = c == 't' ? SectionType::TEXT : SectionType::DATA;
+ sections.push_back(Section(type, start, size));
+ break;
+ }
+ case 'f':
+ filename = optarg;
+ break;
+ case '?':
+ if (optopt == 'c')
+ errx(EX_USAGE, "Option -%c requires an argument.\n", optopt);
+ else
+ errx(EX_USAGE, "Unknown option `-%c'.\n", optopt);
+ default:
+ abort();
+ }
+ }
+
+ if (filename == NULL || sections.empty()) {
+ usage();
+ }
+}
+
+void to_iso(Elf64_Addr i, char *buf) {
+ const char *suffix;
+ if (i > 1024 * 1024) {
+ i /= 1024 * 1024;
+ suffix = "M";
+ } else if (i > 1024) {
+ i /= 1024;
+ suffix = "k";
+ } else {
+ suffix = "";
+ }
+ sprintf(buf, "%" PRIu64 "%s", i, suffix);
+}
+
+int main(int argc, char **argv) {
+ program = argv[0];
+ parse_args(argc, argv);
+
+ if (elf_version(EV_CURRENT) == EV_NONE)
+ errx(EX_SOFTWARE, "ELF library initialization failed: %s", elf_errmsg(-1));
+
+ int fd;
+ if ((fd = open(filename, O_RDONLY, 0)) < 0)
+ err(EX_NOINPUT, "open \"%s\" failed", argv[1]);
+
+ Elf *e;
+ if ((e = elf_begin(fd, ELF_C_READ, NULL)) == NULL)
+ errx(EX_SOFTWARE, "elf_begin() failed: %s.", elf_errmsg(-1));
+ if (elf_kind(e) != ELF_K_ELF)
+ errx(EX_DATAERR, "%s is not an ELF object.", argv[1]);
+
+ size_t shstrndx;
+ if (elf_getshdrstrndx(e, &shstrndx) != 0)
+ errx(EX_SOFTWARE, "elf_getshdrstrndx() failed: %s.", elf_errmsg(-1));
+
+ size_t program_header_count;
+ if (elf_getphdrnum(e, &program_header_count) != 0)
+ errx(EX_DATAERR, "elf_getphdrnum() failed: %s.", elf_errmsg(-1));
+
+ size_t text_size = 0, data_size = 0, bss_size = 0;
+ for (int i = 0; i < program_header_count; i++) {
+ GElf_Phdr phdr;
+
+ if (gelf_getphdr(e, i, &phdr) != &phdr)
+ errx(EX_SOFTWARE, "getphdr() failed: %s.", elf_errmsg(-1));
+
+ if (phdr.p_type == PT_LOAD) {
+ SectionType expectedType;
+ size_t *size;
+
+ if (phdr.p_flags == (PF_X | PF_W | PF_R) || phdr.p_flags == (PF_X | PF_R)) {
+ if (debug) {
+ printf("Adding PH #%d as text\n", i);
+ }
+
+ expectedType = SectionType::TEXT;
+ size = &text_size;
+ } else if (phdr.p_flags == (PF_R | PF_W)) {
+ expectedType = SectionType::DATA;
+ if (phdr.p_filesz > 0) {
+ if (debug) {
+ printf("Adding PH #%d as data\n", i);
+ }
+ size = &data_size;
+ }
+ else {
+ if (debug) {
+ printf("Adding PH #%d as bss\n", i);
+ }
+ size = &bss_size;
+ }
+ } else {
+ warnx("Unknown flag combination: 0x%02x", phdr.p_flags);
+ warnx("Unknown flag combination: 0x%02x", PF_X | PF_R);
+ continue;
+ }
+
+ auto s = std::find_if(sections.begin(), sections.end(), [&](Section &section) {
+ return section.type == expectedType && section.contains(phdr.p_vaddr, phdr.p_memsz);
+ });
+
+ if (s == sections.end()) {
+ fprintf(stderr,
+ "Could not find a section for elf header #%d of type %s, at address 0x%08" PRIx64 " with size %" PRId64 "\n",
+ i, to_str(expectedType), phdr.p_vaddr, phdr.p_memsz);
+ }
+ else {
+ (*s).used += phdr.p_memsz;
+
+ *size += phdr.p_memsz;
+ }
+ } else {
+ // ignored
+ };
+ }
+
+ printf("Size by sections\n");
+ printf("Type Start End Size Used\n");
+ std::for_each(sections.begin(), sections.end(), [&](Section &s) {
+ char size[100];
+ to_iso(s.size, size);
+ int used_pct = (int) (double(s.used) / double(s.size) * 100.0);
+ printf("%4s %08" PRIx64 " %08" PRIx64 " %5s %6" PRId64 " %3d%%\n", to_str(s.type), s.start, s.end, size, s.used,
+ used_pct);
+ });
+
+ printf("\n");
+ printf("Size by type\n");
+ printf("text=%zu, data=%zu, bss=%zu\n", text_size, data_size, bss_size);
+ return EXIT_SUCCESS;
+}
diff --git a/cmake/intel-quark-d2000.toolchain.cmake b/cmake/intel-quark-d2000.toolchain.cmake
index 3e15792..16f12f5 100644
--- a/cmake/intel-quark-d2000.toolchain.cmake
+++ b/cmake/intel-quark-d2000.toolchain.cmake
@@ -1,6 +1,6 @@
if (${INTEL_QUARK_TOOLCHAIN_LOADED})
- return()
-endif()
+ return()
+endif ()
set(INTEL_QUARK_TOOLCHAIN_LOADED TRUE)
include(CMakeForceCompiler)
@@ -10,12 +10,14 @@ set(TRIPLE "i586-intel-elfiamcu")
if (NOT IS_DIRECTORY "${ISSM_DIR}")
message(FATAL_ERROR "ISSM_DIR has to be set to a directory:" ${ISSM_DIR})
set(ISSM_DIR CACHE PATH "The path to Intes ISSM")
-endif()
+endif ()
if (NOT INTEL_QUARK_CHIP)
set(INTEL_QUARK_CHIP CACHE STRING "The Intel Quark chip to build for")
message(FATAL_ERROR "INTEL_QUARK_CHIP has to be set before including the toolchain file")
-endif()
+endif ()
+
+get_filename_component(toolchain_dir "${CMAKE_TOOLCHAIN_FILE}" DIRECTORY)
set(CMAKE_SYSTEM_NAME Generic)
set(CMAKE_SYSTEM_PROCESSOR intel)
@@ -26,22 +28,22 @@ set(BASE_FLAGS "-std=c90 -Wall -Wextra -Werror -Wno-unused-parameter")
set(INCLUDES "")
-if(IS_DIRECTORY "${QMSI_DIR}")
+if (IS_DIRECTORY "${QMSI_DIR}")
message("Using QMSI_DIR: ${QMSI_DIR}")
-else()
+else ()
message("Detecting QMSI_DIR..")
find_path(QMSI_DIR qm_common.h
- HINTS "${ISSM_DIR}/firmware/bsp/1.0/include"
- NO_DEFAULT_PATH)
+ HINTS "${ISSM_DIR}/firmware/bsp/1.0/include"
+ NO_DEFAULT_PATH)
- if(IS_DIRECTORY "${QMSI_DIR}")
+ if (IS_DIRECTORY "${QMSI_DIR}")
message("Found QMSI_DIR: ${QMSI_DIR}")
- else()
+ else ()
message(FATAL_ERROR "Could not find QMSI directory")
- endif()
+ endif ()
-endif()
+endif ()
# TODO: these directories should be validated
list(APPEND includes "${ISSM_DIR}/firmware/bsp/1.0/include")
@@ -52,9 +54,12 @@ list(APPEND includes "${ISSM_DIR}/firmware/bsp/1.0/drivers/bmc150")
if (INTEL_QUARK_CHIP STREQUAL D2000)
list(APPEND includes "${ISSM_DIR}/firmware/bsp/1.0/soc/quark_d2000/include")
set(ld_file "${ISSM_DIR}/firmware/bsp/1.0/soc/quark_d2000/quark_d2000.ld")
+
+ list(APPEND mcu_text_areas 0x00180000:20k)
+ list(APPEND mcu_data_areas 0x00280000:5k)
elseif (INTEL_QUARK_CHIP STREQUAL SE)
list(APPEND includes "${ISSM_DIR}/firmware/bsp/1.0/soc/quark_se/include")
-endif()
+endif ()
# QMSI Library
file(GLOB_RECURSE qmsi_sources ${ISSM_DIR}/firmware/bsp/1.0/drivers/*.c)
@@ -129,7 +134,7 @@ set(CMAKE_C_FLAGS "${BASE_FLAGS} ${TARGET_FLAGS} " CACHE STRING "c flags")
set(CMAKE_CXX_FLAGS "${BASE_FLAGS} ${TARGET_FLAGS} -fno-exceptions -fno-rtti -felide-constructors -std=c++14" CACHE STRING "c++ flags")
# ${CMAKE_C_FLAGS} is prepended to this string
-set(LD_FILE )
+set(LD_FILE)
set(linker_flags "")
set(linker_flags "${linker_flags} -nostdlib")
set(linker_flags "${linker_flags} -Xlinker -A")
@@ -143,9 +148,9 @@ set(CMAKE_EXE_LINKER_FLAGS "${linker_flags}" CACHE STRING "linker flags" FORCE)
set(GCC "${ISSM_DIR}/tools/compiler/bin/${TRIPLE}-gcc")
-if(NOT EXISTS "${GCC}")
+if (NOT EXISTS "${GCC}")
message(FATAL_ERROR "Could not find ${TRIPLE}-gcc. Is $ISSM_DIR set correctly?")
-endif()
+endif ()
# No C++ support for D2000
# set(GXX "${ISSM_DIR}/tools/compiler/bin/${TRIPLE}-g++")
@@ -156,13 +161,14 @@ endif()
cmake_force_c_compiler("${GCC}" GNU)
-# search for programs in the build host directories
+# search for programs in the build elfinfo directories
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
# for libraries and headers in the target directories
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
function(toolchain_target TARGET)
+ add_dependencies("${TARGET}" elfinfo)
target_link_libraries("${TARGET}" intel_sys)
target_link_libraries("${TARGET}" qmsi)
target_link_libraries("${TARGET}" ipp)
@@ -170,7 +176,44 @@ function(toolchain_target TARGET)
target_link_libraries("${TARGET}" softfp)
target_link_libraries("${TARGET}" c)
target_link_libraries("${TARGET}" g)
-# target_link_libraries("${TARGET}" gcc)
+ # target_link_libraries("${TARGET}" gcc)
target_compile_definitions("${TARGET}" PUBLIC -D__IPP_ENABLED__)
target_link_libraries("${TARGET}" "-Xlinker" "-T${ld_file}")
endfunction()
+
+# elfinfo tools
+
+get_filename_component(ELFINFO_SOURCE_DIR "${toolchain_dir}/elfinfo" ABSOLUTE)
+get_filename_component(ELFINFO_INSTALL_DIR "${CMAKE_BINARY_DIR}/elfinfo" ABSOLUTE)
+
+include(ExternalProject)
+ExternalProject_Add(elfinfo
+ SOURCE_DIR "${ELFINFO_SOURCE_DIR}"
+ DOWNLOAD_COMMAND ""
+ UPDATE_COMMAND ""
+ CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${ELFINFO_INSTALL_DIR})
+
+function(add_extra_commands target_name)
+ # add_custom_command(TARGET ${target_name} POST_BUILD
+ # COMMAND mkdir -p ${target_name}-info && arm-none-eabi-objdump -D ${target_name} > ${target_name}-info/${target_name}.asm)
+ # add_custom_command(TARGET ${target_name} POST_BUILD
+ # COMMAND mkdir -p ${target_name}-info && arm-none-eabi-nm -C ${target_name} > ${target_name}-info/${target_name}.nm)
+ # add_custom_command(TARGET ${target_name} POST_BUILD
+ # COMMAND mkdir -p ${target_name}-info && arm-none-eabi-size ${target_name} > ${target_name}-info/${target_name}.size)
+ # add_custom_command(TARGET ${target_name} POST_BUILD
+ # COMMAND mkdir -p ${target_name}-info && arm-none-eabi-readelf -a ${target_name} > ${target_name}-info/${target_name}.readelf)
+ # add_custom_command(TARGET ${target_name} POST_BUILD
+ # COMMAND mkdir -p ${target_name}-info && arm-none-eabi-objcopy -O ihex ${target_name} ${target_name}-info/${target_name}.hex)
+ # add_custom_command(TARGET ${target_name} POST_BUILD
+ # COMMAND mkdir -p ${target_name}-info && arm-none-eabi-objcopy -O binary ${target_name} ${target_name}-info/${target_name}.bin)
+
+ foreach(area ${mcu_text_areas})
+ set(text_segments "${text_segments}" "-t" "${area}")
+ endforeach()
+ foreach(area ${mcu_data_areas})
+ set(data_segments "${data_segments}" "-d" "${area}")
+ endforeach()
+
+ add_custom_command(TARGET ${target_name} DEPENDS elfinfo POST_BUILD
+ COMMAND "${ELFINFO_INSTALL_DIR}/bin/elfinfo" -f ${target_name} ${text_segments} ${data_segments})
+endfunction()