Add arm dll support

Most support was already present.

arm-link.c:
- set RELOCATE_DLLPLT to 1
- create_plt_entry:
 - remove DLLs unimplemented!
 - leave code gen to relocate_plt. only set got_offset
- relocate_plt:
 - create code for got entry
- relocate:
 - Add TCC_OUTPUT_DLL for R_ARM_ABS32

tccelf.c:
- prepare_dynamic_rel:
 - Add R_ARM_ABS32
- alloc_sec_names:
 - Always add SHT_ARM_ATTRIBUTES section
- New function create_arm_attribute_section
- elf_output_file:
 - call create_arm_attribute_section
This commit is contained in:
herman ten brugge 2020-08-04 09:15:42 +02:00
parent 1da7159689
commit b8fb2b02d9
2 changed files with 71 additions and 15 deletions

View File

@ -16,7 +16,7 @@
#define ELF_PAGE_SIZE 0x1000
#define PCRELATIVE_DLLPLT 1
#define RELOCATE_DLLPLT 0
#define RELOCATE_DLLPLT 1
enum float_abi {
ARM_SOFTFP_FLOAT,
@ -107,8 +107,6 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
/* when building a DLL, GOT entry accesses must be done relative to
start of GOT (see x86_64 example above) */
if (s1->output_type == TCC_OUTPUT_DLL)
tcc_error("DLLs unimplemented!");
/* empty PLT: create PLT0 entry that push address of call site and
jump to ld.so resolution routine (GOT + 8) */
@ -127,13 +125,9 @@ ST_FUNC unsigned create_plt_entry(TCCState *s1, unsigned got_offset, struct sym_
write32le(p, 0x4778); /* bx pc */
write32le(p+2, 0x46c0); /* nop */
}
p = section_ptr_add(plt, 16);
/* Jump to GOT entry where ld.so initially put address of PLT0 */
write32le(p, 0xe59fc004); /* ldr ip, [pc, #4] */
write32le(p+4, 0xe08fc00c); /* add ip, pc, ip */
write32le(p+8, 0xe59cf000); /* ldr pc, [ip] */
/* p + 12 contains offset to GOT entry once patched by relocate_plt */
write32le(p+12, got_offset);
p = section_ptr_add(plt, 12);
/* save GOT offset for relocate_plt */
write32le(p + 4, got_offset);
return plt_offset;
}
@ -154,10 +148,13 @@ ST_FUNC void relocate_plt(TCCState *s1)
write32le(s1->plt->data + 16, x - 16);
p += 20;
while (p < p_end) {
unsigned off = x + read32le(p + 4) + (s1->plt->data - p) + 4;
if (read32le(p) == 0x46c04778) /* PLT Thumb stub present */
p += 4;
add32le(p + 12, x + (s1->plt->data - p));
p += 16;
write32le(p, 0xe28fc600 | ((off >> 20) & 0xff)); // add ip, pc, #0xNN00000
write32le(p + 4, 0xe28cca00 | ((off >> 12) & 0xff)); // add ip, ip, #0xNN000
write32le(p + 8, 0xe5bcf000 | (off & 0xfff)); // ldr pc, [ip, #0xNNN]!
p += 12;
}
}
}
@ -166,7 +163,7 @@ ST_FUNC void relocate_plt(TCCState *s1)
void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t addr, addr_t val)
{
ElfW(Sym) *sym;
int sym_index;
int sym_index, esym_index;
sym_index = ELFW(R_SYM)(rel->r_info);
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
@ -348,6 +345,18 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
(*(int *)ptr) |= x & 0x7fffffff;
}
case R_ARM_ABS32:
if (s1->output_type == TCC_OUTPUT_DLL) {
esym_index = get_sym_attr(s1, sym_index, 0)->dyn_index;
qrel->r_offset = rel->r_offset;
if (esym_index) {
qrel->r_info = ELFW(R_INFO)(esym_index, R_ARM_ABS32);
qrel++;
return;
} else {
qrel->r_info = ELFW(R_INFO)(0, R_ARM_RELATIVE);
qrel++;
}
}
*(int *)ptr += val;
return;
case R_ARM_REL32:

