1266 lines
31 KiB
C
Executable file
1266 lines
31 KiB
C
Executable file
// SPDX-License-Identifier: GPL-2.0
|
|
/*
|
|
* Samsung Exynos SoC series dsp driver
|
|
*
|
|
* Copyright (c) 2019 Samsung Electronics Co., Ltd.
|
|
* http://www.samsung.com/
|
|
*/
|
|
|
|
#include "dl/dsp-dl-linker.h"
|
|
#include "dl/dsp-lib-manager.h"
|
|
#include "dl/dsp-pm-manager.h"
|
|
#include "dl/dsp-elf-loader.h"
|
|
#include "dl/dsp-common.h"
|
|
#include "dl/dsp-string-tree.h"
|
|
#include "dl/dsp-llstack.h"
|
|
|
|
static struct dsp_string_tree_node *gp_str;
|
|
static struct dsp_reloc_rule_list *rules;
|
|
|
|
static const char *const reloc_gp_str[RELOC_GP_NUM] = {
|
|
"_segment_start_thread_local_DMb",
|
|
"_segment_end_thread_local_DMb",
|
|
"_segment_start_thread_local_TCMb",
|
|
"_segment_end_thread_local_TCMb",
|
|
"_dm_gp",
|
|
"_tcm_gp",
|
|
"_sfr_gp",
|
|
};
|
|
|
|
struct dsp_link_info *dsp_link_info_create(struct dsp_elf32 *elf)
|
|
{
|
|
struct dsp_link_info *l_info;
|
|
int idx;
|
|
|
|
l_info = (struct dsp_link_info *)dsp_dl_malloc(
|
|
sizeof(*l_info), "lib link_info");
|
|
l_info->sec = (unsigned long *)dsp_dl_malloc(
|
|
sizeof(*l_info->sec) *
|
|
elf->hdr->e_shnum,
|
|
"info sec");
|
|
|
|
for (idx = 0; idx < elf->hdr->e_shnum; idx++)
|
|
l_info->sec[idx] = -1;
|
|
|
|
l_info->elf = elf;
|
|
dsp_list_head_init(&l_info->reloc_sym);
|
|
return l_info;
|
|
}
|
|
|
|
void dsp_link_info_free(struct dsp_link_info *info)
|
|
{
|
|
dsp_dl_free(info->sec);
|
|
dsp_list_free(&info->reloc_sym,
|
|
struct dsp_reloc_sym, node);
|
|
}
|
|
|
|
static int dsp_reloc_sym_str_compare(
|
|
struct dsp_list_node *a,
|
|
struct dsp_list_node *b)
|
|
{
|
|
struct dsp_reloc_sym *a_sym = container_of(a,
|
|
struct dsp_reloc_sym, node);
|
|
struct dsp_reloc_sym *b_sym = container_of(b,
|
|
struct dsp_reloc_sym, node);
|
|
|
|
return strcmp(a_sym->sym_str, b_sym->sym_str);
|
|
}
|
|
|
|
static int dsp_reloc_sym_addr_compare(
|
|
struct dsp_list_node *a,
|
|
struct dsp_list_node *b)
|
|
{
|
|
struct dsp_reloc_sym *a_sym = container_of(a,
|
|
struct dsp_reloc_sym, node);
|
|
struct dsp_reloc_sym *b_sym = container_of(b,
|
|
struct dsp_reloc_sym, node);
|
|
|
|
if (a_sym->align < b_sym->align)
|
|
return 1;
|
|
else if (a_sym->align > b_sym->align)
|
|
return -1;
|
|
else if (a_sym->value < b_sym->value)
|
|
return 1;
|
|
else if (a_sym->value > b_sym->value)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
void dsp_link_info_print(struct dsp_link_info *info)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
struct dsp_list_head remove;
|
|
struct dsp_list_node *node;
|
|
int idx;
|
|
|
|
DL_DEBUG("text start address : 0x%lx\n", info->text);
|
|
DL_DEBUG("text size : %zu(0x%x)\n", info->text_size,
|
|
(unsigned int)info->text_size);
|
|
DL_DEBUG("DMb start address : 0x%lx\n", info->DMb);
|
|
DL_DEBUG("DMb size : %zu(0x%x)\n", info->DMb_size,
|
|
(unsigned int)info->DMb_size);
|
|
DL_DEBUG("DMb_local start address : 0x%lx\n", info->DMb_local);
|
|
DL_DEBUG("DMb_local size : %zu(0x%x)\n", info->DMb_local_size,
|
|
(unsigned int)info->DMb_local_size);
|
|
DL_DEBUG("DRAMb start address : 0x%lx\n", info->DRAMb);
|
|
DL_DEBUG("DRAMb size : %zu(0x%x)\n", info->DRAMb_size,
|
|
(unsigned int)info->DRAMb_size);
|
|
DL_DEBUG("TCMb start address : 0x%lx\n", info->TCMb);
|
|
DL_DEBUG("TCMb size : %zu(0x%x)\n", info->TCMb_size,
|
|
(unsigned int)info->TCMb_size);
|
|
DL_DEBUG("TCMb_local start address : 0x%lx\n", info->TCMb_local);
|
|
DL_DEBUG("TCMb_local size : %zu(0x%x)\n", info->TCMb_local_size,
|
|
(unsigned int)info->TCMb_local_size);
|
|
DL_DEBUG("SFRw start address : 0x%lx\n", info->SFRw);
|
|
DL_DEBUG("SFRw size : %zu(0x%x)\n", info->SFRw_size,
|
|
(unsigned int)info->SFRw_size);
|
|
|
|
DL_DEBUG("Section address\n");
|
|
|
|
for (idx = 0; idx < elf->hdr->e_shnum; idx++) {
|
|
struct dsp_elf32_shdr *shdr = &elf->shdr[idx];
|
|
|
|
DL_BUF_STR("[%d] ", idx);
|
|
DL_BUF_STR("%s ", elf->shstrtab + shdr->sh_name);
|
|
DL_BUF_STR("0x%lx\n", info->sec[idx]);
|
|
DL_PRINT_BUF(DEBUG);
|
|
}
|
|
|
|
dsp_list_head_init(&remove);
|
|
dsp_list_unique(&info->reloc_sym, &remove, dsp_reloc_sym_str_compare);
|
|
dsp_list_free(&remove, struct dsp_reloc_sym, node);
|
|
|
|
dsp_list_sort(&info->reloc_sym, dsp_reloc_sym_addr_compare);
|
|
dsp_list_for_each(node, &info->reloc_sym) {
|
|
struct dsp_reloc_sym *sym_info = container_of(node,
|
|
struct dsp_reloc_sym, node);
|
|
|
|
DL_INFO("Symbol(%s) value(0x%x) addr(0x%x)\n",
|
|
sym_info->sym_str, sym_info->value,
|
|
sym_info->value * sym_info->align);
|
|
}
|
|
}
|
|
|
|
static unsigned long __addr_align(unsigned long addr)
|
|
{
|
|
return (addr + 0x3) & ~0x3;
|
|
}
|
|
|
|
static unsigned long __dsp_link_info_sec_alloc(struct dsp_link_info *info,
|
|
unsigned long start, struct dsp_list_head *head)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
struct dsp_list_node *node;
|
|
|
|
dsp_list_for_each(node, head) {
|
|
struct dsp_elf32_idx_node *idx_node =
|
|
container_of(node, struct dsp_elf32_idx_node, node);
|
|
int idx = idx_node->idx;
|
|
struct dsp_elf32_shdr *shdr = &elf->shdr[idx];
|
|
|
|
DL_DEBUG("%s\n", elf->shstrtab + shdr->sh_name);
|
|
|
|
start = __addr_align(start);
|
|
info->sec[idx] = start;
|
|
|
|
DL_DEBUG("[%d]addr : 0x%lx(0x%x)\n", idx, info->sec[idx],
|
|
elf->shdr[idx].sh_size);
|
|
start += shdr->sh_size;
|
|
}
|
|
|
|
start = __addr_align(start);
|
|
return start;
|
|
}
|
|
|
|
void dsp_link_info_set_text(struct dsp_link_info *info, unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
|
|
info->text = addr;
|
|
|
|
DL_DEBUG("set text\n");
|
|
info->text_size = __dsp_link_info_sec_alloc(info, addr,
|
|
&elf->text.text) - info->text;
|
|
}
|
|
|
|
void dsp_link_info_set_DMb(struct dsp_link_info *info, unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
unsigned long addr_acc;
|
|
|
|
info->DMb = addr_acc = addr;
|
|
|
|
DL_DEBUG("set DMb\n");
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->DMb.robss);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->DMb.rodata);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->DMb.bss);
|
|
info->DMb_size = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DMb.data) - info->DMb;
|
|
}
|
|
|
|
void dsp_link_info_set_DMb_local(struct dsp_link_info *info, unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
unsigned long addr_acc;
|
|
|
|
info->DMb_local = addr_acc = addr;
|
|
|
|
DL_DEBUG("set DMb_local\n");
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DMb_local.robss);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DMb_local.rodata);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DMb_local.bss);
|
|
info->DMb_local_size = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DMb_local.data) - info->DMb_local;
|
|
}
|
|
|
|
void dsp_link_info_set_DRAMb(struct dsp_link_info *info, unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
unsigned long addr_acc;
|
|
|
|
info->DRAMb = addr_acc = addr;
|
|
|
|
DL_DEBUG("set DRAMb\n");
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->DRAMb.robss);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DRAMb.rodata);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->DRAMb.bss);
|
|
info->DRAMb_size = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->DRAMb.data) - info->DRAMb;
|
|
}
|
|
|
|
void dsp_link_info_set_TCMb(struct dsp_link_info *info, unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
unsigned long addr_acc;
|
|
|
|
info->TCMb = addr_acc = addr;
|
|
|
|
DL_DEBUG("set TCMb\n");
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->TCMb.robss);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->TCMb.rodata);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->TCMb.bss);
|
|
info->TCMb_size = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->TCMb.data) - info->TCMb;
|
|
}
|
|
|
|
void dsp_link_info_set_TCMb_local(struct dsp_link_info *info,
|
|
unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
unsigned long addr_acc;
|
|
|
|
info->TCMb_local = addr_acc = addr;
|
|
|
|
DL_DEBUG("set TCMb_local\n");
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->TCMb_local.robss);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->TCMb_local.rodata);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->TCMb_local.bss);
|
|
info->TCMb_local_size = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->TCMb_local.data) - info->TCMb_local;
|
|
}
|
|
|
|
void dsp_link_info_set_SFRw(struct dsp_link_info *info, unsigned long addr)
|
|
{
|
|
struct dsp_elf32 *elf = info->elf;
|
|
unsigned long addr_acc;
|
|
|
|
info->SFRw = addr_acc = addr;
|
|
|
|
DL_DEBUG("set SFRw\n");
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->SFRw.robss);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->SFRw.rodata);
|
|
addr_acc = __dsp_link_info_sec_alloc(info, addr_acc, &elf->SFRw.bss);
|
|
info->SFRw_size = __dsp_link_info_sec_alloc(info, addr_acc,
|
|
&elf->SFRw.data) - info->SFRw;
|
|
}
|
|
|
|
unsigned int dsp_link_info_get_kernel_addr(struct dsp_link_info *info,
|
|
char *kernel_name)
|
|
{
|
|
int ret;
|
|
struct dsp_elf32 *elf = info->elf;
|
|
struct dsp_elf32_sym *sym;
|
|
struct dsp_reloc_sym *reloc_sym;
|
|
unsigned int sym_align;
|
|
unsigned long sec_addr;
|
|
unsigned int kernel_addr;
|
|
|
|
if (kernel_name == NULL)
|
|
return 0;
|
|
|
|
ret = dsp_hash_get(&elf->symhash, kernel_name, (void **)&sym);
|
|
if (ret == -1) {
|
|
DL_ERROR("No kernel %s in lib\n", kernel_name);
|
|
return (unsigned int) -1;
|
|
}
|
|
|
|
sym_align = elf->shdr[sym->st_shndx].sh_addralign;
|
|
|
|
sec_addr = info->sec[sym->st_shndx];
|
|
kernel_addr = (unsigned int)(sec_addr /
|
|
sym_align + sym->st_value);
|
|
|
|
DL_DEBUG("sh ndx: %u, sec addr: %lu, sym value: %u, align value: %u\n",
|
|
sym->st_shndx, sec_addr, sym->st_value, sym_align);
|
|
DL_INFO("kernel name(%s) value(0x%x) addr(0x%x)\n",
|
|
kernel_name, kernel_addr, kernel_addr * sym_align);
|
|
|
|
reloc_sym = (struct dsp_reloc_sym *)dsp_dl_malloc(
|
|
sizeof(struct dsp_reloc_sym),
|
|
"Information of symbol of kernel");
|
|
reloc_sym->sym_str = kernel_name;
|
|
reloc_sym->value = kernel_addr;
|
|
reloc_sym->align = sym_align;
|
|
dsp_list_node_init(&reloc_sym->node);
|
|
dsp_list_node_push_back(&info->reloc_sym, &reloc_sym->node);
|
|
|
|
return kernel_addr;
|
|
}
|
|
|
|
void dsp_linker_alloc_bss(struct dsp_elf32 *elf)
|
|
{
|
|
unsigned int *alloc_tmp =
|
|
(unsigned int *)dsp_dl_malloc(sizeof(*alloc_tmp) *
|
|
elf->hdr->e_shnum, "alloc bss alloc_tmp");
|
|
struct dsp_list_node *node;
|
|
|
|
memset(alloc_tmp, 0, sizeof(*alloc_tmp) * elf->hdr->e_shnum);
|
|
|
|
dsp_list_for_each(node, &elf->bss_sym) {
|
|
struct dsp_elf32_idx_node *idx_node =
|
|
container_of(node, struct dsp_elf32_idx_node, node);
|
|
struct dsp_elf32_sym *sym = &elf->symtab[idx_node->idx];
|
|
int ndx = sym->st_shndx;
|
|
|
|
alloc_tmp[ndx] = __addr_align(alloc_tmp[ndx]);
|
|
sym->st_value = alloc_tmp[ndx];
|
|
DL_DEBUG("%s(%d) %s : %d\n", elf->shstrtab +
|
|
elf->shdr[ndx].sh_name, ndx,
|
|
elf->strtab + sym->st_name, sym->st_value);
|
|
|
|
alloc_tmp[ndx] += sym->st_size;
|
|
}
|
|
dsp_dl_free(alloc_tmp);
|
|
}
|
|
|
|
static long long __get_linker_value(enum dsp_linker_value_type link_v,
|
|
struct dsp_link_info *sym_info, struct dsp_link_info *rela_info,
|
|
struct dsp_elf32_shdr *rela_shdr, struct dsp_elf32_sym *sym,
|
|
struct dsp_elf32_rela *rela)
|
|
{
|
|
long long ret;
|
|
struct dsp_elf32 *sym_elf = sym_info->elf;
|
|
struct dsp_elf32 *rela_elf = rela_info->elf;
|
|
|
|
switch (link_v) {
|
|
case ADDEND:
|
|
ret = (long long)rela->r_addend;
|
|
DL_DEBUG("addend : %llu\n", ret);
|
|
return ret;
|
|
case BLOCK_ADDR_AR:
|
|
ret = (long long)rela_info->sec[rela_shdr->sh_info];
|
|
DL_DEBUG("block_addr_AR : %llu\n", ret);
|
|
return ret;
|
|
case BLOCK_ADDR_BR:
|
|
ret = (long long)rela_elf->shdr[rela_shdr->sh_info].sh_offset;
|
|
DL_DEBUG("block_addr_BR : %llu\n", ret);
|
|
return ret;
|
|
case ITEM_ADDR_AR:
|
|
ret = (long long)(rela_info->sec[rela_shdr->sh_info] +
|
|
rela->r_offset);
|
|
DL_DEBUG("item_addr_AR : %llu\n", ret);
|
|
return ret;
|
|
case ITEM_ADDR_BR:
|
|
ret = (long long)rela->r_offset;
|
|
DL_DEBUG("item_addr_BR: %llu\n", ret);
|
|
return ret;
|
|
case ITEM_VALUE:
|
|
DL_DEBUG("item_value : %u\n", 0);
|
|
return 0;
|
|
case STORED_VALUE:
|
|
DL_DEBUG("stored_value : %u\n", 0);
|
|
return 0;
|
|
case SYMBOL_ADDR_AR:
|
|
ret = (long long)sym_info->sec[sym->st_shndx] /
|
|
sym_elf->shdr[sym->st_shndx].sh_addralign +
|
|
sym->st_value;
|
|
DL_DEBUG("symbol_addr_AR : %llu\n", ret);
|
|
return ret;
|
|
case SYMBOL_ADDR_BR:
|
|
ret = (long long)sym->st_value *
|
|
sym_elf->shdr[sym->st_shndx].sh_addralign;
|
|
DL_DEBUG("symbol_addr_BR : %llu\n", ret);
|
|
return ret;
|
|
case SYMBOL_BLOCK_ADDR_AR:
|
|
ret = (long long)sym_info->sec[sym->st_shndx];
|
|
DL_DEBUG("symbol_block_addr_AR: %llu\n", ret);
|
|
return ret;
|
|
case SYMBOL_BLOCK_ADDR_BR:
|
|
ret = (long long)sym_elf->shdr[sym->st_shndx].sh_offset;
|
|
DL_DEBUG("symbol_block_addr_BR: %llu\n", ret);
|
|
return ret;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int __process_op(struct dsp_llstack *st, char op)
|
|
{
|
|
int ret;
|
|
long long op1, op2;
|
|
|
|
switch (op) {
|
|
case '|':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 | op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu | %llu: %llu\n", op1, op2, op1 | op2);
|
|
break;
|
|
|
|
case '&':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 & op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu & %llu: %llu\n", op1, op2, op1 & op2);
|
|
break;
|
|
|
|
case '>':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 >> op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu > %llu: %llu\n", op1, op2, op1 >> op2);
|
|
break;
|
|
|
|
case '<':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 << op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu < %llu: %llu\n", op1, op2, op1 << op2);
|
|
break;
|
|
|
|
case '-':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 - op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu - %llu: %llu\n", op1, op2, op1 - op2);
|
|
break;
|
|
|
|
case '+':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 + op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu + %llu: %llu\n", op1, op2, op1 + op2);
|
|
break;
|
|
|
|
case '%':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 % op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu %% %llu: %llu\n", op1, op2, op1 % op2);
|
|
break;
|
|
|
|
case '/':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 / op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu / %llu: %llu\n", op1, op2, op1 / op2);
|
|
break;
|
|
|
|
case '*':
|
|
ret = dsp_llstack_pop(st, &op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, op1 * op2);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("%llu * %llu: %llu\n", op1, op2, op1 * op2);
|
|
break;
|
|
|
|
case '~':
|
|
ret = dsp_llstack_pop(st, &op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
ret = dsp_llstack_push(st, -1 * op1);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("~ %llu: %llu\n", op1, -1 * op1);
|
|
break;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static unsigned int __cast_to_type(long long value, struct dsp_type *type)
|
|
{
|
|
if (type->sign == UNSIGNED || value >= 0) {
|
|
return (unsigned int)(value &
|
|
((1LL << type->bit_sz) - 1));
|
|
} else {
|
|
return (unsigned int)(value |
|
|
~((1LL << type->bit_sz) - 1));
|
|
}
|
|
}
|
|
|
|
static unsigned int __rule_get_value(struct dsp_reloc_rule *rule,
|
|
struct dsp_link_info *sym_info, struct dsp_link_info *rela_info,
|
|
struct dsp_elf32_shdr *rela_shdr, struct dsp_elf32_sym *sym,
|
|
struct dsp_elf32_rela *rela)
|
|
{
|
|
int ret;
|
|
struct dsp_llstack st;
|
|
long long value;
|
|
struct dsp_list_node *node;
|
|
|
|
dsp_llstack_init(&st);
|
|
|
|
dsp_list_for_each(node, &rule->exp) {
|
|
struct dsp_exp_element *elem =
|
|
container_of(node, struct dsp_exp_element, list_node);
|
|
|
|
if (elem->type == EXP_INTEGER) {
|
|
DL_DEBUG("integer : %d\n", elem->integer);
|
|
ret = dsp_llstack_push(&st, (long long)elem->integer);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
} else if (elem->type == EXP_LINKER_VALUE) {
|
|
value = __get_linker_value(elem->linker_value,
|
|
sym_info, rela_info, rela_shdr,
|
|
sym, rela);
|
|
|
|
ret = dsp_llstack_push(&st, value);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
} else if (elem->type == EXP_OP) {
|
|
ret = __process_op(&st, elem->op);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
ret = dsp_llstack_pop(&st, &value);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("value : %lld(%u)\n", value,
|
|
__cast_to_type(value, &rule->type));
|
|
|
|
return __cast_to_type(value, &rule->type);
|
|
}
|
|
|
|
static int __calc_gp_link_value(struct dsp_lib *lib, unsigned int *value,
|
|
const char *sym_str)
|
|
{
|
|
struct dsp_dl_out *lib_dl = lib->dl_out;
|
|
struct dsp_gpt *gpt = lib->gpt;
|
|
int ret_value = dsp_string_tree_get(gp_str, sym_str);
|
|
|
|
DL_DEBUG("ret_value : %d\n", ret_value);
|
|
switch (ret_value) {
|
|
case DM_THREAD_LOCAL_START:
|
|
*value = lib_dl->DM_sh.size;
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
case DM_THREAD_LOCAL_END:
|
|
*value = lib_dl->DM_sh.size + lib_dl->DM_local.size;
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
case TCM_THREAD_LOCAL_START:
|
|
*value = lib_dl->TCM_sh.size;
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
case TCM_THREAD_LOCAL_END:
|
|
*value = lib_dl->TCM_sh.size + lib_dl->TCM_local.size;
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
case DM_GP:
|
|
*value = gpt->addr;
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
case TCM_GP:
|
|
*value = gpt->addr + sizeof(unsigned int);
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
case SH_MEM_GP:
|
|
*value = gpt->addr + sizeof(unsigned int) * 2;
|
|
DL_DEBUG("value : %d\n", *value);
|
|
return 0;
|
|
default:
|
|
return -1;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int __find_real_sym(
|
|
struct dsp_elf32_sym **real_sym, struct dsp_lib **real_lib,
|
|
struct dsp_link_info **sym_info, const char *sym_str,
|
|
struct dsp_link_info *rela_info,
|
|
struct dsp_lib **libs, int libs_size,
|
|
struct dsp_lib **common_libs, int common_size)
|
|
{
|
|
int ret, idx;
|
|
|
|
for (idx = 0; idx < libs_size; idx++) {
|
|
struct dsp_link_info *cur_info = libs[idx]->link_info;
|
|
|
|
if (cur_info == rela_info)
|
|
continue;
|
|
|
|
DL_DEBUG("Find %s in %s\n", sym_str, libs[idx]->name);
|
|
ret = dsp_hash_get(&cur_info->elf->symhash, sym_str,
|
|
(void **)real_sym);
|
|
if (ret != -1) {
|
|
*sym_info = cur_info;
|
|
*real_lib = libs[idx];
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
for (idx = 0; idx < common_size; idx++) {
|
|
struct dsp_link_info *cur_info = common_libs[idx]->link_info;
|
|
|
|
if (cur_info == rela_info)
|
|
continue;
|
|
|
|
DL_DEBUG("Find %s in common lib %s\n",
|
|
sym_str, common_libs[idx]->name);
|
|
ret = dsp_hash_get(&cur_info->elf->symhash, sym_str,
|
|
(void **)real_sym);
|
|
if (ret != -1) {
|
|
*sym_info = cur_info;
|
|
*real_lib = common_libs[idx];
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
static int __calc_link_value(struct dsp_lib *lib,
|
|
unsigned int *value, const char *sym_str,
|
|
struct dsp_elf32_rela *rela, struct dsp_elf32_shdr *rela_shdr,
|
|
struct dsp_lib **libs, int libs_size,
|
|
struct dsp_lib **common_libs, int common_size)
|
|
{
|
|
int ret;
|
|
struct dsp_link_info *rela_info;
|
|
unsigned int ruleidx;
|
|
struct dsp_reloc_rule *rule;
|
|
struct dsp_link_info *sym_info = NULL;
|
|
struct dsp_elf32_sym *real_sym = NULL;
|
|
struct dsp_lib *real_lib = NULL;
|
|
|
|
unsigned int sym_align = 1;
|
|
struct dsp_reloc_sym *reloc_sym;
|
|
|
|
ret = __calc_gp_link_value(lib, value, sym_str);
|
|
if (ret == -1) {
|
|
rela_info = lib->link_info;
|
|
ruleidx = dsp_elf32_rela_get_rule_idx(rela);
|
|
if (ruleidx >= rules->cnt) {
|
|
DL_ERROR("invalid ruleidx(%u/%d)\n",
|
|
ruleidx, rules->cnt);
|
|
return -1;
|
|
}
|
|
rule = rules->list[ruleidx];
|
|
|
|
ret = dsp_hash_get(&rela_info->elf->symhash, sym_str,
|
|
(void **)&real_sym);
|
|
if (ret == -1) {
|
|
DL_DEBUG("Sym(%s) is external variable\n", sym_str);
|
|
|
|
ret = __find_real_sym(&real_sym, &real_lib,
|
|
&sym_info, sym_str, rela_info,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("Symbol(%s) is not found\n",
|
|
sym_str);
|
|
return -1;
|
|
}
|
|
} else {
|
|
DL_DEBUG("Sym(%s) is internal variable\n", sym_str);
|
|
real_lib = lib;
|
|
sym_info = rela_info;
|
|
}
|
|
|
|
*value = __rule_get_value(rule, sym_info, rela_info, rela_shdr,
|
|
real_sym, rela);
|
|
}
|
|
|
|
if (real_sym) {
|
|
struct dsp_elf32 *real_elf = real_lib->elf;
|
|
int real_shdr_idx = real_sym->st_shndx;
|
|
|
|
sym_align = real_elf->shdr[real_shdr_idx].sh_addralign;
|
|
}
|
|
|
|
DL_DEBUG("value : %u\n", *value);
|
|
|
|
if (strncmp(sym_str, "LE_F", 4) != 0) {
|
|
reloc_sym = (struct dsp_reloc_sym *)dsp_dl_malloc(
|
|
sizeof(struct dsp_reloc_sym),
|
|
"Information of symbol relocated");
|
|
reloc_sym->sym_str = sym_str;
|
|
reloc_sym->value = *value;
|
|
reloc_sym->align = sym_align;
|
|
dsp_list_node_init(&reloc_sym->node);
|
|
dsp_list_node_push_back(&lib->link_info->reloc_sym,
|
|
&reloc_sym->node);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void __relocate(struct dsp_reloc_info *r_info, char *data, char item_rev)
|
|
{
|
|
int v_bits = r_info->high - r_info->low + 1;
|
|
int t_bits;
|
|
int bits;
|
|
|
|
v_bits = (v_bits > 0) ? v_bits : 0;
|
|
t_bits = v_bits;
|
|
|
|
if (r_info->l_ext != BIT_NONE)
|
|
t_bits++;
|
|
|
|
if (r_info->h_ext != BIT_NONE)
|
|
t_bits++;
|
|
|
|
bits = t_bits + r_info->sh;
|
|
|
|
if (bits > 8) {
|
|
struct dsp_reloc_info low_info;
|
|
|
|
low_info.item_cnt = r_info->item_cnt;
|
|
|
|
if (r_info->sh >= 8) {
|
|
low_info.idx = (unsigned int) -1;
|
|
r_info->sh -= 8;
|
|
r_info->idx -= 1;
|
|
} else {
|
|
unsigned int l_bits = 8 - r_info->sh;
|
|
|
|
low_info.idx = r_info->idx;
|
|
low_info.sh = r_info->sh;
|
|
low_info.low = r_info->low;
|
|
|
|
if (r_info->l_ext != BIT_NONE)
|
|
low_info.high = r_info->low + (l_bits - 1) - 1;
|
|
else
|
|
low_info.high = r_info->low + l_bits - 1;
|
|
|
|
low_info.h_ext = BIT_NONE;
|
|
low_info.l_ext = r_info->l_ext;
|
|
low_info.value = r_info->value;
|
|
|
|
r_info->sh = 0;
|
|
r_info->idx -= 1;
|
|
r_info->l_ext = BIT_NONE;
|
|
r_info->low = low_info.high + 1;
|
|
}
|
|
|
|
__relocate(r_info, data, item_rev);
|
|
__relocate(&low_info, data, item_rev);
|
|
} else {
|
|
unsigned int value = 0;
|
|
unsigned int data_idx;
|
|
int mask;
|
|
|
|
if (r_info->idx == (unsigned int) -1)
|
|
return;
|
|
|
|
if (r_info->h_ext == BIT_ONE)
|
|
value = 1;
|
|
else if (r_info->h_ext == BIT_ZERO)
|
|
value = 0;
|
|
else if (r_info->h_ext == BIT_SIGN)
|
|
value = ((int)r_info->value >= 0) ? 0 : 1;
|
|
|
|
value <<= t_bits - 1;
|
|
|
|
mask = ((1 << v_bits) - 1) << r_info->low;
|
|
value |= (r_info->value & mask) >> r_info->low;
|
|
|
|
if (r_info->l_ext == BIT_ONE)
|
|
value |= 1;
|
|
|
|
value <<= r_info->sh;
|
|
DL_DEBUG("value : %d, total bit : %d\n", value, t_bits);
|
|
|
|
mask = ((1 << t_bits) - 1) << r_info->sh;
|
|
|
|
if (item_rev)
|
|
data_idx = r_info->item_cnt - r_info->idx - 1;
|
|
else
|
|
data_idx = r_info->idx;
|
|
|
|
data[data_idx] &= ~mask;
|
|
data[data_idx] |= value;
|
|
}
|
|
}
|
|
|
|
static int __cvt_to_item_idx(unsigned int *sh, int num, int item_cnt,
|
|
int item_align)
|
|
{
|
|
int idx;
|
|
|
|
num += item_align;
|
|
idx = item_cnt - num / 8 - 1;
|
|
*sh = num % 8;
|
|
return idx;
|
|
}
|
|
|
|
static int __process_rule(struct dsp_lib *lib, struct dsp_reloc_rule *rule,
|
|
struct dsp_elf32_shdr *rela_shdr, unsigned int value,
|
|
struct dsp_elf32_rela *rela)
|
|
{
|
|
struct dsp_link_info *l_info = lib->link_info;
|
|
struct dsp_elf32 *elf = l_info->elf;
|
|
|
|
struct dsp_elf32_shdr *data_shdr = &elf->shdr[rela_shdr->sh_info];
|
|
char *reloc_data = elf->data + data_shdr->sh_offset + rela->r_offset;
|
|
|
|
int item_bit = rule->cont.type.bit_sz * rule->cont.inst_num;
|
|
int item_cnt = item_bit / 8 + ((item_bit % 8) ? 1 : 0);
|
|
int item_align = item_cnt * 8 - item_bit;
|
|
char item_rev = (char)(rule->cont.type.bit_sz == 8);
|
|
|
|
struct dsp_pos *pos;
|
|
struct dsp_reloc_info r_info;
|
|
struct dsp_bit_slice *sl;
|
|
|
|
struct dsp_list_node *pos_node, *bit_node;
|
|
|
|
if ((reloc_data > (elf->data + elf->size)) ||
|
|
(reloc_data < elf->data)) {
|
|
DL_ERROR("reloc_data is out of range(%#lx/%#zx)\n",
|
|
(unsigned long)(reloc_data - elf->data),
|
|
elf->size);
|
|
return -1;
|
|
}
|
|
DL_DEBUG("reloc_data : %#lx/%#zx\n",
|
|
(unsigned long)(reloc_data - elf->data), elf->size);
|
|
DL_DEBUG("item_bit : %d, cnt : %d, align : %d\n",
|
|
item_bit, item_cnt, item_align);
|
|
DL_DEBUG("cont bit sz : %d, item reversed : %d",
|
|
rule->cont.type.bit_sz, item_rev);
|
|
|
|
dsp_list_for_each(pos_node, &rule->pos_list) {
|
|
pos = container_of(pos_node, struct dsp_pos, list_node);
|
|
|
|
if (pos->type == BIT_POS) {
|
|
r_info.value = value;
|
|
r_info.idx = __cvt_to_item_idx(&r_info.sh,
|
|
pos->bit_pos, item_cnt, item_align);
|
|
r_info.item_cnt = item_cnt;
|
|
r_info.low = 0;
|
|
r_info.high = rule->type.bit_sz - 1;
|
|
r_info.h_ext = BIT_NONE;
|
|
r_info.l_ext = BIT_NONE;
|
|
__relocate(&r_info, reloc_data, item_rev);
|
|
} else {
|
|
dsp_list_for_each(bit_node, &pos->bit_slice_list) {
|
|
sl = container_of(bit_node,
|
|
struct dsp_bit_slice,
|
|
list_node);
|
|
r_info.value = value;
|
|
r_info.low = sl->low;
|
|
r_info.high = sl->high;
|
|
r_info.h_ext = sl->h_ext;
|
|
r_info.l_ext = sl->l_ext;
|
|
r_info.idx = __cvt_to_item_idx(&r_info.sh,
|
|
sl->value, item_cnt,
|
|
item_align);
|
|
r_info.item_cnt = item_cnt;
|
|
__relocate(&r_info, reloc_data, item_rev);
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int __rela_relocation(struct dsp_lib *lib, struct dsp_elf32_rela *rela,
|
|
struct dsp_elf32_shdr *rela_shdr,
|
|
struct dsp_lib **libs, int libs_size,
|
|
struct dsp_lib **common_libs, int common_size)
|
|
{
|
|
int ret;
|
|
struct dsp_elf32 *elf;
|
|
unsigned int symidx;
|
|
struct dsp_elf32_sym *sym;
|
|
const char *sym_str;
|
|
unsigned int ruleidx;
|
|
struct dsp_reloc_rule *rule;
|
|
unsigned int value;
|
|
|
|
elf = lib->link_info->elf;
|
|
symidx = dsp_elf32_rela_get_sym_idx(rela);
|
|
sym = &elf->symtab[symidx];
|
|
sym_str = elf->strtab + sym->st_name;
|
|
|
|
ruleidx = dsp_elf32_rela_get_rule_idx(rela);
|
|
if (ruleidx >= rules->cnt) {
|
|
DL_ERROR("invalid ruleidx(%u/%d)\n", ruleidx, rules->cnt);
|
|
return -1;
|
|
}
|
|
rule = rules->list[ruleidx];
|
|
|
|
ret = __calc_link_value(lib, &value, sym_str, rela, rela_shdr,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Symbol(%s) Link value(%x)\n", sym_str, value);
|
|
|
|
return __process_rule(lib, rule, rela_shdr, value, rela);
|
|
}
|
|
|
|
static int __linker_reloc_list(struct dsp_lib *lib,
|
|
struct dsp_list_head *rela_list,
|
|
struct dsp_lib **libs, int libs_size,
|
|
struct dsp_lib **common_libs, int common_size)
|
|
{
|
|
int ret;
|
|
struct dsp_elf32_rela_node *rela_node;
|
|
struct dsp_elf32_shdr *rela_shdr;
|
|
unsigned int idx;
|
|
struct dsp_list_node *node;
|
|
|
|
dsp_list_for_each(node, rela_list) {
|
|
rela_node =
|
|
container_of(node, struct dsp_elf32_rela_node, node);
|
|
DL_DEBUG("Relocate section %d\n", rela_node->idx);
|
|
|
|
rela_shdr = &lib->link_info->elf->shdr[rela_node->idx];
|
|
|
|
for (idx = 0; idx < rela_node->rela_num; idx++) {
|
|
DL_DEBUG("Relocate rela %d\n", idx);
|
|
ret = __rela_relocation(lib, &rela_node->rela[idx],
|
|
rela_shdr, libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int __linker_relocate(struct dsp_lib *lib,
|
|
struct dsp_lib **libs, int libs_size,
|
|
struct dsp_lib **common_libs, int common_size)
|
|
{
|
|
int ret;
|
|
struct dsp_elf32 *elf = lib->link_info->elf;
|
|
|
|
DL_DEBUG("Reloc text\n");
|
|
ret = __linker_reloc_list(lib, &elf->text.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Reloc DMb\n");
|
|
ret = __linker_reloc_list(lib, &elf->DMb.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Reloc DMb local\n");
|
|
ret = __linker_reloc_list(lib, &elf->DMb_local.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Reloc TCMb\n");
|
|
ret = __linker_reloc_list(lib, &elf->TCMb.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Reloc TCMb_local\n");
|
|
ret = __linker_reloc_list(lib, &elf->TCMb_local.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Reloc DRAMb\n");
|
|
ret = __linker_reloc_list(lib, &elf->DRAMb.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
DL_DEBUG("Reloc SFRw\n");
|
|
ret = __linker_reloc_list(lib, &elf->SFRw.rela,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int dsp_linker_init(struct dsp_dl_lib_file *file)
|
|
{
|
|
int idx;
|
|
int ret;
|
|
|
|
rules = (struct dsp_reloc_rule_list *)dsp_dl_malloc(
|
|
sizeof(struct dsp_reloc_rule_list),
|
|
"Reloc rules");
|
|
ret = dsp_reloc_rule_list_import(rules, file);
|
|
if (ret == -1) {
|
|
DL_ERROR("Failed to import reloc rule list\n");
|
|
dsp_dl_free(rules);
|
|
return -1;
|
|
}
|
|
|
|
gp_str = (struct dsp_string_tree_node *)dsp_dl_malloc(
|
|
sizeof(struct dsp_string_tree_node),
|
|
"Linker string tree");
|
|
|
|
dsp_string_tree_init(gp_str);
|
|
|
|
for (idx = 0; idx < RELOC_GP_NUM; idx++) {
|
|
DL_DEBUG("Strin tree push %s\n", reloc_gp_str[idx]);
|
|
dsp_string_tree_push(gp_str, reloc_gp_str[idx], idx);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void dsp_linker_free(void)
|
|
{
|
|
dsp_reloc_rule_list_free(rules);
|
|
dsp_string_tree_free(gp_str);
|
|
dsp_dl_free(gp_str);
|
|
dsp_dl_free(rules);
|
|
}
|
|
|
|
int dsp_linker_link_libs(struct dsp_lib **libs, int libs_size,
|
|
struct dsp_lib **common_libs, int common_size)
|
|
{
|
|
int ret, idx;
|
|
struct dsp_lib *lib;
|
|
struct dsp_elf32 *elf;
|
|
struct dsp_link_info *l_info;
|
|
unsigned long text_offset;
|
|
|
|
DL_DEBUG(DL_BORDER);
|
|
|
|
for (idx = 0; idx < libs_size; idx++) {
|
|
lib = libs[idx];
|
|
if (!lib->link_info) {
|
|
elf = lib->elf;
|
|
|
|
dsp_linker_alloc_bss(elf);
|
|
|
|
if (!lib->link_info)
|
|
lib->link_info = dsp_link_info_create(elf);
|
|
|
|
l_info = lib->link_info;
|
|
text_offset = lib->pm->start_addr -
|
|
dsp_pm_manager_get_pm_start_addr();
|
|
|
|
dsp_link_info_set_text(l_info, text_offset);
|
|
dsp_link_info_set_DMb(l_info, 0UL);
|
|
dsp_link_info_set_DMb_local(l_info, 0UL);
|
|
dsp_link_info_set_DRAMb(l_info, 0UL);
|
|
dsp_link_info_set_TCMb(l_info, 0UL);
|
|
dsp_link_info_set_TCMb_local(l_info, 0UL);
|
|
dsp_link_info_set_SFRw(l_info, 0UL);
|
|
}
|
|
}
|
|
|
|
for (idx = 0; idx < libs_size; idx++) {
|
|
lib = libs[idx];
|
|
if (!lib->loaded) {
|
|
ret = __linker_relocate(lib,
|
|
libs, libs_size,
|
|
common_libs, common_size);
|
|
if (ret == -1) {
|
|
DL_ERROR("[%s] CHK_ERR\n", __func__);
|
|
return -1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|