View File

@ -1028,7 +1028,8 @@ static void relocate_rel(TCCState *s1, Section *sr)
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
{
int count = 0;
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || defined(TCC_TARGET_ARM64)
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || \
defined(TCC_TARGET_ARM) || defined(TCC_TARGET_ARM64)
ElfW_Rel *rel;
for_each_elem(sr, 0, rel, ElfW_Rel) {
int sym_index = ELFW(R_SYM)(rel->r_info);
@ -1046,6 +1047,8 @@ static int prepare_dynamic_rel(TCCState *s1, Section *sr)
case R_X86_64_32:
case R_X86_64_32S:
case R_X86_64_64:
#elif defined(TCC_TARGET_ARM)
case R_ARM_ABS32:
#elif defined(TCC_TARGET_ARM64)
case R_AARCH64_ABS32:
case R_AARCH64_ABS64:
@ -1779,7 +1782,11 @@ static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
if ((s1->do_debug && s->sh_type != SHT_RELX) ||
file_type == TCC_OUTPUT_OBJ ||
(s->sh_flags & SHF_ALLOC) ||
i == (s1->nb_sections - 1)) {
i == (s1->nb_sections - 1)
#ifdef TCC_TARGET_ARM
|| s->sh_type == SHT_ARM_ATTRIBUTES
#endif
) {
/* we output all sections if debug or object file */
s->sh_size = s->data_offset;
}
@ -2339,6 +2346,42 @@ static void tidy_section_headers(TCCState *s1, int *sec_order)
}
#endif
#ifdef TCC_TARGET_ARM
static void create_arm_attribute_section(TCCState *s1)
{
// Needed for DLL support.
static const unsigned char arm_attr[] = {
0x41, // 'A'
0x2c, 0x00, 0x00, 0x00, // size 0x2c
'a', 'e', 'a', 'b', 'i', 0x00, // "aeabi"
0x01, 0x22, 0x00, 0x00, 0x00, // 'File Attributes', size 0x22
0x05, 0x36, 0x00, // 'CPU_name', "6"
0x06, 0x06, // 'CPU_arch', 'v6'
0x08, 0x01, // 'ARM_ISA_use', 'Yes'
0x09, 0x01, // 'THUMB_ISA_use', 'Thumb-1'
0x0a, 0x02, // 'FP_arch', 'VFPv2'
0x12, 0x04, // 'ABI_PCS_wchar_t', 4
0x14, 0x01, // 'ABI_FP_denormal', 'Needed'
0x15, 0x01, // 'ABI_FP_exceptions', 'Needed'
0x17, 0x03, // 'ABI_FP_number_model', 'IEEE 754'
0x18, 0x01, // 'ABI_align_needed', '8-byte'
0x19, 0x01, // 'ABI_align_preserved', '8-byte, except leaf SP'
0x1a, 0x02, // 'ABI_enum_size', 'int'
0x1c, 0x01, // 'ABI_VFP_args', 'VFP registers'
0x22, 0x01 // 'CPU_unaligned_access', 'v6'
};
Section *attr = new_section(s1, ".ARM.attributes", SHT_ARM_ATTRIBUTES, 0);
unsigned char *ptr = section_ptr_add(attr, sizeof(arm_attr));
attr->sh_addralign = 1;
memcpy(ptr, arm_attr, sizeof(arm_attr));
if (s1->float_abi != ARM_HARD_FLOAT) {
ptr[26] = 0x00; // 'FP_arch', 'No'
ptr[41] = 0x1e; // 'ABI_optimization_goals'
ptr[42] = 0x06; // 'Aggressive Debug'
}
}
#endif
/* Output an elf, coff or binary file */
/* XXX: suppress unneeded sections */
static int elf_output_file(TCCState *s1, const char *filename)
@ -2348,6 +2391,10 @@ static int elf_output_file(TCCState *s1, const char *filename)
ElfW(Phdr) *phdr;
Section *strsec, *interp, *dynamic, *dynstr;
#ifdef TCC_TARGET_ARM
create_arm_attribute_section (s1);
#endif
file_type = s1->output_type;
s1->nb_errors = 0;
ret = -1;