2002-08-18 21:17:59 +08:00
|
|
|
/*
|
|
|
|
* ELF file handling for TCC
|
2013-12-17 20:59:14 +08:00
|
|
|
*
|
2004-10-28 05:38:03 +08:00
|
|
|
* Copyright (c) 2001-2004 Fabrice Bellard
|
2002-08-18 21:17:59 +08:00
|
|
|
*
|
2003-05-24 22:11:17 +08:00
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
2002-08-18 21:17:59 +08:00
|
|
|
*
|
2003-05-24 22:11:17 +08:00
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
2002-08-18 21:17:59 +08:00
|
|
|
*
|
2003-05-24 22:11:17 +08:00
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
|
|
* License along with this library; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
2002-08-18 21:17:59 +08:00
|
|
|
*/
|
|
|
|
|
2009-12-20 08:53:49 +08:00
|
|
|
#include "tcc.h"
|
|
|
|
|
2014-04-06 07:02:42 +08:00
|
|
|
/* Define this to get some debug output during relocation processing. */
|
|
|
|
#undef DEBUG_RELOC
|
|
|
|
|
2016-10-15 21:55:31 +08:00
|
|
|
/********************************************************/
|
|
|
|
/* global variables */
|
|
|
|
|
2019-10-22 22:55:20 +08:00
|
|
|
/* elf version information */
|
2019-11-26 04:06:07 +08:00
|
|
|
struct sym_version {
|
|
|
|
char *lib;
|
2019-10-22 22:55:20 +08:00
|
|
|
char *version;
|
2019-11-26 04:06:07 +08:00
|
|
|
int out_index;
|
|
|
|
int prev_same_lib;
|
|
|
|
};
|
2019-12-10 03:32:13 +08:00
|
|
|
|
|
|
|
#define nb_sym_versions s1->nb_sym_versions
|
|
|
|
#define sym_versions s1->sym_versions
|
|
|
|
#define nb_sym_to_version s1->nb_sym_to_version
|
|
|
|
#define sym_to_version s1->sym_to_version
|
|
|
|
#define dt_verneednum s1->dt_verneednum
|
|
|
|
#define versym_section s1->versym_section
|
|
|
|
#define verneed_section s1->verneed_section
|
2019-10-22 22:55:20 +08:00
|
|
|
|
2017-12-13 00:57:20 +08:00
|
|
|
/* special flag to indicate that the section should not be linked to the other ones */
|
|
|
|
#define SHF_PRIVATE 0x80000000
|
|
|
|
/* section is dynsymtab_section */
|
|
|
|
#define SHF_DYNSYM 0x40000000
|
|
|
|
|
2016-10-15 21:55:31 +08:00
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
|
|
|
ST_FUNC void tccelf_new(TCCState *s)
|
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
TCCState *s1 = s;
|
2016-10-15 21:55:31 +08:00
|
|
|
/* no section zero */
|
2017-02-14 01:23:43 +08:00
|
|
|
dynarray_add(&s->sections, &s->nb_sections, NULL);
|
2016-10-15 21:55:31 +08:00
|
|
|
|
|
|
|
/* create standard sections */
|
|
|
|
text_section = new_section(s, ".text", SHT_PROGBITS, SHF_ALLOC | SHF_EXECINSTR);
|
|
|
|
data_section = new_section(s, ".data", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
|
|
|
bss_section = new_section(s, ".bss", SHT_NOBITS, SHF_ALLOC | SHF_WRITE);
|
2017-03-12 12:25:09 +08:00
|
|
|
common_section = new_section(s, ".common", SHT_NOBITS, SHF_PRIVATE);
|
|
|
|
common_section->sh_num = SHN_COMMON;
|
2016-10-15 21:55:31 +08:00
|
|
|
|
|
|
|
/* symbols are always generated for linking stage */
|
|
|
|
symtab_section = new_symtab(s, ".symtab", SHT_SYMTAB, 0,
|
|
|
|
".strtab",
|
|
|
|
".hashtab", SHF_PRIVATE);
|
|
|
|
s->symtab = symtab_section;
|
|
|
|
|
|
|
|
/* private symbol table for dynamic symbols */
|
2017-12-13 00:57:20 +08:00
|
|
|
s->dynsymtab_section = new_symtab(s, ".dynsymtab", SHT_SYMTAB, SHF_PRIVATE|SHF_DYNSYM,
|
2016-10-15 21:55:31 +08:00
|
|
|
".dynstrtab",
|
|
|
|
".dynhashtab", SHF_PRIVATE);
|
2016-12-16 00:01:22 +08:00
|
|
|
get_sym_attr(s, 0, 1);
|
2016-10-15 21:55:31 +08:00
|
|
|
}
|
|
|
|
|
2016-10-18 05:24:01 +08:00
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
|
|
|
ST_FUNC void tccelf_bounds_new(TCCState *s)
|
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
TCCState *s1 = s;
|
2016-10-18 05:24:01 +08:00
|
|
|
/* create bounds sections */
|
|
|
|
bounds_section = new_section(s, ".bounds",
|
|
|
|
SHT_PROGBITS, SHF_ALLOC);
|
|
|
|
lbounds_section = new_section(s, ".lbounds",
|
|
|
|
SHT_PROGBITS, SHF_ALLOC);
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
ST_FUNC void tccelf_stab_new(TCCState *s)
|
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
TCCState *s1 = s;
|
2020-01-18 05:58:39 +08:00
|
|
|
int shf = 0;
|
|
|
|
#ifdef CONFIG_TCC_BACKTRACE
|
|
|
|
/* include stab info with standalone backtrace support */
|
|
|
|
if (s->do_backtrace && s->output_type != TCC_OUTPUT_MEMORY)
|
|
|
|
shf = SHF_ALLOC;
|
|
|
|
#endif
|
|
|
|
stab_section = new_section(s, ".stab", SHT_PROGBITS, shf);
|
2016-10-18 05:24:01 +08:00
|
|
|
stab_section->sh_entsize = sizeof(Stab_Sym);
|
2020-01-18 05:58:39 +08:00
|
|
|
stab_section->sh_addralign = sizeof ((Stab_Sym*)0)->n_value;
|
|
|
|
stab_section->link = new_section(s, ".stabstr", SHT_STRTAB, shf);
|
2016-10-18 05:24:01 +08:00
|
|
|
/* put first entry */
|
2019-12-11 07:37:18 +08:00
|
|
|
put_stabs(s, "", 0, 0, 0, 0);
|
2016-10-18 05:24:01 +08:00
|
|
|
}
|
|
|
|
|
2016-10-15 21:55:31 +08:00
|
|
|
static void free_section(Section *s)
|
|
|
|
{
|
|
|
|
tcc_free(s->data);
|
|
|
|
}
|
|
|
|
|
|
|
|
ST_FUNC void tccelf_delete(TCCState *s1)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2019-11-26 04:06:07 +08:00
|
|
|
/* free symbol versions */
|
|
|
|
for (i = 0; i < nb_sym_versions; i++) {
|
|
|
|
tcc_free(sym_versions[i].version);
|
|
|
|
tcc_free(sym_versions[i].lib);
|
|
|
|
}
|
|
|
|
tcc_free(sym_versions);
|
|
|
|
tcc_free(sym_to_version);
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2019-11-26 04:06:07 +08:00
|
|
|
|
2016-10-15 21:55:31 +08:00
|
|
|
/* free all sections */
|
|
|
|
for(i = 1; i < s1->nb_sections; i++)
|
|
|
|
free_section(s1->sections[i]);
|
|
|
|
dynarray_reset(&s1->sections, &s1->nb_sections);
|
|
|
|
|
|
|
|
for(i = 0; i < s1->nb_priv_sections; i++)
|
|
|
|
free_section(s1->priv_sections[i]);
|
|
|
|
dynarray_reset(&s1->priv_sections, &s1->nb_priv_sections);
|
|
|
|
|
|
|
|
/* free any loaded DLLs */
|
|
|
|
#ifdef TCC_IS_NATIVE
|
|
|
|
for ( i = 0; i < s1->nb_loaded_dlls; i++) {
|
|
|
|
DLLReference *ref = s1->loaded_dlls[i];
|
|
|
|
if ( ref->handle )
|
|
|
|
# ifdef _WIN32
|
|
|
|
FreeLibrary((HMODULE)ref->handle);
|
|
|
|
# else
|
|
|
|
dlclose(ref->handle);
|
|
|
|
# endif
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* free loaded dlls array */
|
|
|
|
dynarray_reset(&s1->loaded_dlls, &s1->nb_loaded_dlls);
|
2016-12-16 00:01:22 +08:00
|
|
|
tcc_free(s1->sym_attrs);
|
2017-12-13 00:57:20 +08:00
|
|
|
|
|
|
|
symtab_section = NULL; /* for tccrun.c:rt_printline() */
|
2016-10-15 21:55:31 +08:00
|
|
|
}
|
|
|
|
|
2017-12-13 00:33:37 +08:00
|
|
|
/* save section data state */
|
|
|
|
ST_FUNC void tccelf_begin_file(TCCState *s1)
|
|
|
|
{
|
|
|
|
Section *s; int i;
|
|
|
|
for (i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
|
|
|
s->sh_offset = s->data_offset;
|
|
|
|
}
|
|
|
|
/* disable symbol hashing during compilation */
|
|
|
|
s = s1->symtab, s->reloc = s->hash, s->hash = NULL;
|
|
|
|
#if defined TCC_TARGET_X86_64 && defined TCC_TARGET_PE
|
|
|
|
s1->uw_sym = 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
/* At the end of compilation, convert any UNDEF syms to global, and merge
|
|
|
|
with previously existing symbols */
|
|
|
|
ST_FUNC void tccelf_end_file(TCCState *s1)
|
|
|
|
{
|
|
|
|
Section *s = s1->symtab;
|
|
|
|
int first_sym, nb_syms, *tr, i;
|
|
|
|
|
|
|
|
first_sym = s->sh_offset / sizeof (ElfSym);
|
|
|
|
nb_syms = s->data_offset / sizeof (ElfSym) - first_sym;
|
|
|
|
s->data_offset = s->sh_offset;
|
|
|
|
s->link->data_offset = s->link->sh_offset;
|
|
|
|
s->hash = s->reloc, s->reloc = NULL;
|
|
|
|
tr = tcc_mallocz(nb_syms * sizeof *tr);
|
|
|
|
|
|
|
|
for (i = 0; i < nb_syms; ++i) {
|
|
|
|
ElfSym *sym = (ElfSym*)s->data + first_sym + i;
|
|
|
|
if (sym->st_shndx == SHN_UNDEF
|
|
|
|
&& ELFW(ST_BIND)(sym->st_info) == STB_LOCAL)
|
|
|
|
sym->st_info = ELFW(ST_INFO)(STB_GLOBAL, ELFW(ST_TYPE)(sym->st_info));
|
|
|
|
tr[i] = set_elf_sym(s, sym->st_value, sym->st_size, sym->st_info,
|
2018-06-08 21:31:40 +08:00
|
|
|
sym->st_other, sym->st_shndx, (char*)s->link->data + sym->st_name);
|
2017-12-13 00:33:37 +08:00
|
|
|
}
|
|
|
|
/* now update relocations */
|
|
|
|
for (i = 1; i < s1->nb_sections; i++) {
|
|
|
|
Section *sr = s1->sections[i];
|
|
|
|
if (sr->sh_type == SHT_RELX && sr->link == s) {
|
|
|
|
ElfW_Rel *rel = (ElfW_Rel*)(sr->data + sr->sh_offset);
|
|
|
|
ElfW_Rel *rel_end = (ElfW_Rel*)(sr->data + sr->data_offset);
|
|
|
|
for (; rel < rel_end; ++rel) {
|
|
|
|
int n = ELFW(R_SYM)(rel->r_info) - first_sym;
|
|
|
|
//if (n < 0) tcc_error("internal: invalid symbol index in relocation");
|
|
|
|
rel->r_info = ELFW(R_INFO)(tr[n], ELFW(R_TYPE)(rel->r_info));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
tcc_free(tr);
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:55:31 +08:00
|
|
|
ST_FUNC Section *new_section(TCCState *s1, const char *name, int sh_type, int sh_flags)
|
|
|
|
{
|
|
|
|
Section *sec;
|
|
|
|
|
|
|
|
sec = tcc_mallocz(sizeof(Section) + strlen(name));
|
2019-12-11 07:37:18 +08:00
|
|
|
sec->s1 = s1;
|
2016-10-15 21:55:31 +08:00
|
|
|
strcpy(sec->name, name);
|
|
|
|
sec->sh_type = sh_type;
|
|
|
|
sec->sh_flags = sh_flags;
|
|
|
|
switch(sh_type) {
|
2019-10-22 22:55:20 +08:00
|
|
|
case SHT_GNU_versym:
|
|
|
|
sec->sh_addralign = 2;
|
|
|
|
break;
|
2016-10-15 21:55:31 +08:00
|
|
|
case SHT_HASH:
|
|
|
|
case SHT_REL:
|
|
|
|
case SHT_RELA:
|
|
|
|
case SHT_DYNSYM:
|
|
|
|
case SHT_SYMTAB:
|
|
|
|
case SHT_DYNAMIC:
|
2019-10-22 22:55:20 +08:00
|
|
|
case SHT_GNU_verneed:
|
|
|
|
case SHT_GNU_verdef:
|
|
|
|
sec->sh_addralign = PTR_SIZE;
|
2016-10-15 21:55:31 +08:00
|
|
|
break;
|
|
|
|
case SHT_STRTAB:
|
|
|
|
sec->sh_addralign = 1;
|
|
|
|
break;
|
|
|
|
default:
|
2017-05-08 12:38:09 +08:00
|
|
|
sec->sh_addralign = PTR_SIZE; /* gcc/pcc default alignment */
|
2016-10-15 21:55:31 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (sh_flags & SHF_PRIVATE) {
|
2017-02-14 01:23:43 +08:00
|
|
|
dynarray_add(&s1->priv_sections, &s1->nb_priv_sections, sec);
|
2016-10-15 21:55:31 +08:00
|
|
|
} else {
|
|
|
|
sec->sh_num = s1->nb_sections;
|
2017-02-14 01:23:43 +08:00
|
|
|
dynarray_add(&s1->sections, &s1->nb_sections, sec);
|
2016-10-15 21:55:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
|
2016-12-16 00:01:22 +08:00
|
|
|
ST_FUNC Section *new_symtab(TCCState *s1,
|
|
|
|
const char *symtab_name, int sh_type, int sh_flags,
|
|
|
|
const char *strtab_name,
|
|
|
|
const char *hash_name, int hash_sh_flags)
|
|
|
|
{
|
|
|
|
Section *symtab, *strtab, *hash;
|
|
|
|
int *ptr, nb_buckets;
|
|
|
|
|
|
|
|
symtab = new_section(s1, symtab_name, sh_type, sh_flags);
|
|
|
|
symtab->sh_entsize = sizeof(ElfW(Sym));
|
|
|
|
strtab = new_section(s1, strtab_name, SHT_STRTAB, sh_flags);
|
|
|
|
put_elf_str(strtab, "");
|
|
|
|
symtab->link = strtab;
|
|
|
|
put_elf_sym(symtab, 0, 0, 0, 0, 0, NULL);
|
|
|
|
|
|
|
|
nb_buckets = 1;
|
|
|
|
|
|
|
|
hash = new_section(s1, hash_name, SHT_HASH, hash_sh_flags);
|
|
|
|
hash->sh_entsize = sizeof(int);
|
|
|
|
symtab->hash = hash;
|
|
|
|
hash->link = symtab;
|
|
|
|
|
|
|
|
ptr = section_ptr_add(hash, (2 + nb_buckets + 1) * sizeof(int));
|
|
|
|
ptr[0] = nb_buckets;
|
|
|
|
ptr[1] = 1;
|
|
|
|
memset(ptr + 2, 0, (nb_buckets + 1) * sizeof(int));
|
|
|
|
return symtab;
|
|
|
|
}
|
|
|
|
|
2016-10-15 21:55:31 +08:00
|
|
|
/* realloc section and set its content to zero */
|
|
|
|
ST_FUNC void section_realloc(Section *sec, unsigned long new_size)
|
|
|
|
{
|
|
|
|
unsigned long size;
|
|
|
|
unsigned char *data;
|
|
|
|
|
|
|
|
size = sec->data_allocated;
|
|
|
|
if (size == 0)
|
|
|
|
size = 1;
|
|
|
|
while (size < new_size)
|
|
|
|
size = size * 2;
|
|
|
|
data = tcc_realloc(sec->data, size);
|
|
|
|
memset(data + sec->data_allocated, 0, size - sec->data_allocated);
|
|
|
|
sec->data = data;
|
|
|
|
sec->data_allocated = size;
|
|
|
|
}
|
|
|
|
|
2017-03-12 12:25:09 +08:00
|
|
|
/* reserve at least 'size' bytes aligned per 'align' in section
|
|
|
|
'sec' from current offset, and return the aligned offset */
|
|
|
|
ST_FUNC size_t section_add(Section *sec, addr_t size, int align)
|
2016-10-15 21:55:31 +08:00
|
|
|
{
|
|
|
|
size_t offset, offset1;
|
|
|
|
|
2017-03-12 12:25:09 +08:00
|
|
|
offset = (sec->data_offset + align - 1) & -align;
|
2016-10-15 21:55:31 +08:00
|
|
|
offset1 = offset + size;
|
2017-03-12 12:25:09 +08:00
|
|
|
if (sec->sh_type != SHT_NOBITS && offset1 > sec->data_allocated)
|
2016-10-15 21:55:31 +08:00
|
|
|
section_realloc(sec, offset1);
|
|
|
|
sec->data_offset = offset1;
|
2017-03-12 12:25:09 +08:00
|
|
|
if (align > sec->sh_addralign)
|
|
|
|
sec->sh_addralign = align;
|
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reserve at least 'size' bytes in section 'sec' from
|
|
|
|
sec->data_offset. */
|
|
|
|
ST_FUNC void *section_ptr_add(Section *sec, addr_t size)
|
|
|
|
{
|
|
|
|
size_t offset = section_add(sec, size, 1);
|
2016-10-15 21:55:31 +08:00
|
|
|
return sec->data + offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* reserve at least 'size' bytes from section start */
|
|
|
|
ST_FUNC void section_reserve(Section *sec, unsigned long size)
|
|
|
|
{
|
|
|
|
if (size > sec->data_allocated)
|
|
|
|
section_realloc(sec, size);
|
|
|
|
if (size > sec->data_offset)
|
|
|
|
sec->data_offset = size;
|
|
|
|
}
|
|
|
|
|
2019-10-29 14:02:58 +08:00
|
|
|
static Section *find_section_create (TCCState *s1, const char *name, int create)
|
2016-10-15 21:55:31 +08:00
|
|
|
{
|
|
|
|
Section *sec;
|
|
|
|
int i;
|
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
sec = s1->sections[i];
|
|
|
|
if (!strcmp(name, sec->name))
|
|
|
|
return sec;
|
|
|
|
}
|
|
|
|
/* sections are created as PROGBITS */
|
2019-10-29 14:02:58 +08:00
|
|
|
return create ? new_section(s1, name, SHT_PROGBITS, SHF_ALLOC) : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return a reference to a section, and create it if it does not
|
|
|
|
exists */
|
|
|
|
ST_FUNC Section *find_section(TCCState *s1, const char *name)
|
|
|
|
{
|
|
|
|
return find_section_create (s1, name, 1);
|
2016-10-15 21:55:31 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ------------------------------------------------------------------------- */
|
|
|
|
|
2009-12-20 08:53:49 +08:00
|
|
|
ST_FUNC int put_elf_str(Section *s, const char *sym)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
int offset, len;
|
|
|
|
char *ptr;
|
|
|
|
|
|
|
|
len = strlen(sym) + 1;
|
|
|
|
offset = s->data_offset;
|
|
|
|
ptr = section_ptr_add(s, len);
|
2017-12-13 00:33:37 +08:00
|
|
|
memmove(ptr, sym, len);
|
2002-08-18 21:17:59 +08:00
|
|
|
return offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* elf symbol hashing function */
|
|
|
|
static unsigned long elf_hash(const unsigned char *name)
|
|
|
|
{
|
|
|
|
unsigned long h = 0, g;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
while (*name) {
|
|
|
|
h = (h << 4) + *name++;
|
|
|
|
g = h & 0xf0000000;
|
|
|
|
if (g)
|
|
|
|
h ^= g >> 24;
|
|
|
|
h &= ~g;
|
|
|
|
}
|
|
|
|
return h;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* rebuild hash table of section s */
|
|
|
|
/* NOTE: we do factorize the hash table code to go faster */
|
|
|
|
static void rebuild_hash(Section *s, unsigned int nb_buckets)
|
|
|
|
{
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2002-08-18 21:17:59 +08:00
|
|
|
int *ptr, *hash, nb_syms, sym_index, h;
|
2014-03-09 22:52:31 +08:00
|
|
|
unsigned char *strtab;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
strtab = s->link->data;
|
2008-11-30 07:14:07 +08:00
|
|
|
nb_syms = s->data_offset / sizeof(ElfW(Sym));
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2017-12-10 13:18:27 +08:00
|
|
|
if (!nb_buckets)
|
|
|
|
nb_buckets = ((int*)s->hash->data)[0];
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
s->hash->data_offset = 0;
|
|
|
|
ptr = section_ptr_add(s->hash, (2 + nb_buckets + nb_syms) * sizeof(int));
|
|
|
|
ptr[0] = nb_buckets;
|
|
|
|
ptr[1] = nb_syms;
|
|
|
|
ptr += 2;
|
|
|
|
hash = ptr;
|
|
|
|
memset(hash, 0, (nb_buckets + 1) * sizeof(int));
|
|
|
|
ptr += nb_buckets + 1;
|
|
|
|
|
2008-11-30 07:14:07 +08:00
|
|
|
sym = (ElfW(Sym) *)s->data + 1;
|
2002-08-18 21:17:59 +08:00
|
|
|
for(sym_index = 1; sym_index < nb_syms; sym_index++) {
|
2017-11-30 22:15:22 +08:00
|
|
|
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
2002-08-18 21:17:59 +08:00
|
|
|
h = elf_hash(strtab + sym->st_name) % nb_buckets;
|
|
|
|
*ptr = hash[h];
|
|
|
|
hash[h] = sym_index;
|
|
|
|
} else {
|
|
|
|
*ptr = 0;
|
|
|
|
}
|
|
|
|
ptr++;
|
|
|
|
sym++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* return the symbol number */
|
2013-02-04 23:08:06 +08:00
|
|
|
ST_FUNC int put_elf_sym(Section *s, addr_t value, unsigned long size,
|
2010-01-15 03:56:04 +08:00
|
|
|
int info, int other, int shndx, const char *name)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
int name_offset, sym_index;
|
|
|
|
int nbuckets, h;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2002-08-18 21:17:59 +08:00
|
|
|
Section *hs;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2008-11-30 07:14:07 +08:00
|
|
|
sym = section_ptr_add(s, sizeof(ElfW(Sym)));
|
2017-12-13 00:33:37 +08:00
|
|
|
if (name && name[0])
|
2002-08-18 21:17:59 +08:00
|
|
|
name_offset = put_elf_str(s->link, name);
|
|
|
|
else
|
|
|
|
name_offset = 0;
|
|
|
|
/* XXX: endianness */
|
|
|
|
sym->st_name = name_offset;
|
|
|
|
sym->st_value = value;
|
|
|
|
sym->st_size = size;
|
|
|
|
sym->st_info = info;
|
|
|
|
sym->st_other = other;
|
|
|
|
sym->st_shndx = shndx;
|
2008-11-30 07:14:07 +08:00
|
|
|
sym_index = sym - (ElfW(Sym) *)s->data;
|
2002-08-18 21:17:59 +08:00
|
|
|
hs = s->hash;
|
|
|
|
if (hs) {
|
|
|
|
int *ptr, *base;
|
|
|
|
ptr = section_ptr_add(hs, sizeof(int));
|
|
|
|
base = (int *)hs->data;
|
2017-11-30 22:15:22 +08:00
|
|
|
/* only add global or weak symbols. */
|
|
|
|
if (ELFW(ST_BIND)(info) != STB_LOCAL) {
|
2002-08-18 21:17:59 +08:00
|
|
|
/* add another hashing entry */
|
|
|
|
nbuckets = base[0];
|
2017-12-13 00:33:37 +08:00
|
|
|
h = elf_hash((unsigned char *)s->link->data + name_offset) % nbuckets;
|
2002-08-18 21:17:59 +08:00
|
|
|
*ptr = base[2 + h];
|
|
|
|
base[2 + h] = sym_index;
|
|
|
|
base[1]++;
|
|
|
|
/* we resize the hash table */
|
|
|
|
hs->nb_hashed_syms++;
|
|
|
|
if (hs->nb_hashed_syms > 2 * nbuckets) {
|
|
|
|
rebuild_hash(s, 2 * nbuckets);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
*ptr = 0;
|
|
|
|
base[1]++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return sym_index;
|
|
|
|
}
|
|
|
|
|
2017-12-13 00:33:37 +08:00
|
|
|
ST_FUNC int find_elf_sym(Section *s, const char *name)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2002-08-18 21:17:59 +08:00
|
|
|
Section *hs;
|
|
|
|
int nbuckets, sym_index, h;
|
|
|
|
const char *name1;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
hs = s->hash;
|
|
|
|
if (!hs)
|
|
|
|
return 0;
|
|
|
|
nbuckets = ((int *)hs->data)[0];
|
2014-03-09 22:52:31 +08:00
|
|
|
h = elf_hash((unsigned char *) name) % nbuckets;
|
2002-08-18 21:17:59 +08:00
|
|
|
sym_index = ((int *)hs->data)[2 + h];
|
|
|
|
while (sym_index != 0) {
|
2008-11-30 07:14:07 +08:00
|
|
|
sym = &((ElfW(Sym) *)s->data)[sym_index];
|
2014-03-09 22:52:31 +08:00
|
|
|
name1 = (char *) s->link->data + sym->st_name;
|
2017-12-13 00:33:37 +08:00
|
|
|
if (!strcmp(name, name1))
|
2002-08-18 21:17:59 +08:00
|
|
|
return sym_index;
|
|
|
|
sym_index = ((int *)hs->data)[2 + nbuckets + sym_index];
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2020-05-22 10:28:02 +08:00
|
|
|
/* return elf symbol value, signal error if 'err' is nonzero, decorate
|
|
|
|
name if FORC */
|
|
|
|
ST_FUNC addr_t get_sym_addr(TCCState *s1, const char *name, int err, int forc)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
int sym_index;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2020-06-27 23:15:06 +08:00
|
|
|
char buf[256];
|
|
|
|
if (forc && s1->leading_underscore
|
|
|
|
#ifdef TCC_TARGET_PE
|
|
|
|
/* win32-32bit stdcall symbols always have _ already */
|
|
|
|
&& !strchr(name, '@')
|
|
|
|
#endif
|
|
|
|
) {
|
|
|
|
buf[0] = '_';
|
|
|
|
pstrcpy(buf + 1, sizeof(buf) - 1, name);
|
|
|
|
name = buf;
|
|
|
|
}
|
|
|
|
sym_index = find_elf_sym(s1->symtab, name);
|
2019-12-11 07:37:18 +08:00
|
|
|
sym = &((ElfW(Sym) *)s1->symtab->data)[sym_index];
|
2009-07-10 23:29:10 +08:00
|
|
|
if (!sym_index || sym->st_shndx == SHN_UNDEF) {
|
|
|
|
if (err)
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error("%s not defined", name);
|
2020-06-27 23:15:06 +08:00
|
|
|
return (addr_t)-1;
|
2009-07-10 23:29:10 +08:00
|
|
|
}
|
2013-02-04 23:08:06 +08:00
|
|
|
return sym->st_value;
|
2003-07-21 03:19:58 +08:00
|
|
|
}
|
|
|
|
|
2020-06-27 23:15:06 +08:00
|
|
|
/* return elf symbol value */
|
|
|
|
LIBTCCAPI void *tcc_get_symbol(TCCState *s, const char *name)
|
|
|
|
{
|
|
|
|
addr_t addr = get_sym_addr(s, name, 0, 1);
|
|
|
|
return addr == -1 ? NULL : (void*)(uintptr_t)addr;
|
|
|
|
}
|
|
|
|
|
2019-09-16 15:24:16 +08:00
|
|
|
/* list elf symbol names and values */
|
|
|
|
ST_FUNC void list_elf_symbols(TCCState *s, void *ctx,
|
|
|
|
void (*symbol_cb)(void *ctx, const char *name, const void *val))
|
|
|
|
{
|
|
|
|
ElfW(Sym) *sym;
|
|
|
|
Section *symtab;
|
|
|
|
int sym_index, end_sym;
|
|
|
|
const char *name;
|
|
|
|
unsigned char sym_vis, sym_bind;
|
|
|
|
|
|
|
|
symtab = s->symtab;
|
|
|
|
end_sym = symtab->data_offset / sizeof (ElfSym);
|
|
|
|
for (sym_index = 0; sym_index < end_sym; ++sym_index) {
|
|
|
|
sym = &((ElfW(Sym) *)symtab->data)[sym_index];
|
|
|
|
if (sym->st_value) {
|
|
|
|
name = (char *) symtab->link->data + sym->st_name;
|
|
|
|
sym_bind = ELFW(ST_BIND)(sym->st_info);
|
|
|
|
sym_vis = ELFW(ST_VISIBILITY)(sym->st_other);
|
|
|
|
if (sym_bind == STB_GLOBAL && sym_vis == STV_DEFAULT)
|
|
|
|
symbol_cb(ctx, name, (void*)(uintptr_t)sym->st_value);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* list elf symbol names and values */
|
|
|
|
LIBTCCAPI void tcc_list_symbols(TCCState *s, void *ctx,
|
|
|
|
void (*symbol_cb)(void *ctx, const char *name, const void *val))
|
|
|
|
{
|
|
|
|
list_elf_symbols(s, ctx, symbol_cb);
|
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2019-10-22 22:55:20 +08:00
|
|
|
static void
|
2019-12-11 07:37:18 +08:00
|
|
|
version_add (TCCState *s1)
|
2019-10-22 22:55:20 +08:00
|
|
|
{
|
2019-11-26 04:06:07 +08:00
|
|
|
int i;
|
2019-10-22 22:55:20 +08:00
|
|
|
ElfW(Sym) *sym;
|
2019-11-26 04:06:07 +08:00
|
|
|
ElfW(Verneed) *vn = NULL;
|
2019-10-22 22:55:20 +08:00
|
|
|
Section *symtab;
|
2019-11-26 04:06:07 +08:00
|
|
|
int sym_index, end_sym, nb_versions = 2, nb_entries = 0;
|
|
|
|
ElfW(Half) *versym;
|
2019-10-22 22:55:20 +08:00
|
|
|
const char *name;
|
2019-12-10 03:32:13 +08:00
|
|
|
|
|
|
|
if (0 == nb_sym_versions)
|
|
|
|
return;
|
|
|
|
versym_section = new_section(s1, ".gnu.version", SHT_GNU_versym, SHF_ALLOC);
|
|
|
|
versym_section->sh_entsize = sizeof(ElfW(Half));
|
|
|
|
versym_section->link = s1->dynsym;
|
2019-10-22 22:55:20 +08:00
|
|
|
|
|
|
|
/* add needed symbols */
|
2019-12-11 07:37:18 +08:00
|
|
|
symtab = s1->dynsym;
|
2019-10-22 22:55:20 +08:00
|
|
|
end_sym = symtab->data_offset / sizeof (ElfSym);
|
2019-11-26 04:06:07 +08:00
|
|
|
versym = section_ptr_add(versym_section, end_sym * sizeof(ElfW(Half)));
|
2019-10-22 22:55:20 +08:00
|
|
|
for (sym_index = 0; sym_index < end_sym; ++sym_index) {
|
2019-11-26 04:06:07 +08:00
|
|
|
int dllindex, verndx;
|
2019-10-22 22:55:20 +08:00
|
|
|
sym = &((ElfW(Sym) *)symtab->data)[sym_index];
|
|
|
|
name = (char *) symtab->link->data + sym->st_name;
|
2019-12-11 07:37:18 +08:00
|
|
|
dllindex = find_elf_sym(s1->dynsymtab_section, name);
|
2019-11-26 04:06:07 +08:00
|
|
|
verndx = (dllindex && dllindex < nb_sym_to_version)
|
|
|
|
? sym_to_version[dllindex] : -1;
|
|
|
|
if (verndx >= 0) {
|
|
|
|
if (!sym_versions[verndx].out_index)
|
|
|
|
sym_versions[verndx].out_index = nb_versions++;
|
|
|
|
versym[sym_index] = sym_versions[verndx].out_index;
|
|
|
|
} else
|
|
|
|
versym[sym_index] = 0;
|
2019-10-22 22:55:20 +08:00
|
|
|
}
|
2020-01-20 12:31:09 +08:00
|
|
|
/* generate verneed section, but not when it will be empty. Some
|
|
|
|
dynamic linkers look at their contents even when DTVERNEEDNUM and
|
|
|
|
section size is zero. */
|
|
|
|
if (nb_versions > 2) {
|
|
|
|
verneed_section = new_section(s1, ".gnu.version_r",
|
|
|
|
SHT_GNU_verneed, SHF_ALLOC);
|
|
|
|
verneed_section->link = s1->dynsym->link;
|
|
|
|
for (i = nb_sym_versions; i-- > 0;) {
|
|
|
|
struct sym_version *sv = &sym_versions[i];
|
|
|
|
int n_same_libs = 0, prev;
|
|
|
|
size_t vnofs;
|
|
|
|
ElfW(Vernaux) *vna = 0;
|
|
|
|
if (sv->out_index < 1)
|
|
|
|
continue;
|
|
|
|
vnofs = section_add(verneed_section, sizeof(*vn), 1);
|
|
|
|
vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
|
|
|
|
vn->vn_version = 1;
|
|
|
|
vn->vn_file = put_elf_str(verneed_section->link, sv->lib);
|
|
|
|
vn->vn_aux = sizeof (*vn);
|
|
|
|
do {
|
|
|
|
prev = sv->prev_same_lib;
|
|
|
|
if (sv->out_index > 0) {
|
|
|
|
vna = section_ptr_add(verneed_section, sizeof(*vna));
|
|
|
|
vna->vna_hash = elf_hash ((const unsigned char *)sv->version);
|
|
|
|
vna->vna_flags = 0;
|
|
|
|
vna->vna_other = sv->out_index;
|
|
|
|
sv->out_index = -2;
|
|
|
|
vna->vna_name = put_elf_str(verneed_section->link, sv->version);
|
|
|
|
vna->vna_next = sizeof (*vna);
|
|
|
|
n_same_libs++;
|
|
|
|
}
|
|
|
|
if (prev >= 0)
|
|
|
|
sv = &sym_versions[prev];
|
|
|
|
} while(prev >= 0);
|
|
|
|
vna->vna_next = 0;
|
|
|
|
vn = (ElfW(Verneed)*)(verneed_section->data + vnofs);
|
|
|
|
vn->vn_cnt = n_same_libs;
|
|
|
|
vn->vn_next = sizeof(*vn) + n_same_libs * sizeof(*vna);
|
|
|
|
nb_entries++;
|
|
|
|
}
|
|
|
|
if (vn)
|
|
|
|
vn->vn_next = 0;
|
|
|
|
verneed_section->sh_info = nb_entries;
|
2019-10-22 22:55:20 +08:00
|
|
|
}
|
2019-11-26 04:06:07 +08:00
|
|
|
dt_verneednum = nb_entries;
|
2019-10-22 22:55:20 +08:00
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2019-10-22 22:55:20 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* add an elf symbol : check if it is already defined and patch
|
|
|
|
it. Return symbol index. NOTE that sh_num can be SHN_UNDEF. */
|
2016-11-12 23:16:04 +08:00
|
|
|
ST_FUNC int set_elf_sym(Section *s, addr_t value, unsigned long size,
|
|
|
|
int info, int other, int shndx, const char *name)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
TCCState *s1 = s->s1;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *esym;
|
2002-08-18 21:17:59 +08:00
|
|
|
int sym_bind, sym_index, sym_type, esym_bind;
|
2007-11-22 01:16:31 +08:00
|
|
|
unsigned char sym_vis, esym_vis, new_vis;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2008-11-30 07:14:07 +08:00
|
|
|
sym_bind = ELFW(ST_BIND)(info);
|
|
|
|
sym_type = ELFW(ST_TYPE)(info);
|
|
|
|
sym_vis = ELFW(ST_VISIBILITY)(other);
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
if (sym_bind != STB_LOCAL) {
|
|
|
|
/* we search global or weak symbols */
|
2017-12-13 00:33:37 +08:00
|
|
|
sym_index = find_elf_sym(s, name);
|
2002-08-18 21:17:59 +08:00
|
|
|
if (!sym_index)
|
|
|
|
goto do_def;
|
2017-12-13 00:33:37 +08:00
|
|
|
esym = &((ElfW(Sym) *)s->data)[sym_index];
|
|
|
|
if (esym->st_value == value && esym->st_size == size && esym->st_info == info
|
|
|
|
&& esym->st_other == other && esym->st_shndx == shndx)
|
|
|
|
return sym_index;
|
2002-08-18 21:17:59 +08:00
|
|
|
if (esym->st_shndx != SHN_UNDEF) {
|
2008-11-30 07:14:07 +08:00
|
|
|
esym_bind = ELFW(ST_BIND)(esym->st_info);
|
2007-11-22 01:16:31 +08:00
|
|
|
/* propagate the most constraining visibility */
|
|
|
|
/* STV_DEFAULT(0)<STV_PROTECTED(3)<STV_HIDDEN(2)<STV_INTERNAL(1) */
|
2008-11-30 07:14:07 +08:00
|
|
|
esym_vis = ELFW(ST_VISIBILITY)(esym->st_other);
|
2007-11-22 01:16:31 +08:00
|
|
|
if (esym_vis == STV_DEFAULT) {
|
|
|
|
new_vis = sym_vis;
|
|
|
|
} else if (sym_vis == STV_DEFAULT) {
|
|
|
|
new_vis = esym_vis;
|
|
|
|
} else {
|
|
|
|
new_vis = (esym_vis < sym_vis) ? esym_vis : sym_vis;
|
|
|
|
}
|
2008-11-30 07:14:07 +08:00
|
|
|
esym->st_other = (esym->st_other & ~ELFW(ST_VISIBILITY)(-1))
|
2007-11-22 01:16:31 +08:00
|
|
|
| new_vis;
|
|
|
|
other = esym->st_other; /* in case we have to patch esym */
|
2016-11-12 23:16:04 +08:00
|
|
|
if (shndx == SHN_UNDEF) {
|
2002-08-18 21:17:59 +08:00
|
|
|
/* ignore adding of undefined symbol if the
|
|
|
|
corresponding symbol is already defined */
|
|
|
|
} else if (sym_bind == STB_GLOBAL && esym_bind == STB_WEAK) {
|
|
|
|
/* global overrides weak, so patch */
|
|
|
|
goto do_patch;
|
|
|
|
} else if (sym_bind == STB_WEAK && esym_bind == STB_GLOBAL) {
|
|
|
|
/* weak is ignored if already global */
|
2011-03-08 04:18:54 +08:00
|
|
|
} else if (sym_bind == STB_WEAK && esym_bind == STB_WEAK) {
|
|
|
|
/* keep first-found weak definition, ignore subsequents */
|
2007-11-22 01:16:31 +08:00
|
|
|
} else if (sym_vis == STV_HIDDEN || sym_vis == STV_INTERNAL) {
|
|
|
|
/* ignore hidden symbols after */
|
2016-10-02 03:58:23 +08:00
|
|
|
} else if ((esym->st_shndx == SHN_COMMON
|
|
|
|
|| esym->st_shndx == bss_section->sh_num)
|
2016-11-12 23:16:04 +08:00
|
|
|
&& (shndx < SHN_LORESERVE
|
|
|
|
&& shndx != bss_section->sh_num)) {
|
2016-10-02 03:58:23 +08:00
|
|
|
/* data symbol gets precedence over common/bss */
|
2008-03-09 03:58:57 +08:00
|
|
|
goto do_patch;
|
2016-11-12 23:16:04 +08:00
|
|
|
} else if (shndx == SHN_COMMON || shndx == bss_section->sh_num) {
|
2016-10-02 03:58:23 +08:00
|
|
|
/* data symbol keeps precedence over common/bss */
|
2017-12-13 00:57:20 +08:00
|
|
|
} else if (s->sh_flags & SHF_DYNSYM) {
|
2008-03-09 03:58:57 +08:00
|
|
|
/* we accept that two DLL define the same symbol */
|
2017-11-27 11:03:03 +08:00
|
|
|
} else if (esym->st_other & ST_ASM_SET) {
|
|
|
|
/* If the existing symbol came from an asm .set
|
|
|
|
we can override. */
|
|
|
|
goto do_patch;
|
2002-08-18 21:17:59 +08:00
|
|
|
} else {
|
2013-02-13 02:13:28 +08:00
|
|
|
#if 0
|
2008-03-09 03:58:57 +08:00
|
|
|
printf("new_bind=%x new_shndx=%x new_vis=%x old_bind=%x old_shndx=%x old_vis=%x\n",
|
2016-11-12 23:16:04 +08:00
|
|
|
sym_bind, shndx, new_vis, esym_bind, esym->st_shndx, esym_vis);
|
2002-08-18 21:17:59 +08:00
|
|
|
#endif
|
2016-10-02 03:58:23 +08:00
|
|
|
tcc_error_noabort("'%s' defined twice", name);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
do_patch:
|
2008-11-30 07:14:07 +08:00
|
|
|
esym->st_info = ELFW(ST_INFO)(sym_bind, sym_type);
|
2016-11-12 23:16:04 +08:00
|
|
|
esym->st_shndx = shndx;
|
2019-12-11 07:37:18 +08:00
|
|
|
s1->new_undef_sym = 1;
|
2002-08-18 21:17:59 +08:00
|
|
|
esym->st_value = value;
|
|
|
|
esym->st_size = size;
|
2005-04-14 05:37:06 +08:00
|
|
|
esym->st_other = other;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
do_def:
|
2013-12-17 20:59:14 +08:00
|
|
|
sym_index = put_elf_sym(s, value, size,
|
|
|
|
ELFW(ST_INFO)(sym_bind, sym_type), other,
|
2016-11-12 23:16:04 +08:00
|
|
|
shndx, name);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
return sym_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* put relocation */
|
2015-02-22 05:29:03 +08:00
|
|
|
ST_FUNC void put_elf_reloca(Section *symtab, Section *s, unsigned long offset,
|
2015-03-24 00:24:55 +08:00
|
|
|
int type, int symbol, addr_t addend)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
TCCState *s1 = s->s1;
|
2002-08-18 21:17:59 +08:00
|
|
|
char buf[256];
|
|
|
|
Section *sr;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW_Rel *rel;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
sr = s->reloc;
|
|
|
|
if (!sr) {
|
|
|
|
/* if no relocation section, create it */
|
2008-12-01 01:52:08 +08:00
|
|
|
snprintf(buf, sizeof(buf), REL_SECTION_FMT, s->name);
|
2002-08-18 21:17:59 +08:00
|
|
|
/* if the symtab is allocated, then we consider the relocation
|
|
|
|
are also */
|
2019-12-11 07:37:18 +08:00
|
|
|
sr = new_section(s->s1, buf, SHT_RELX, symtab->sh_flags);
|
2008-11-30 07:14:07 +08:00
|
|
|
sr->sh_entsize = sizeof(ElfW_Rel);
|
2002-08-18 21:17:59 +08:00
|
|
|
sr->link = symtab;
|
|
|
|
sr->sh_info = s->sh_num;
|
|
|
|
s->reloc = sr;
|
|
|
|
}
|
2008-11-30 07:14:07 +08:00
|
|
|
rel = section_ptr_add(sr, sizeof(ElfW_Rel));
|
2002-08-18 21:17:59 +08:00
|
|
|
rel->r_offset = offset;
|
2008-11-30 07:14:07 +08:00
|
|
|
rel->r_info = ELFW(R_INFO)(symbol, type);
|
2016-12-16 00:01:22 +08:00
|
|
|
#if SHT_RELX == SHT_RELA
|
2015-02-22 05:29:03 +08:00
|
|
|
rel->r_addend = addend;
|
2008-12-02 02:19:25 +08:00
|
|
|
#endif
|
2019-12-11 07:37:18 +08:00
|
|
|
if (SHT_RELX != SHT_RELA && addend)
|
|
|
|
tcc_error("non-zero addend on REL architecture");
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2015-02-22 05:29:03 +08:00
|
|
|
ST_FUNC void put_elf_reloc(Section *symtab, Section *s, unsigned long offset,
|
|
|
|
int type, int symbol)
|
|
|
|
{
|
|
|
|
put_elf_reloca(symtab, s, offset, type, symbol, 0);
|
|
|
|
}
|
|
|
|
|
2016-10-08 08:44:17 +08:00
|
|
|
/* Remove relocations for section S->reloc starting at oldrelocoffset
|
|
|
|
that are to the same place, retaining the last of them. As side effect
|
|
|
|
the relocations are sorted. Possibly reduces the number of relocs. */
|
|
|
|
ST_FUNC void squeeze_multi_relocs(Section *s, size_t oldrelocoffset)
|
|
|
|
{
|
|
|
|
Section *sr = s->reloc;
|
|
|
|
ElfW_Rel *r, *dest;
|
|
|
|
ssize_t a;
|
|
|
|
ElfW(Addr) addr;
|
|
|
|
|
|
|
|
if (oldrelocoffset + sizeof(*r) >= sr->data_offset)
|
|
|
|
return;
|
|
|
|
/* The relocs we're dealing with are the result of initializer parsing.
|
|
|
|
So they will be mostly in order and there aren't many of them.
|
|
|
|
Secondly we need a stable sort (which qsort isn't). We use
|
|
|
|
a simple insertion sort. */
|
|
|
|
for (a = oldrelocoffset + sizeof(*r); a < sr->data_offset; a += sizeof(*r)) {
|
|
|
|
ssize_t i = a - sizeof(*r);
|
|
|
|
addr = ((ElfW_Rel*)(sr->data + a))->r_offset;
|
|
|
|
for (; i >= (ssize_t)oldrelocoffset &&
|
|
|
|
((ElfW_Rel*)(sr->data + i))->r_offset > addr; i -= sizeof(*r)) {
|
|
|
|
ElfW_Rel tmp = *(ElfW_Rel*)(sr->data + a);
|
|
|
|
*(ElfW_Rel*)(sr->data + a) = *(ElfW_Rel*)(sr->data + i);
|
|
|
|
*(ElfW_Rel*)(sr->data + i) = tmp;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
r = (ElfW_Rel*)(sr->data + oldrelocoffset);
|
|
|
|
dest = r;
|
|
|
|
for (; r < (ElfW_Rel*)(sr->data + sr->data_offset); r++) {
|
|
|
|
if (dest->r_offset != r->r_offset)
|
|
|
|
dest++;
|
|
|
|
*dest = *r;
|
|
|
|
}
|
|
|
|
sr->data_offset = (unsigned char*)dest - sr->data + sizeof(*r);
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* put stab debug information */
|
|
|
|
|
2019-12-11 07:37:18 +08:00
|
|
|
ST_FUNC void put_stabs(TCCState *s1, const char *str, int type, int other, int desc,
|
2002-08-18 21:17:59 +08:00
|
|
|
unsigned long value)
|
|
|
|
{
|
|
|
|
Stab_Sym *sym;
|
|
|
|
|
2020-01-18 05:58:39 +08:00
|
|
|
unsigned offset;
|
|
|
|
if (type == N_SLINE
|
|
|
|
&& (offset = stab_section->data_offset)
|
|
|
|
&& (sym = (Stab_Sym*)(stab_section->data + offset) - 1)
|
|
|
|
&& sym->n_type == type
|
|
|
|
&& sym->n_value == value) {
|
|
|
|
/* just update line_number in previous entry */
|
|
|
|
sym->n_desc = desc;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
sym = section_ptr_add(stab_section, sizeof(Stab_Sym));
|
|
|
|
if (str) {
|
2019-12-11 07:37:18 +08:00
|
|
|
sym->n_strx = put_elf_str(stab_section->link, str);
|
2002-08-18 21:17:59 +08:00
|
|
|
} else {
|
|
|
|
sym->n_strx = 0;
|
|
|
|
}
|
|
|
|
sym->n_type = type;
|
|
|
|
sym->n_other = other;
|
|
|
|
sym->n_desc = desc;
|
|
|
|
sym->n_value = value;
|
|
|
|
}
|
|
|
|
|
2019-12-11 07:37:18 +08:00
|
|
|
ST_FUNC void put_stabs_r(TCCState *s1, const char *str, int type, int other, int desc,
|
2002-08-18 21:17:59 +08:00
|
|
|
unsigned long value, Section *sec, int sym_index)
|
|
|
|
{
|
2013-12-17 20:59:14 +08:00
|
|
|
put_elf_reloc(symtab_section, stab_section,
|
2020-01-18 05:58:39 +08:00
|
|
|
stab_section->data_offset + 8,
|
|
|
|
sizeof ((Stab_Sym*)0)->n_value == PTR_SIZE ? R_DATA_PTR : R_DATA_32,
|
|
|
|
sym_index);
|
|
|
|
put_stabs(s1, str, type, other, desc, value);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2019-12-11 07:37:18 +08:00
|
|
|
ST_FUNC void put_stabn(TCCState *s1, int type, int other, int desc, int value)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
put_stabs(s1, NULL, type, other, desc, value);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2016-12-16 00:01:22 +08:00
|
|
|
ST_FUNC struct sym_attr *get_sym_attr(TCCState *s1, int index, int alloc)
|
2016-11-12 23:16:07 +08:00
|
|
|
{
|
|
|
|
int n;
|
|
|
|
struct sym_attr *tab;
|
|
|
|
|
|
|
|
if (index >= s1->nb_sym_attrs) {
|
|
|
|
if (!alloc)
|
2016-12-16 00:01:22 +08:00
|
|
|
return s1->sym_attrs;
|
2016-11-12 23:16:07 +08:00
|
|
|
/* find immediately bigger power of 2 and reallocate array */
|
|
|
|
n = 1;
|
|
|
|
while (index >= n)
|
|
|
|
n *= 2;
|
|
|
|
tab = tcc_realloc(s1->sym_attrs, n * sizeof(*s1->sym_attrs));
|
|
|
|
s1->sym_attrs = tab;
|
|
|
|
memset(s1->sym_attrs + s1->nb_sym_attrs, 0,
|
|
|
|
(n - s1->nb_sym_attrs) * sizeof(*s1->sym_attrs));
|
|
|
|
s1->nb_sym_attrs = n;
|
|
|
|
}
|
|
|
|
return &s1->sym_attrs[index];
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* In an ELF file symbol table, the local symbols must appear below
|
|
|
|
the global and weak ones. Since TCC cannot sort it while generating
|
|
|
|
the code, we must do it after. All the relocation tables are also
|
|
|
|
modified to take into account the symbol table sorting */
|
2002-11-02 22:13:21 +08:00
|
|
|
static void sort_syms(TCCState *s1, Section *s)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
int *old_to_new_syms;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *new_syms;
|
2002-08-18 21:17:59 +08:00
|
|
|
int nb_syms, i;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *p, *q;
|
2013-12-17 21:02:51 +08:00
|
|
|
ElfW_Rel *rel;
|
2002-08-18 21:17:59 +08:00
|
|
|
Section *sr;
|
|
|
|
int type, sym_index;
|
|
|
|
|
2008-11-30 07:14:07 +08:00
|
|
|
nb_syms = s->data_offset / sizeof(ElfW(Sym));
|
|
|
|
new_syms = tcc_malloc(nb_syms * sizeof(ElfW(Sym)));
|
2002-08-18 21:17:59 +08:00
|
|
|
old_to_new_syms = tcc_malloc(nb_syms * sizeof(int));
|
|
|
|
|
|
|
|
/* first pass for local symbols */
|
2008-11-30 07:14:07 +08:00
|
|
|
p = (ElfW(Sym) *)s->data;
|
2002-08-18 21:17:59 +08:00
|
|
|
q = new_syms;
|
|
|
|
for(i = 0; i < nb_syms; i++) {
|
2008-11-30 07:14:07 +08:00
|
|
|
if (ELFW(ST_BIND)(p->st_info) == STB_LOCAL) {
|
2002-08-18 21:17:59 +08:00
|
|
|
old_to_new_syms[i] = q - new_syms;
|
|
|
|
*q++ = *p;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
/* save the number of local symbols in section header */
|
2017-06-10 02:44:29 +08:00
|
|
|
if( s->sh_size ) /* this 'if' makes IDA happy */
|
|
|
|
s->sh_info = q - new_syms;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* then second pass for non local symbols */
|
2008-11-30 07:14:07 +08:00
|
|
|
p = (ElfW(Sym) *)s->data;
|
2002-08-18 21:17:59 +08:00
|
|
|
for(i = 0; i < nb_syms; i++) {
|
2008-11-30 07:14:07 +08:00
|
|
|
if (ELFW(ST_BIND)(p->st_info) != STB_LOCAL) {
|
2002-08-18 21:17:59 +08:00
|
|
|
old_to_new_syms[i] = q - new_syms;
|
|
|
|
*q++ = *p;
|
|
|
|
}
|
|
|
|
p++;
|
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* we copy the new symbols to the old */
|
2008-11-30 07:14:07 +08:00
|
|
|
memcpy(s->data, new_syms, nb_syms * sizeof(ElfW(Sym)));
|
2002-08-18 21:17:59 +08:00
|
|
|
tcc_free(new_syms);
|
|
|
|
|
|
|
|
/* now we modify all the relocations */
|
2002-11-02 22:13:21 +08:00
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
sr = s1->sections[i];
|
2008-11-30 07:14:07 +08:00
|
|
|
if (sr->sh_type == SHT_RELX && sr->link == s) {
|
2013-12-17 21:02:51 +08:00
|
|
|
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
2008-11-30 07:14:07 +08:00
|
|
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
|
|
|
type = ELFW(R_TYPE)(rel->r_info);
|
2002-08-18 21:17:59 +08:00
|
|
|
sym_index = old_to_new_syms[sym_index];
|
2008-11-30 07:14:07 +08:00
|
|
|
rel->r_info = ELFW(R_INFO)(sym_index, type);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
tcc_free(old_to_new_syms);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* relocate symbol table, resolve undefined symbols if do_resolve is
|
|
|
|
true and output error if undefined symbol. */
|
2016-11-12 23:16:09 +08:00
|
|
|
ST_FUNC void relocate_syms(TCCState *s1, Section *symtab, int do_resolve)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2016-11-12 23:16:08 +08:00
|
|
|
ElfW(Sym) *sym;
|
|
|
|
int sym_bind, sh_num;
|
2002-08-18 21:17:59 +08:00
|
|
|
const char *name;
|
|
|
|
|
2016-11-12 23:16:09 +08:00
|
|
|
for_each_elem(symtab, 1, sym, ElfW(Sym)) {
|
2002-08-18 21:17:59 +08:00
|
|
|
sh_num = sym->st_shndx;
|
|
|
|
if (sh_num == SHN_UNDEF) {
|
2017-12-13 00:57:20 +08:00
|
|
|
name = (char *) s1->symtab->link->data + sym->st_name;
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Use ld.so to resolve symbol for us (for tcc -run) */
|
2002-08-18 21:17:59 +08:00
|
|
|
if (do_resolve) {
|
2016-10-18 05:24:01 +08:00
|
|
|
#if defined TCC_IS_NATIVE && !defined TCC_TARGET_PE
|
2020-05-18 11:15:08 +08:00
|
|
|
#ifdef TCC_TARGET_MACHO
|
|
|
|
/* The symbols in the symtables have a prepended '_'
|
|
|
|
but dlsym() needs the undecorated name. */
|
|
|
|
void *addr = dlsym(RTLD_DEFAULT, name + 1);
|
|
|
|
#else
|
2016-11-12 23:16:09 +08:00
|
|
|
void *addr = dlsym(RTLD_DEFAULT, name);
|
2020-05-18 11:15:08 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
if (addr) {
|
2016-11-12 23:16:09 +08:00
|
|
|
sym->st_value = (addr_t) addr;
|
2014-04-06 07:02:42 +08:00
|
|
|
#ifdef DEBUG_RELOC
|
2015-07-30 04:53:57 +08:00
|
|
|
printf ("relocate_sym: %s -> 0x%lx\n", name, sym->st_value);
|
2014-04-06 07:02:42 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
goto found;
|
|
|
|
}
|
2009-07-07 03:34:22 +08:00
|
|
|
#endif
|
2016-11-12 23:16:08 +08:00
|
|
|
/* if dynamic symbol exist, it will be used in relocate_section */
|
|
|
|
} else if (s1->dynsym && find_elf_sym(s1->dynsym, name))
|
|
|
|
goto found;
|
2002-08-18 21:17:59 +08:00
|
|
|
/* XXX: _fp_hw seems to be part of the ABI, so we ignore
|
|
|
|
it */
|
|
|
|
if (!strcmp(name, "_fp_hw"))
|
|
|
|
goto found;
|
|
|
|
/* only weak symbols are accepted to be undefined. Their
|
|
|
|
value is zero */
|
2008-11-30 07:14:07 +08:00
|
|
|
sym_bind = ELFW(ST_BIND)(sym->st_info);
|
2016-11-12 23:16:09 +08:00
|
|
|
if (sym_bind == STB_WEAK)
|
2002-08-18 21:17:59 +08:00
|
|
|
sym->st_value = 0;
|
2016-11-12 23:16:09 +08:00
|
|
|
else
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("undefined symbol '%s'", name);
|
2002-08-18 21:17:59 +08:00
|
|
|
} else if (sh_num < SHN_LORESERVE) {
|
|
|
|
/* add section base */
|
2002-11-02 22:13:21 +08:00
|
|
|
sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
found: ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* relocate a given section (CPU dependent) by applying the relocations
|
|
|
|
in the associated relocation section */
|
2009-12-20 08:53:49 +08:00
|
|
|
ST_FUNC void relocate_section(TCCState *s1, Section *s)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2013-12-17 21:02:51 +08:00
|
|
|
Section *sr = s->reloc;
|
|
|
|
ElfW_Rel *rel;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2004-11-07 23:43:15 +08:00
|
|
|
int type, sym_index;
|
2002-08-18 21:17:59 +08:00
|
|
|
unsigned char *ptr;
|
2016-11-12 23:16:08 +08:00
|
|
|
addr_t tgt, addr;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
qrel = (ElfW_Rel *)sr->data;
|
2016-12-16 00:01:22 +08:00
|
|
|
|
2013-12-17 21:02:51 +08:00
|
|
|
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
2002-08-18 21:17:59 +08:00
|
|
|
ptr = s->data + rel->r_offset;
|
2008-11-30 07:14:07 +08:00
|
|
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
|
|
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
2016-11-12 23:16:08 +08:00
|
|
|
type = ELFW(R_TYPE)(rel->r_info);
|
|
|
|
tgt = sym->st_value;
|
2016-12-16 00:01:22 +08:00
|
|
|
#if SHT_RELX == SHT_RELA
|
2016-11-12 23:16:08 +08:00
|
|
|
tgt += rel->r_addend;
|
2008-12-02 02:19:25 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
addr = s->sh_addr + rel->r_offset;
|
2017-03-28 14:51:39 +08:00
|
|
|
relocate(s1, rel, type, ptr, addr, tgt);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
/* if the relocation is allocated, we change its symbol table */
|
2020-01-18 05:58:39 +08:00
|
|
|
if (sr->sh_flags & SHF_ALLOC) {
|
2002-11-02 22:13:21 +08:00
|
|
|
sr->link = s1->dynsym;
|
2020-01-18 05:58:39 +08:00
|
|
|
if (s1->output_type == TCC_OUTPUT_DLL) {
|
|
|
|
size_t r = (uint8_t*)qrel - sr->data;
|
|
|
|
if (sizeof ((Stab_Sym*)0)->n_value < PTR_SIZE
|
|
|
|
&& 0 == strcmp(s->name, ".stab"))
|
|
|
|
r = 0; /* cannot apply 64bit relocation to 32bit value */
|
|
|
|
sr->data_offset = sr->sh_size = r;
|
|
|
|
}
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2002-08-18 21:17:59 +08:00
|
|
|
/* relocate relocation table in 'sr' */
|
2002-11-02 22:13:21 +08:00
|
|
|
static void relocate_rel(TCCState *s1, Section *sr)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
Section *s;
|
2013-12-17 21:02:51 +08:00
|
|
|
ElfW_Rel *rel;
|
|
|
|
|
2002-11-02 22:13:21 +08:00
|
|
|
s = s1->sections[sr->sh_info];
|
2013-12-17 21:02:51 +08:00
|
|
|
for_each_elem(sr, 0, rel, ElfW_Rel)
|
2002-08-18 21:17:59 +08:00
|
|
|
rel->r_offset += s->sh_addr;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* count the number of dynamic relocations so that we can reserve
|
|
|
|
their space */
|
2002-11-02 22:13:21 +08:00
|
|
|
static int prepare_dynamic_rel(TCCState *s1, Section *sr)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2018-06-08 21:31:40 +08:00
|
|
|
int count = 0;
|
2020-08-04 15:15:42 +08:00
|
|
|
#if defined(TCC_TARGET_I386) || defined(TCC_TARGET_X86_64) || \
|
2020-08-04 16:36:47 +08:00
|
|
|
defined(TCC_TARGET_ARM) || defined(TCC_TARGET_ARM64) || \
|
|
|
|
defined(TCC_TARGET_RISCV64)
|
2013-12-17 21:02:51 +08:00
|
|
|
ElfW_Rel *rel;
|
|
|
|
for_each_elem(sr, 0, rel, ElfW_Rel) {
|
2018-12-18 00:05:05 +08:00
|
|
|
int sym_index = ELFW(R_SYM)(rel->r_info);
|
2018-06-08 21:31:40 +08:00
|
|
|
int type = ELFW(R_TYPE)(rel->r_info);
|
2002-08-18 21:17:59 +08:00
|
|
|
switch(type) {
|
2009-03-21 11:04:35 +08:00
|
|
|
#if defined(TCC_TARGET_I386)
|
2002-08-18 21:17:59 +08:00
|
|
|
case R_386_32:
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (!get_sym_attr(s1, sym_index, 0)->dyn_index
|
|
|
|
&& ((ElfW(Sym)*)symtab_section->data + sym_index)->st_shndx == SHN_UNDEF) {
|
|
|
|
/* don't fixup unresolved (weak) symbols */
|
|
|
|
rel->r_info = ELFW(R_INFO)(sym_index, R_386_RELATIVE);
|
|
|
|
break;
|
|
|
|
}
|
2009-03-21 11:04:35 +08:00
|
|
|
#elif defined(TCC_TARGET_X86_64)
|
|
|
|
case R_X86_64_32:
|
|
|
|
case R_X86_64_32S:
|
2009-04-05 01:07:19 +08:00
|
|
|
case R_X86_64_64:
|
2020-08-04 15:15:42 +08:00
|
|
|
#elif defined(TCC_TARGET_ARM)
|
|
|
|
case R_ARM_ABS32:
|
2020-08-02 01:44:49 +08:00
|
|
|
#elif defined(TCC_TARGET_ARM64)
|
|
|
|
case R_AARCH64_ABS32:
|
|
|
|
case R_AARCH64_ABS64:
|
2020-08-04 16:36:47 +08:00
|
|
|
#elif defined(TCC_TARGET_RISCV64)
|
|
|
|
case R_RISCV_32:
|
|
|
|
case R_RISCV_64:
|
2009-03-21 11:04:35 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
count++;
|
|
|
|
break;
|
2009-03-21 11:04:35 +08:00
|
|
|
#if defined(TCC_TARGET_I386)
|
2002-08-18 21:17:59 +08:00
|
|
|
case R_386_PC32:
|
2009-03-21 11:04:35 +08:00
|
|
|
#elif defined(TCC_TARGET_X86_64)
|
|
|
|
case R_X86_64_PC32:
|
2020-08-02 01:44:49 +08:00
|
|
|
#elif defined(TCC_TARGET_ARM64)
|
|
|
|
case R_AARCH64_PREL32:
|
2009-03-21 11:04:35 +08:00
|
|
|
#endif
|
2016-12-16 00:01:22 +08:00
|
|
|
if (get_sym_attr(s1, sym_index, 0)->dyn_index)
|
2002-08-18 21:17:59 +08:00
|
|
|
count++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (count) {
|
|
|
|
/* allocate the section */
|
|
|
|
sr->sh_flags |= SHF_ALLOC;
|
2008-11-30 07:14:07 +08:00
|
|
|
sr->sh_size = count * sizeof(ElfW_Rel);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2018-06-08 21:31:40 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
return count;
|
|
|
|
}
|
2020-05-09 07:40:36 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2020-06-27 23:15:06 +08:00
|
|
|
#if !defined(ELF_OBJ_ONLY) || (defined(TCC_TARGET_MACHO) && defined TCC_IS_NATIVE)
|
2002-11-02 22:13:21 +08:00
|
|
|
static void build_got(TCCState *s1)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
/* if no got, then create it */
|
2002-11-02 22:13:21 +08:00
|
|
|
s1->got = new_section(s1, ".got", SHT_PROGBITS, SHF_ALLOC | SHF_WRITE);
|
|
|
|
s1->got->sh_entsize = 4;
|
2016-11-12 23:16:04 +08:00
|
|
|
set_elf_sym(symtab_section, 0, 4, ELFW(ST_INFO)(STB_GLOBAL, STT_OBJECT),
|
2005-04-14 05:37:06 +08:00
|
|
|
0, s1->got->sh_num, "_GLOBAL_OFFSET_TABLE_");
|
2016-12-16 00:01:22 +08:00
|
|
|
/* keep space for _DYNAMIC pointer and two dummy got entries */
|
|
|
|
section_ptr_add(s1->got, 3 * PTR_SIZE);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2016-11-12 23:16:05 +08:00
|
|
|
/* Create a GOT and (for function call) a PLT entry corresponding to a symbol
|
|
|
|
in s1->symtab. When creating the dynamic symbol table entry for the GOT
|
|
|
|
relocation, use 'size' and 'info' for the corresponding symbol metadata.
|
|
|
|
Returns the offset of the GOT or (if any) PLT entry. */
|
2016-12-16 00:01:22 +08:00
|
|
|
static struct sym_attr * put_got_entry(TCCState *s1, int dyn_reloc_type,
|
2019-06-17 04:06:07 +08:00
|
|
|
int sym_index)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2016-12-16 00:01:22 +08:00
|
|
|
int need_plt_entry;
|
2002-08-18 21:17:59 +08:00
|
|
|
const char *name;
|
2016-12-16 00:01:22 +08:00
|
|
|
ElfW(Sym) *sym;
|
|
|
|
struct sym_attr *attr;
|
|
|
|
unsigned got_offset;
|
|
|
|
char plt_name[100];
|
|
|
|
int len;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2016-11-18 07:00:11 +08:00
|
|
|
need_plt_entry = (dyn_reloc_type == R_JMP_SLOT);
|
2016-12-16 00:01:22 +08:00
|
|
|
attr = get_sym_attr(s1, sym_index, 1);
|
2016-11-12 23:16:05 +08:00
|
|
|
|
|
|
|
/* In case a function is both called and its address taken 2 GOT entries
|
|
|
|
are created, one for taking the address (GOT) and the other for the PLT
|
2016-12-16 00:01:22 +08:00
|
|
|
entry (PLTGOT). */
|
|
|
|
if (need_plt_entry ? attr->plt_offset : attr->got_offset)
|
|
|
|
return attr;
|
2016-11-12 23:16:05 +08:00
|
|
|
|
2016-12-16 00:01:22 +08:00
|
|
|
/* create the GOT entry */
|
|
|
|
got_offset = s1->got->data_offset;
|
|
|
|
section_ptr_add(s1->got, PTR_SIZE);
|
2016-11-12 23:16:05 +08:00
|
|
|
|
|
|
|
/* Create the GOT relocation that will insert the address of the object or
|
|
|
|
function of interest in the GOT entry. This is a static relocation for
|
|
|
|
memory output (dlsym will give us the address of symbols) and dynamic
|
|
|
|
relocation otherwise (executable and DLLs). The relocation should be
|
|
|
|
done lazily for GOT entry with *_JUMP_SLOT relocation type (the one
|
|
|
|
associated to a PLT entry) but is currently done at load time for an
|
|
|
|
unknown reason. */
|
2016-12-16 00:01:22 +08:00
|
|
|
|
|
|
|
sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
|
|
|
|
name = (char *) symtab_section->link->data + sym->st_name;
|
|
|
|
|
2014-04-06 06:30:22 +08:00
|
|
|
if (s1->dynsym) {
|
2017-05-07 10:52:21 +08:00
|
|
|
if (ELFW(ST_BIND)(sym->st_info) == STB_LOCAL) {
|
|
|
|
/* Hack alarm. We don't want to emit dynamic symbols
|
|
|
|
and symbol based relocs for STB_LOCAL symbols, but rather
|
|
|
|
want to resolve them directly. At this point the symbol
|
|
|
|
values aren't final yet, so we must defer this. We will later
|
|
|
|
have to create a RELATIVE reloc anyway, so we misuse the
|
|
|
|
relocation slot to smuggle the symbol reference until
|
|
|
|
fill_local_got_entries. Not that the sym_index is
|
|
|
|
relative to symtab_section, not s1->dynsym! Nevertheless
|
|
|
|
we use s1->dyn_sym so that if this is the first call
|
|
|
|
that got->reloc is correctly created. Also note that
|
|
|
|
RELATIVE relocs are not normally created for the .got,
|
|
|
|
so the types serves as a marker for later (and is retained
|
|
|
|
also for the final output, which is okay because then the
|
|
|
|
got is just normal data). */
|
|
|
|
put_elf_reloc(s1->dynsym, s1->got, got_offset, R_RELATIVE,
|
|
|
|
sym_index);
|
|
|
|
} else {
|
|
|
|
if (0 == attr->dyn_index)
|
2019-06-17 04:06:07 +08:00
|
|
|
attr->dyn_index = set_elf_sym(s1->dynsym, sym->st_value,
|
|
|
|
sym->st_size, sym->st_info, 0,
|
|
|
|
sym->st_shndx, name);
|
2017-05-07 10:52:21 +08:00
|
|
|
put_elf_reloc(s1->dynsym, s1->got, got_offset, dyn_reloc_type,
|
|
|
|
attr->dyn_index);
|
|
|
|
}
|
2016-12-16 00:01:22 +08:00
|
|
|
} else {
|
|
|
|
put_elf_reloc(symtab_section, s1->got, got_offset, dyn_reloc_type,
|
2016-11-12 23:16:05 +08:00
|
|
|
sym_index);
|
2016-12-16 00:01:22 +08:00
|
|
|
}
|
2016-11-12 23:16:05 +08:00
|
|
|
|
2016-12-16 00:01:22 +08:00
|
|
|
if (need_plt_entry) {
|
|
|
|
if (!s1->plt) {
|
|
|
|
s1->plt = new_section(s1, ".plt", SHT_PROGBITS,
|
|
|
|
SHF_ALLOC | SHF_EXECINSTR);
|
|
|
|
s1->plt->sh_entsize = 4;
|
|
|
|
}
|
|
|
|
|
|
|
|
attr->plt_offset = create_plt_entry(s1, got_offset, attr);
|
|
|
|
|
|
|
|
/* create a symbol 'sym@plt' for the PLT jump vector */
|
|
|
|
len = strlen(name);
|
|
|
|
if (len > sizeof plt_name - 5)
|
|
|
|
len = sizeof plt_name - 5;
|
|
|
|
memcpy(plt_name, name, len);
|
|
|
|
strcpy(plt_name + len, "@plt");
|
|
|
|
attr->plt_sym = put_elf_sym(s1->symtab, attr->plt_offset, sym->st_size,
|
|
|
|
ELFW(ST_INFO)(STB_GLOBAL, STT_FUNC), 0, s1->plt->sh_num, plt_name);
|
|
|
|
|
|
|
|
} else {
|
|
|
|
attr->got_offset = got_offset;
|
|
|
|
}
|
|
|
|
|
|
|
|
return attr;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* build GOT and PLT entries */
|
2009-12-20 08:53:49 +08:00
|
|
|
ST_FUNC void build_got_entries(TCCState *s1)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2011-05-16 20:15:32 +08:00
|
|
|
Section *s;
|
2013-12-17 21:02:51 +08:00
|
|
|
ElfW_Rel *rel;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2016-12-11 01:22:08 +08:00
|
|
|
int i, type, gotplt_entry, reloc_type, sym_index;
|
2016-12-16 00:01:22 +08:00
|
|
|
struct sym_attr *attr;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2002-11-02 22:13:21 +08:00
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
2008-11-30 07:14:07 +08:00
|
|
|
if (s->sh_type != SHT_RELX)
|
2002-08-18 21:17:59 +08:00
|
|
|
continue;
|
|
|
|
/* no need to handle got relocations */
|
|
|
|
if (s->link != symtab_section)
|
|
|
|
continue;
|
2013-12-17 21:02:51 +08:00
|
|
|
for_each_elem(s, 0, rel, ElfW_Rel) {
|
2008-11-30 07:14:07 +08:00
|
|
|
type = ELFW(R_TYPE)(rel->r_info);
|
2016-12-11 01:22:08 +08:00
|
|
|
gotplt_entry = gotplt_entry_type(type);
|
2019-12-11 07:37:18 +08:00
|
|
|
if (gotplt_entry == -1)
|
|
|
|
tcc_error ("Unknown relocation type for got: %d", type);
|
2016-11-18 06:54:06 +08:00
|
|
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
|
|
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
2016-12-06 04:58:00 +08:00
|
|
|
|
2016-12-16 00:01:22 +08:00
|
|
|
if (gotplt_entry == NO_GOTPLT_ENTRY) {
|
2016-11-12 23:16:07 +08:00
|
|
|
continue;
|
2016-12-16 00:01:22 +08:00
|
|
|
}
|
2016-11-12 23:16:07 +08:00
|
|
|
|
2016-12-18 12:18:19 +08:00
|
|
|
/* Automatically create PLT/GOT [entry] if it is an undefined
|
|
|
|
reference (resolved at runtime), or the symbol is absolute,
|
|
|
|
probably created by tcc_add_symbol, and thus on 64-bit
|
|
|
|
targets might be too far from application code. */
|
2016-12-16 00:01:22 +08:00
|
|
|
if (gotplt_entry == AUTO_GOTPLT_ENTRY) {
|
|
|
|
if (sym->st_shndx == SHN_UNDEF) {
|
2016-12-18 12:18:19 +08:00
|
|
|
ElfW(Sym) *esym;
|
|
|
|
int dynindex;
|
2016-12-16 00:01:22 +08:00
|
|
|
if (s1->output_type == TCC_OUTPUT_DLL && ! PCRELATIVE_DLLPLT)
|
|
|
|
continue;
|
2016-12-18 12:18:19 +08:00
|
|
|
/* Relocations for UNDEF symbols would normally need
|
|
|
|
to be transferred into the executable or shared object.
|
|
|
|
If that were done AUTO_GOTPLT_ENTRY wouldn't exist.
|
|
|
|
But TCC doesn't do that (at least for exes), so we
|
|
|
|
need to resolve all such relocs locally. And that
|
|
|
|
means PLT slots for functions in DLLs and COPY relocs for
|
|
|
|
data symbols. COPY relocs were generated in
|
|
|
|
bind_exe_dynsyms (and the symbol adjusted to be defined),
|
|
|
|
and for functions we were generated a dynamic symbol
|
|
|
|
of function type. */
|
|
|
|
if (s1->dynsym) {
|
|
|
|
/* dynsym isn't set for -run :-/ */
|
|
|
|
dynindex = get_sym_attr(s1, sym_index, 0)->dyn_index;
|
|
|
|
esym = (ElfW(Sym) *)s1->dynsym->data + dynindex;
|
|
|
|
if (dynindex
|
|
|
|
&& (ELFW(ST_TYPE)(esym->st_info) == STT_FUNC
|
|
|
|
|| (ELFW(ST_TYPE)(esym->st_info) == STT_NOTYPE
|
|
|
|
&& ELFW(ST_TYPE)(sym->st_info) == STT_FUNC)))
|
|
|
|
goto jmp_slot;
|
|
|
|
}
|
2017-04-27 20:16:49 +08:00
|
|
|
} else if (!(sym->st_shndx == SHN_ABS
|
|
|
|
#ifndef TCC_TARGET_ARM
|
|
|
|
&& PTR_SIZE == 8
|
|
|
|
#endif
|
|
|
|
))
|
2016-12-16 00:01:22 +08:00
|
|
|
continue;
|
|
|
|
}
|
2016-12-10 17:14:29 +08:00
|
|
|
|
2016-11-12 23:16:07 +08:00
|
|
|
#ifdef TCC_TARGET_X86_64
|
2017-05-07 10:52:21 +08:00
|
|
|
if ((type == R_X86_64_PLT32 || type == R_X86_64_PC32) &&
|
2019-01-13 13:00:51 +08:00
|
|
|
sym->st_shndx != SHN_UNDEF &&
|
2017-05-07 10:52:21 +08:00
|
|
|
(ELFW(ST_VISIBILITY)(sym->st_other) != STV_DEFAULT ||
|
2019-01-13 13:00:51 +08:00
|
|
|
ELFW(ST_BIND)(sym->st_info) == STB_LOCAL ||
|
|
|
|
s1->output_type == TCC_OUTPUT_EXE)) {
|
2016-11-12 23:16:07 +08:00
|
|
|
rel->r_info = ELFW(R_INFO)(sym_index, R_X86_64_PC32);
|
|
|
|
continue;
|
|
|
|
}
|
2014-04-06 07:02:42 +08:00
|
|
|
#endif
|
2019-12-11 07:37:18 +08:00
|
|
|
reloc_type = code_reloc(type);
|
|
|
|
if (reloc_type == -1)
|
|
|
|
tcc_error ("Unknown relocation type: %d", type);
|
|
|
|
else if (reloc_type != 0) {
|
2016-12-16 00:01:22 +08:00
|
|
|
jmp_slot:
|
|
|
|
reloc_type = R_JMP_SLOT;
|
|
|
|
} else
|
|
|
|
reloc_type = R_GLOB_DAT;
|
2016-11-12 23:16:07 +08:00
|
|
|
|
|
|
|
if (!s1->got)
|
|
|
|
build_got(s1);
|
|
|
|
|
2016-12-11 01:22:08 +08:00
|
|
|
if (gotplt_entry == BUILD_GOT_ONLY)
|
2016-11-12 23:16:07 +08:00
|
|
|
continue;
|
|
|
|
|
2019-06-17 04:06:07 +08:00
|
|
|
attr = put_got_entry(s1, reloc_type, sym_index);
|
2016-12-16 00:01:22 +08:00
|
|
|
|
|
|
|
if (reloc_type == R_JMP_SLOT)
|
|
|
|
rel->r_info = ELFW(R_INFO)(attr->plt_sym, type);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2020-06-27 23:15:06 +08:00
|
|
|
ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t offs)
|
2020-01-18 05:58:39 +08:00
|
|
|
{
|
|
|
|
int shn = sec ? sec->sh_num : offs ? SHN_ABS : SHN_UNDEF;
|
|
|
|
if (sec && offs == -1)
|
|
|
|
offs = sec->data_offset;
|
|
|
|
return set_elf_sym(symtab_section, offs, 0,
|
|
|
|
ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
|
|
|
|
}
|
|
|
|
|
2003-05-30 06:52:53 +08:00
|
|
|
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
|
|
|
{
|
|
|
|
Section *s;
|
2020-06-27 23:15:06 +08:00
|
|
|
addr_t end_offset;
|
2020-01-18 05:58:39 +08:00
|
|
|
char buf[1024];
|
2003-05-30 06:52:53 +08:00
|
|
|
s = find_section(s1, section_name);
|
|
|
|
if (!s) {
|
|
|
|
end_offset = 0;
|
|
|
|
s = data_section;
|
|
|
|
} else {
|
|
|
|
end_offset = s->data_offset;
|
|
|
|
}
|
2020-01-18 05:58:39 +08:00
|
|
|
snprintf(buf, sizeof(buf), "__%s_start", section_name + 1);
|
|
|
|
set_global_sym(s1, buf, s, 0);
|
|
|
|
snprintf(buf, sizeof(buf), "__%s_end", section_name + 1);
|
|
|
|
set_global_sym(s1, buf, s, end_offset);
|
2003-05-30 06:52:53 +08:00
|
|
|
}
|
|
|
|
|
2019-11-28 01:29:12 +08:00
|
|
|
#ifndef TCC_TARGET_PE
|
2015-03-26 11:22:37 +08:00
|
|
|
static int tcc_add_support(TCCState *s1, const char *filename)
|
|
|
|
{
|
|
|
|
char buf[1024];
|
2017-02-23 15:41:57 +08:00
|
|
|
snprintf(buf, sizeof(buf), "%s/%s", s1->tcc_lib_path, filename);
|
2016-10-02 02:46:16 +08:00
|
|
|
return tcc_add_file(s1, buf);
|
2015-03-26 11:22:37 +08:00
|
|
|
}
|
2018-06-01 05:51:59 +08:00
|
|
|
#endif
|
2015-03-26 11:22:37 +08:00
|
|
|
|
2020-01-18 05:58:39 +08:00
|
|
|
ST_FUNC void add_array (TCCState *s1, const char *sec, int c)
|
2019-10-29 14:02:58 +08:00
|
|
|
{
|
|
|
|
Section *s;
|
2020-01-18 05:58:39 +08:00
|
|
|
s = find_section(s1, sec);
|
|
|
|
s->sh_flags |= SHF_WRITE;
|
2020-01-15 15:53:19 +08:00
|
|
|
#ifndef TCC_TARGET_PE
|
2020-01-18 05:58:39 +08:00
|
|
|
s->sh_type = sec[1] == 'i' ? SHT_INIT_ARRAY : SHT_FINI_ARRAY;
|
2020-01-15 15:53:19 +08:00
|
|
|
#endif
|
2020-01-18 05:58:39 +08:00
|
|
|
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
|
|
|
|
section_ptr_add(s, PTR_SIZE);
|
2019-10-29 14:02:58 +08:00
|
|
|
}
|
|
|
|
|
2020-01-18 05:58:39 +08:00
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
|
|
|
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
2019-10-29 14:02:58 +08:00
|
|
|
{
|
2020-01-18 05:58:39 +08:00
|
|
|
if (0 == s1->do_bounds_check)
|
|
|
|
return;
|
|
|
|
section_ptr_add(bounds_section, sizeof(addr_t));
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef CONFIG_TCC_BACKTRACE
|
|
|
|
static void put_ptr(TCCState *s1, Section *s, int offs)
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
c = set_global_sym(s1, NULL, s, offs);
|
|
|
|
s = data_section;
|
|
|
|
put_elf_reloc (s1->symtab, s, s->data_offset, R_DATA_PTR, c);
|
|
|
|
section_ptr_add(s, PTR_SIZE);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* set symbol to STB_LOCAL and resolve. The point is to not export it as
|
|
|
|
a dynamic symbol to allow so's to have one each with a different value. */
|
|
|
|
static void set_local_sym(TCCState *s1, const char *name, Section *s, int offset)
|
|
|
|
{
|
|
|
|
int c = find_elf_sym(s1->symtab, name);
|
|
|
|
if (c) {
|
|
|
|
ElfW(Sym) *esym = (ElfW(Sym)*)s1->symtab->data + c;
|
|
|
|
esym->st_info = ELFW(ST_INFO)(STB_LOCAL, STT_NOTYPE);
|
|
|
|
esym->st_value = offset;
|
|
|
|
esym->st_shndx = s->sh_num;
|
|
|
|
}
|
2019-10-29 14:02:58 +08:00
|
|
|
}
|
|
|
|
|
2020-01-18 05:58:39 +08:00
|
|
|
ST_FUNC void tcc_add_btstub(TCCState *s1)
|
2019-10-29 14:02:58 +08:00
|
|
|
{
|
2020-01-18 05:58:39 +08:00
|
|
|
Section *s;
|
2020-01-18 08:22:28 +08:00
|
|
|
int n, o;
|
2020-01-18 05:58:39 +08:00
|
|
|
CString cstr;
|
|
|
|
|
|
|
|
s = data_section;
|
|
|
|
o = s->data_offset;
|
|
|
|
/* create (part of) a struct rt_context (see tccrun.c) */
|
|
|
|
put_ptr(s1, stab_section, 0);
|
|
|
|
put_ptr(s1, stab_section, -1);
|
|
|
|
put_ptr(s1, stab_section->link, 0);
|
|
|
|
section_ptr_add(s, 3 * PTR_SIZE);
|
|
|
|
/* prog_base */
|
2020-05-22 11:06:08 +08:00
|
|
|
#ifndef TCC_TARGET_MACHO
|
|
|
|
/* XXX this relocation is wrong, it uses sym-index 0 (local,undef) */
|
2020-01-18 05:58:39 +08:00
|
|
|
put_elf_reloc(s1->symtab, s, s->data_offset, R_DATA_PTR, 0);
|
2020-05-22 11:06:08 +08:00
|
|
|
#endif
|
2020-01-18 05:58:39 +08:00
|
|
|
section_ptr_add(s, PTR_SIZE);
|
2020-01-18 08:22:28 +08:00
|
|
|
n = 2 * PTR_SIZE;
|
2020-01-18 05:58:39 +08:00
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
|
|
|
if (s1->do_bounds_check) {
|
|
|
|
put_ptr(s1, bounds_section, 0);
|
2020-01-18 08:22:28 +08:00
|
|
|
n -= PTR_SIZE;
|
2020-01-18 05:58:39 +08:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
section_ptr_add(s, n);
|
|
|
|
|
|
|
|
cstr_new(&cstr);
|
|
|
|
cstr_printf(&cstr,
|
|
|
|
" extern void __bt_init(),*__rt_info[],__bt_init_dll();"
|
|
|
|
"__attribute__((constructor)) static void __bt_init_rt(){");
|
|
|
|
#ifdef TCC_TARGET_PE
|
2020-01-18 08:22:28 +08:00
|
|
|
if (s1->output_type == TCC_OUTPUT_DLL)
|
2020-01-19 18:15:12 +08:00
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
2020-01-18 08:22:28 +08:00
|
|
|
cstr_printf(&cstr, "__bt_init_dll(%d);", s1->do_bounds_check);
|
2020-01-19 18:15:12 +08:00
|
|
|
#else
|
|
|
|
cstr_printf(&cstr, "__bt_init_dll(0);");
|
|
|
|
#endif
|
2020-01-18 05:58:39 +08:00
|
|
|
#endif
|
2020-05-22 11:06:08 +08:00
|
|
|
cstr_printf(&cstr, "__bt_init(__rt_info,%d, 0);}",
|
2020-01-18 05:58:39 +08:00
|
|
|
s1->output_type == TCC_OUTPUT_DLL ? 0 : s1->rt_num_callers + 1);
|
|
|
|
tcc_compile_string(s1, cstr.data);
|
|
|
|
cstr_free(&cstr);
|
2020-06-25 02:51:18 +08:00
|
|
|
set_local_sym(s1, &"___rt_info"[!s1->leading_underscore], s, o);
|
2019-10-29 14:02:58 +08:00
|
|
|
}
|
2020-01-18 05:58:39 +08:00
|
|
|
#endif
|
2019-10-29 14:02:58 +08:00
|
|
|
|
2020-01-18 05:58:39 +08:00
|
|
|
#ifndef TCC_TARGET_PE
|
2009-12-20 05:22:43 +08:00
|
|
|
/* add tcc runtime libraries */
|
2009-12-20 08:53:49 +08:00
|
|
|
ST_FUNC void tcc_add_runtime(TCCState *s1)
|
2009-12-20 05:22:43 +08:00
|
|
|
{
|
2018-06-01 05:51:59 +08:00
|
|
|
s1->filetype = 0;
|
2019-12-10 15:07:25 +08:00
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
bcheck cleanup
- revert Makefiles to state before last bcheck additions
Instead, just load bcheck.o explicitly if that is
what is wanted.
- move tcc_add_bcheck() to the <target>-link.c files and
remove revently added arguments. This function is to
support tccelf.c with linking, not for tccgen.c to
support compilation.
- remove -ba option: It said:
"-ba Enable better address checking with bounds checker"
Okay, if it is better then to have it is not an option.
- remove va_copy. It is C99 and we try to stay C89 in tinycc
when possible. For example, MS compilers do not have va_copy.
- win64: revert any 'fixes' to alloca
It was correct as it was before, except for bound_checking
where it was not implemented. This should now work too.
- remove parasitic filename:linenum features
Such feature is already present with rt_printline in
tccrun.c. If it doesn't work it can be fixed.
- revert changes to gen_bounded_ptr_add()
gen_bounded_ptr_add() was working as it should before
(mostly). For the sake of simplicity I switched it to
CDECL. Anyway, FASTCALL means SLOWCALL with tinycc.
In exchange you get one addition which is required for
bounds_cnecking function arguments. The important thing
is to check them *BEFORE* they are loaded into registers.
New function gbound_args() does that.
In any case, code instrumentation with the bounds-check
functions as such now seems to work flawlessly again,
which means when they are inserted as NOPs, any code that
tcc can compile, seems to behave just the same as without
them.
What these functions then do when fully enabled, is a
differnt story. I did not touch this.
2019-12-12 22:45:45 +08:00
|
|
|
tcc_add_bcheck(s1);
|
2019-12-10 15:07:25 +08:00
|
|
|
#endif
|
tccpp: fix issues, add tests
* fix some macro expansion issues
* add some pp tests in tests/pp
* improved tcc -E output for better diff'ability
* remove -dD feature (quirky code, exotic feature,
didn't work well)
Based partially on ideas / researches from PipCet
Some issues remain with VA_ARGS macros (if used in a
rather tricky way).
Also, to keep it simple, the pp doesn't automtically
add any extra spaces to separate tokens which otherwise
would form wrong tokens if re-read from tcc -E output
(such as '+' '=') GCC does that, other compilers don't.
* cleanups
- #line 01 "file" / # 01 "file" processing
- #pragma comment(lib,"foo")
- tcc -E: forward some pragmas to output (pack, comment(lib))
- fix macro parameter list parsing mess from
a3fc54345949535524d01319e1ca6378b7c2c201
a715d7143d9d17da17e67fec6af1c01409a71a31
(some coffee might help, next time ;)
- introduce TOK_PPSTR - to have character constants as
written in the file (similar to TOK_PPNUM)
- allow '\' appear in macros
- new functions begin/end_macro to:
- fix switching macro levels during expansion
- allow unget_tok to unget more than one tok
- slight speedup by using bitflags in isidnum_table
Also:
- x86_64.c : fix decl after statements
- i386-gen,c : fix a vstack leak with VLA on windows
- configure/Makefile : build on windows (MSYS) was broken
- tcc_warning: fflush stderr to keep output order (win32)
2015-05-09 20:29:39 +08:00
|
|
|
tcc_add_pragma_libs(s1);
|
2003-10-05 05:24:46 +08:00
|
|
|
/* add libc */
|
|
|
|
if (!s1->nostdlib) {
|
2020-06-02 00:10:58 +08:00
|
|
|
if (s1->option_pthread)
|
|
|
|
tcc_add_library_err(s1, "pthread");
|
2016-10-18 05:24:01 +08:00
|
|
|
tcc_add_library_err(s1, "c");
|
2017-02-23 15:41:57 +08:00
|
|
|
#ifdef TCC_LIBGCC
|
2014-03-25 21:18:57 +08:00
|
|
|
if (!s1->static_link) {
|
2017-02-23 15:41:57 +08:00
|
|
|
if (TCC_LIBGCC[0] == '/')
|
|
|
|
tcc_add_file(s1, TCC_LIBGCC);
|
|
|
|
else
|
|
|
|
tcc_add_dll(s1, TCC_LIBGCC, 0);
|
2015-03-03 22:11:18 +08:00
|
|
|
}
|
2019-12-10 15:07:25 +08:00
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TCC_BCHECK
|
|
|
|
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
|
|
|
|
tcc_add_library_err(s1, "pthread");
|
|
|
|
tcc_add_library_err(s1, "dl");
|
2020-01-18 05:58:39 +08:00
|
|
|
tcc_add_support(s1, "bcheck.o");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
#ifdef CONFIG_TCC_BACKTRACE
|
|
|
|
if (s1->do_backtrace) {
|
|
|
|
if (s1->output_type == TCC_OUTPUT_EXE)
|
|
|
|
tcc_add_support(s1, "bt-exe.o");
|
|
|
|
if (s1->output_type != TCC_OUTPUT_DLL)
|
|
|
|
tcc_add_support(s1, "bt-log.o");
|
|
|
|
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
|
|
|
tcc_add_btstub(s1);
|
2019-12-10 15:07:25 +08:00
|
|
|
}
|
2008-09-06 03:08:37 +08:00
|
|
|
#endif
|
2020-09-10 11:49:15 +08:00
|
|
|
tcc_add_support(s1, TCC_LIBTCC1);
|
2020-05-22 10:37:35 +08:00
|
|
|
#ifndef TCC_TARGET_MACHO
|
2011-08-06 22:11:12 +08:00
|
|
|
/* add crt end if not memory output */
|
|
|
|
if (s1->output_type != TCC_OUTPUT_MEMORY)
|
2011-08-06 22:49:30 +08:00
|
|
|
tcc_add_crt(s1, "crtn.o");
|
2020-05-22 10:37:35 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2004-10-24 06:53:42 +08:00
|
|
|
}
|
2020-01-18 05:58:39 +08:00
|
|
|
#endif
|
2004-10-24 06:53:42 +08:00
|
|
|
|
|
|
|
/* add various standard linker symbols (must be done after the
|
|
|
|
sections are filled (for example after allocating common
|
|
|
|
symbols)) */
|
2017-12-10 13:18:27 +08:00
|
|
|
static void tcc_add_linker_symbols(TCCState *s1)
|
2004-10-24 06:53:42 +08:00
|
|
|
{
|
|
|
|
char buf[1024];
|
|
|
|
int i;
|
|
|
|
Section *s;
|
|
|
|
|
2020-01-18 05:58:39 +08:00
|
|
|
set_global_sym(s1, "_etext", text_section, -1);
|
|
|
|
set_global_sym(s1, "_edata", data_section, -1);
|
|
|
|
set_global_sym(s1, "_end", bss_section, -1);
|
2019-06-23 08:10:10 +08:00
|
|
|
#ifdef TCC_TARGET_RISCV64
|
|
|
|
/* XXX should be .sdata+0x800, not .data+0x800 */
|
2020-01-18 05:58:39 +08:00
|
|
|
set_global_sym(s1, "__global_pointer$", data_section, 0x800);
|
2019-06-23 08:10:10 +08:00
|
|
|
#endif
|
2003-05-30 06:52:53 +08:00
|
|
|
/* horrible new standard ldscript defines */
|
|
|
|
add_init_array_defines(s1, ".preinit_array");
|
|
|
|
add_init_array_defines(s1, ".init_array");
|
|
|
|
add_init_array_defines(s1, ".fini_array");
|
2002-08-18 21:17:59 +08:00
|
|
|
/* add start and stop symbols for sections whose name can be
|
|
|
|
expressed in C */
|
2002-11-02 22:13:21 +08:00
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
2020-01-18 05:58:39 +08:00
|
|
|
if ((s->sh_flags & SHF_ALLOC)
|
|
|
|
&& (s->sh_type == SHT_PROGBITS
|
|
|
|
|| s->sh_type == SHT_STRTAB)) {
|
2002-08-18 21:17:59 +08:00
|
|
|
const char *p;
|
|
|
|
/* check if section name can be expressed in C */
|
|
|
|
p = s->name;
|
|
|
|
for(;;) {
|
2020-01-18 05:58:39 +08:00
|
|
|
int c = *p;
|
|
|
|
if (!c)
|
2002-08-18 21:17:59 +08:00
|
|
|
break;
|
2020-01-18 05:58:39 +08:00
|
|
|
if (!isid(c) && !isnum(c))
|
2002-08-18 21:17:59 +08:00
|
|
|
goto next_sec;
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), "__start_%s", s->name);
|
2020-01-18 05:58:39 +08:00
|
|
|
set_global_sym(s1, buf, s, 0);
|
2002-08-18 21:17:59 +08:00
|
|
|
snprintf(buf, sizeof(buf), "__stop_%s", s->name);
|
2020-01-18 05:58:39 +08:00
|
|
|
set_global_sym(s1, buf, s, -1);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
next_sec: ;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-12-13 00:33:37 +08:00
|
|
|
ST_FUNC void resolve_common_syms(TCCState *s1)
|
2017-12-10 13:18:27 +08:00
|
|
|
{
|
|
|
|
ElfW(Sym) *sym;
|
|
|
|
|
|
|
|
/* Allocate common symbols in BSS. */
|
|
|
|
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
|
|
|
if (sym->st_shndx == SHN_COMMON) {
|
|
|
|
/* symbol alignment is in st_value for SHN_COMMONs */
|
|
|
|
sym->st_value = section_add(bss_section, sym->st_size,
|
|
|
|
sym->st_value);
|
|
|
|
sym->st_shndx = bss_section->sh_num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now assign linker provided symbols their value. */
|
2017-12-13 00:33:37 +08:00
|
|
|
tcc_add_linker_symbols(s1);
|
2017-12-10 13:18:27 +08:00
|
|
|
}
|
|
|
|
|
2004-10-24 06:53:42 +08:00
|
|
|
static void tcc_output_binary(TCCState *s1, FILE *f,
|
2013-12-18 11:17:17 +08:00
|
|
|
const int *sec_order)
|
2004-10-24 06:53:42 +08:00
|
|
|
{
|
|
|
|
Section *s;
|
|
|
|
int i, offset, size;
|
|
|
|
|
|
|
|
offset = 0;
|
|
|
|
for(i=1;i<s1->nb_sections;i++) {
|
2013-12-18 11:17:17 +08:00
|
|
|
s = s1->sections[sec_order[i]];
|
2004-10-24 06:53:42 +08:00
|
|
|
if (s->sh_type != SHT_NOBITS &&
|
|
|
|
(s->sh_flags & SHF_ALLOC)) {
|
|
|
|
while (offset < s->sh_offset) {
|
|
|
|
fputc(0, f);
|
|
|
|
offset++;
|
|
|
|
}
|
|
|
|
size = s->sh_size;
|
|
|
|
fwrite(s->data, 1, size, f);
|
|
|
|
offset += size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2010-02-05 03:38:01 +08:00
|
|
|
ST_FUNC void fill_got_entry(TCCState *s1, ElfW_Rel *rel)
|
|
|
|
{
|
2013-12-17 20:59:14 +08:00
|
|
|
int sym_index = ELFW(R_SYM) (rel->r_info);
|
|
|
|
ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
|
2016-12-16 00:01:22 +08:00
|
|
|
struct sym_attr *attr = get_sym_attr(s1, sym_index, 0);
|
|
|
|
unsigned offset = attr->got_offset;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2016-12-16 00:01:22 +08:00
|
|
|
if (0 == offset)
|
2013-12-17 20:59:14 +08:00
|
|
|
return;
|
|
|
|
section_reserve(s1->got, offset + PTR_SIZE);
|
2020-08-02 01:44:49 +08:00
|
|
|
#if PTR_SIZE == 8
|
2016-12-16 00:01:22 +08:00
|
|
|
write64le(s1->got->data + offset, sym->st_value);
|
|
|
|
#else
|
|
|
|
write32le(s1->got->data + offset, sym->st_value);
|
2010-04-14 00:30:01 +08:00
|
|
|
#endif
|
2010-02-05 03:38:01 +08:00
|
|
|
}
|
|
|
|
|
2014-05-08 23:32:29 +08:00
|
|
|
/* Perform relocation to GOT or PLT entries */
|
2010-02-05 03:38:01 +08:00
|
|
|
ST_FUNC void fill_got(TCCState *s1)
|
|
|
|
{
|
2013-12-17 20:59:14 +08:00
|
|
|
Section *s;
|
2013-12-17 21:02:51 +08:00
|
|
|
ElfW_Rel *rel;
|
2013-12-17 20:59:14 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
|
|
|
if (s->sh_type != SHT_RELX)
|
|
|
|
continue;
|
|
|
|
/* no need to handle got relocations */
|
|
|
|
if (s->link != symtab_section)
|
|
|
|
continue;
|
2013-12-17 21:02:51 +08:00
|
|
|
for_each_elem(s, 0, rel, ElfW_Rel) {
|
2013-12-17 20:59:14 +08:00
|
|
|
switch (ELFW(R_TYPE) (rel->r_info)) {
|
|
|
|
case R_X86_64_GOT32:
|
|
|
|
case R_X86_64_GOTPCREL:
|
2015-12-17 14:30:35 +08:00
|
|
|
case R_X86_64_GOTPCRELX:
|
|
|
|
case R_X86_64_REX_GOTPCRELX:
|
2013-12-17 20:59:14 +08:00
|
|
|
case R_X86_64_PLT32:
|
|
|
|
fill_got_entry(s1, rel);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2010-02-05 03:38:01 +08:00
|
|
|
}
|
|
|
|
|
2017-05-07 10:52:21 +08:00
|
|
|
/* See put_got_entry for a description. This is the second stage
|
|
|
|
where GOT references to local defined symbols are rewritten. */
|
|
|
|
static void fill_local_got_entries(TCCState *s1)
|
|
|
|
{
|
|
|
|
ElfW_Rel *rel;
|
2018-06-01 05:51:51 +08:00
|
|
|
if (!s1->got->reloc)
|
|
|
|
return;
|
2017-05-07 10:52:21 +08:00
|
|
|
for_each_elem(s1->got->reloc, 0, rel, ElfW_Rel) {
|
|
|
|
if (ELFW(R_TYPE)(rel->r_info) == R_RELATIVE) {
|
|
|
|
int sym_index = ELFW(R_SYM) (rel->r_info);
|
|
|
|
ElfW(Sym) *sym = &((ElfW(Sym) *) symtab_section->data)[sym_index];
|
|
|
|
struct sym_attr *attr = get_sym_attr(s1, sym_index, 0);
|
|
|
|
unsigned offset = attr->got_offset;
|
|
|
|
if (offset != rel->r_offset - s1->got->sh_addr)
|
|
|
|
tcc_error_noabort("huh");
|
|
|
|
rel->r_info = ELFW(R_INFO)(0, R_RELATIVE);
|
|
|
|
#if SHT_RELX == SHT_RELA
|
|
|
|
rel->r_addend = sym->st_value;
|
|
|
|
#else
|
|
|
|
/* All our REL architectures also happen to be 32bit LE. */
|
|
|
|
write32le(s1->got->data + offset, sym->st_value);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Bind symbols of executable: resolve undefined symbols from exported symbols
|
|
|
|
in shared libraries and export non local defined symbols to shared libraries
|
|
|
|
if -rdynamic switch was given on command line */
|
|
|
|
static void bind_exe_dynsyms(TCCState *s1)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2013-12-18 11:17:17 +08:00
|
|
|
const char *name;
|
|
|
|
int sym_index, index;
|
|
|
|
ElfW(Sym) *sym, *esym;
|
|
|
|
int type;
|
2014-02-02 20:02:11 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Resolve undefined symbols from dynamic symbols. When there is a match:
|
|
|
|
- if STT_FUNC or STT_GNU_IFUNC symbol -> add it in PLT
|
|
|
|
- if STT_OBJECT symbol -> add it in .bss section with suitable reloc */
|
|
|
|
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
|
|
|
if (sym->st_shndx == SHN_UNDEF) {
|
2014-03-09 22:52:31 +08:00
|
|
|
name = (char *) symtab_section->link->data + sym->st_name;
|
2013-12-18 11:17:17 +08:00
|
|
|
sym_index = find_elf_sym(s1->dynsymtab_section, name);
|
|
|
|
if (sym_index) {
|
|
|
|
esym = &((ElfW(Sym) *)s1->dynsymtab_section->data)[sym_index];
|
|
|
|
type = ELFW(ST_TYPE)(esym->st_info);
|
|
|
|
if ((type == STT_FUNC) || (type == STT_GNU_IFUNC)) {
|
|
|
|
/* Indirect functions shall have STT_FUNC type in executable
|
|
|
|
* dynsym section. Indeed, a dlsym call following a lazy
|
|
|
|
* resolution would pick the symbol value from the
|
|
|
|
* executable dynsym entry which would contain the address
|
|
|
|
* of the function wanted by the caller of dlsym instead of
|
|
|
|
* the address of the function that would return that
|
|
|
|
* address */
|
2016-12-18 12:18:19 +08:00
|
|
|
int dynindex
|
|
|
|
= put_elf_sym(s1->dynsym, 0, esym->st_size,
|
|
|
|
ELFW(ST_INFO)(STB_GLOBAL,STT_FUNC), 0, 0,
|
|
|
|
name);
|
|
|
|
int index = sym - (ElfW(Sym) *) symtab_section->data;
|
|
|
|
get_sym_attr(s1, index, 1)->dyn_index = dynindex;
|
2013-12-18 11:17:17 +08:00
|
|
|
} else if (type == STT_OBJECT) {
|
|
|
|
unsigned long offset;
|
|
|
|
ElfW(Sym) *dynsym;
|
|
|
|
offset = bss_section->data_offset;
|
|
|
|
/* XXX: which alignment ? */
|
|
|
|
offset = (offset + 16 - 1) & -16;
|
2016-11-18 07:00:11 +08:00
|
|
|
set_elf_sym (s1->symtab, offset, esym->st_size,
|
|
|
|
esym->st_info, 0, bss_section->sh_num, name);
|
2013-12-18 11:17:17 +08:00
|
|
|
index = put_elf_sym(s1->dynsym, offset, esym->st_size,
|
|
|
|
esym->st_info, 0, bss_section->sh_num,
|
|
|
|
name);
|
2016-12-16 00:01:22 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Ensure R_COPY works for weak symbol aliases */
|
|
|
|
if (ELFW(ST_BIND)(esym->st_info) == STB_WEAK) {
|
|
|
|
for_each_elem(s1->dynsymtab_section, 1, dynsym, ElfW(Sym)) {
|
|
|
|
if ((dynsym->st_value == esym->st_value)
|
|
|
|
&& (ELFW(ST_BIND)(dynsym->st_info) == STB_GLOBAL)) {
|
2014-03-09 22:52:31 +08:00
|
|
|
char *dynname = (char *) s1->dynsymtab_section->link->data
|
2013-12-18 11:17:17 +08:00
|
|
|
+ dynsym->st_name;
|
|
|
|
put_elf_sym(s1->dynsym, offset, dynsym->st_size,
|
|
|
|
dynsym->st_info, 0,
|
|
|
|
bss_section->sh_num, dynname);
|
|
|
|
break;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2016-12-16 00:01:22 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
put_elf_reloc(s1->dynsym, bss_section,
|
|
|
|
offset, R_COPY, index);
|
|
|
|
offset += esym->st_size;
|
|
|
|
bss_section->data_offset = offset;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
} else {
|
2013-12-18 11:17:17 +08:00
|
|
|
/* STB_WEAK undefined symbols are accepted */
|
|
|
|
/* XXX: _fp_hw seems to be part of the ABI, so we ignore it */
|
|
|
|
if (ELFW(ST_BIND)(sym->st_info) == STB_WEAK ||
|
|
|
|
!strcmp(name, "_fp_hw")) {
|
|
|
|
} else {
|
|
|
|
tcc_error_noabort("undefined symbol '%s'", name);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
} else if (s1->rdynamic && ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
|
|
|
/* if -rdynamic option, then export all non local symbols */
|
2014-03-09 22:52:31 +08:00
|
|
|
name = (char *) symtab_section->link->data + sym->st_name;
|
2016-11-12 23:16:04 +08:00
|
|
|
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size, sym->st_info,
|
2013-12-18 11:17:17 +08:00
|
|
|
0, sym->st_shndx, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2016-11-12 23:16:04 +08:00
|
|
|
/* Bind symbols of libraries: export all non local symbols of executable that
|
|
|
|
are referenced by shared libraries. The reason is that the dynamic loader
|
|
|
|
search symbol first in executable and then in libraries. Therefore a
|
|
|
|
reference to a symbol already defined by a library can still be resolved by
|
|
|
|
a symbol in the executable. */
|
2013-12-18 11:17:17 +08:00
|
|
|
static void bind_libs_dynsyms(TCCState *s1)
|
|
|
|
{
|
|
|
|
const char *name;
|
|
|
|
int sym_index;
|
|
|
|
ElfW(Sym) *sym, *esym;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
for_each_elem(s1->dynsymtab_section, 1, esym, ElfW(Sym)) {
|
2015-04-18 15:28:02 +08:00
|
|
|
name = (char *) s1->dynsymtab_section->link->data + esym->st_name;
|
|
|
|
sym_index = find_elf_sym(symtab_section, name);
|
2016-11-12 23:16:03 +08:00
|
|
|
sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (sym_index && sym->st_shndx != SHN_UNDEF
|
|
|
|
&& ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
|
|
|
set_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
|
|
|
|
sym->st_info, 0, sym->st_shndx, name);
|
|
|
|
} else if (esym->st_shndx == SHN_UNDEF) {
|
2015-04-18 15:28:02 +08:00
|
|
|
/* weak symbols can stay undefined */
|
|
|
|
if (ELFW(ST_BIND)(esym->st_info) != STB_WEAK)
|
|
|
|
tcc_warning("undefined dynamic symbol '%s'", name);
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2009-12-20 05:08:15 +08:00
|
|
|
|
2016-11-12 23:16:04 +08:00
|
|
|
/* Export all non local symbols. This is used by shared libraries so that the
|
|
|
|
non local symbols they define can resolve a reference in another shared
|
|
|
|
library or in the executable. Correspondingly, it allows undefined local
|
|
|
|
symbols to be resolved by other shared libraries or by the executable. */
|
2013-12-18 11:17:17 +08:00
|
|
|
static void export_global_syms(TCCState *s1)
|
|
|
|
{
|
2016-12-16 00:01:22 +08:00
|
|
|
int dynindex, index;
|
2013-12-18 11:17:17 +08:00
|
|
|
const char *name;
|
|
|
|
ElfW(Sym) *sym;
|
2009-12-20 05:08:15 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
for_each_elem(symtab_section, 1, sym, ElfW(Sym)) {
|
|
|
|
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
2015-07-30 04:53:57 +08:00
|
|
|
name = (char *) symtab_section->link->data + sym->st_name;
|
|
|
|
dynindex = put_elf_sym(s1->dynsym, sym->st_value, sym->st_size,
|
|
|
|
sym->st_info, 0, sym->st_shndx, name);
|
|
|
|
index = sym - (ElfW(Sym) *) symtab_section->data;
|
2016-12-16 00:01:22 +08:00
|
|
|
get_sym_attr(s1, index, 1)->dyn_index = dynindex;
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2014-02-02 20:02:11 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Allocate strings for section names and decide if an unallocated section
|
|
|
|
should be output.
|
|
|
|
NOTE: the strsec section comes last, so its size is also correct ! */
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
static int alloc_sec_names(TCCState *s1, int file_type, Section *strsec)
|
2013-12-18 11:17:17 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Section *s;
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
int textrel = 0;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Allocate strings for section names */
|
2002-11-02 22:13:21 +08:00
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
2002-08-18 21:17:59 +08:00
|
|
|
/* when generating a DLL, we include relocations but we may
|
|
|
|
patch them */
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2013-12-17 20:59:14 +08:00
|
|
|
if (file_type == TCC_OUTPUT_DLL &&
|
|
|
|
s->sh_type == SHT_RELX &&
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
!(s->sh_flags & SHF_ALLOC) &&
|
|
|
|
(s1->sections[s->sh_info]->sh_flags & SHF_ALLOC) &&
|
|
|
|
prepare_dynamic_rel(s1, s)) {
|
2020-01-18 05:58:39 +08:00
|
|
|
if (!(s1->sections[s->sh_info]->sh_flags & SHF_WRITE))
|
|
|
|
textrel = 1;
|
2019-12-10 03:32:13 +08:00
|
|
|
} else
|
|
|
|
#endif
|
|
|
|
if ((s1->do_debug && s->sh_type != SHT_RELX) ||
|
2013-12-17 20:59:14 +08:00
|
|
|
file_type == TCC_OUTPUT_OBJ ||
|
2002-08-18 21:17:59 +08:00
|
|
|
(s->sh_flags & SHF_ALLOC) ||
|
2020-08-04 15:15:42 +08:00
|
|
|
i == (s1->nb_sections - 1)
|
|
|
|
#ifdef TCC_TARGET_ARM
|
|
|
|
|| s->sh_type == SHT_ARM_ATTRIBUTES
|
|
|
|
#endif
|
|
|
|
) {
|
2002-08-18 21:17:59 +08:00
|
|
|
/* we output all sections if debug or object file */
|
|
|
|
s->sh_size = s->data_offset;
|
|
|
|
}
|
2020-08-05 19:55:11 +08:00
|
|
|
#ifdef TCC_TARGET_ARM
|
|
|
|
/* XXX: Suppress stack unwinding section. */
|
|
|
|
if (s->sh_type == SHT_ARM_EXIDX) {
|
|
|
|
s->sh_flags = 0;
|
|
|
|
s->sh_size = 0;
|
|
|
|
}
|
|
|
|
#endif
|
2017-01-23 08:11:38 +08:00
|
|
|
if (s->sh_size || (s->sh_flags & SHF_ALLOC))
|
|
|
|
s->sh_name = put_elf_str(strsec, s->name);
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2017-01-23 08:11:38 +08:00
|
|
|
strsec->sh_size = strsec->data_offset;
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
return textrel;
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Info to be copied in dynamic section */
|
|
|
|
struct dyn_inf {
|
|
|
|
Section *dynamic;
|
|
|
|
Section *dynstr;
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
unsigned long data_offset;
|
2013-12-18 11:17:17 +08:00
|
|
|
addr_t rel_addr;
|
|
|
|
addr_t rel_size;
|
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
|
|
addr_t bss_addr;
|
|
|
|
addr_t bss_size;
|
|
|
|
#endif
|
|
|
|
};
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Assign sections to segments and decide how are sections laid out when loaded
|
|
|
|
in memory. This function also fills corresponding program headers. */
|
|
|
|
static int layout_sections(TCCState *s1, ElfW(Phdr) *phdr, int phnum,
|
2014-09-07 23:29:38 +08:00
|
|
|
Section *interp, Section* strsec,
|
|
|
|
struct dyn_inf *dyninf, int *sec_order)
|
2013-12-18 11:17:17 +08:00
|
|
|
{
|
|
|
|
int i, j, k, file_type, sh_order_index, file_offset;
|
2014-05-08 23:32:29 +08:00
|
|
|
unsigned long s_align;
|
2013-12-18 11:17:17 +08:00
|
|
|
long long tmp;
|
|
|
|
addr_t addr;
|
|
|
|
ElfW(Phdr) *ph;
|
|
|
|
Section *s;
|
|
|
|
|
|
|
|
file_type = s1->output_type;
|
|
|
|
sh_order_index = 1;
|
2014-05-08 23:32:29 +08:00
|
|
|
file_offset = 0;
|
2013-12-18 11:17:17 +08:00
|
|
|
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF)
|
2008-11-30 07:14:07 +08:00
|
|
|
file_offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
|
2014-05-08 23:32:29 +08:00
|
|
|
s_align = ELF_PAGE_SIZE;
|
|
|
|
if (s1->section_align)
|
|
|
|
s_align = s1->section_align;
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
if (phnum > 0) {
|
2013-12-17 20:59:14 +08:00
|
|
|
if (s1->has_text_addr) {
|
2004-10-18 08:20:26 +08:00
|
|
|
int a_offset, p_offset;
|
|
|
|
addr = s1->text_addr;
|
|
|
|
/* we ensure that (addr % ELF_PAGE_SIZE) == file_offset %
|
|
|
|
ELF_PAGE_SIZE */
|
2014-05-08 23:32:29 +08:00
|
|
|
a_offset = (int) (addr & (s_align - 1));
|
|
|
|
p_offset = file_offset & (s_align - 1);
|
2013-12-17 20:59:14 +08:00
|
|
|
if (a_offset < p_offset)
|
2014-05-08 23:32:29 +08:00
|
|
|
a_offset += s_align;
|
2004-10-18 08:20:26 +08:00
|
|
|
file_offset += (a_offset - p_offset);
|
|
|
|
} else {
|
|
|
|
if (file_type == TCC_OUTPUT_DLL)
|
|
|
|
addr = 0;
|
|
|
|
else
|
|
|
|
addr = ELF_START_ADDR;
|
|
|
|
/* compute address after headers */
|
2014-05-08 23:32:29 +08:00
|
|
|
addr += (file_offset & (s_align - 1));
|
2004-10-18 08:20:26 +08:00
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2014-02-02 20:02:11 +08:00
|
|
|
ph = &phdr[0];
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Leave one program headers for the program interpreter and one for
|
|
|
|
the program header table itself if needed. These are done later as
|
|
|
|
they require section layout to be done first. */
|
2014-02-02 20:02:11 +08:00
|
|
|
if (interp)
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
ph += 2;
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* dynamic relocation table information, for .dynamic section */
|
|
|
|
dyninf->rel_addr = dyninf->rel_size = 0;
|
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
|
|
|
dyninf->bss_addr = dyninf->bss_size = 0;
|
|
|
|
#endif
|
|
|
|
|
2020-09-08 20:31:58 +08:00
|
|
|
for(j = 0; j < (phnum == 6 ? 3 : 2); j++) {
|
|
|
|
ph->p_type = j == 2 ? PT_TLS : PT_LOAD;
|
2013-10-29 22:10:02 +08:00
|
|
|
if (j == 0)
|
2013-11-03 18:55:54 +08:00
|
|
|
ph->p_flags = PF_R | PF_X;
|
|
|
|
else
|
|
|
|
ph->p_flags = PF_R | PF_W;
|
2020-09-08 20:31:58 +08:00
|
|
|
ph->p_align = j == 2 ? 4 : s_align;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Decide the layout of sections loaded in memory. This must
|
|
|
|
be done before program headers are filled since they contain
|
|
|
|
info about the layout. We do the following ordering: interp,
|
|
|
|
symbol tables, relocations, progbits, nobits */
|
2002-08-18 21:17:59 +08:00
|
|
|
/* XXX: do faster and simpler sorting */
|
|
|
|
for(k = 0; k < 5; k++) {
|
2002-11-02 22:13:21 +08:00
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
2002-08-18 21:17:59 +08:00
|
|
|
/* compute if section should be included */
|
|
|
|
if (j == 0) {
|
2020-09-08 20:31:58 +08:00
|
|
|
if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) !=
|
2002-08-18 21:17:59 +08:00
|
|
|
SHF_ALLOC)
|
|
|
|
continue;
|
2020-09-08 20:31:58 +08:00
|
|
|
} else if (j == 1) {
|
|
|
|
if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) !=
|
2013-11-03 18:55:54 +08:00
|
|
|
(SHF_ALLOC | SHF_WRITE))
|
2013-10-29 22:10:02 +08:00
|
|
|
continue;
|
2020-09-08 20:31:58 +08:00
|
|
|
} else {
|
|
|
|
if ((s->sh_flags & (SHF_ALLOC | SHF_WRITE | SHF_TLS)) !=
|
|
|
|
(SHF_ALLOC | SHF_WRITE | SHF_TLS))
|
|
|
|
continue;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
if (s == interp) {
|
|
|
|
if (k != 0)
|
|
|
|
continue;
|
2020-01-18 05:58:39 +08:00
|
|
|
} else if ((s->sh_type == SHT_DYNSYM ||
|
|
|
|
s->sh_type == SHT_STRTAB ||
|
|
|
|
s->sh_type == SHT_HASH)
|
|
|
|
&& !strstr(s->name, ".stab")) {
|
2002-08-18 21:17:59 +08:00
|
|
|
if (k != 1)
|
|
|
|
continue;
|
2008-11-30 07:14:07 +08:00
|
|
|
} else if (s->sh_type == SHT_RELX) {
|
2002-08-18 21:17:59 +08:00
|
|
|
if (k != 2)
|
|
|
|
continue;
|
|
|
|
} else if (s->sh_type == SHT_NOBITS) {
|
|
|
|
if (k != 4)
|
|
|
|
continue;
|
|
|
|
} else {
|
|
|
|
if (k != 3)
|
|
|
|
continue;
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
sec_order[sh_order_index++] = i;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* section matches: we align it and add its size */
|
2004-10-18 08:20:26 +08:00
|
|
|
tmp = addr;
|
2013-12-17 20:59:14 +08:00
|
|
|
addr = (addr + s->sh_addralign - 1) &
|
2002-08-18 21:17:59 +08:00
|
|
|
~(s->sh_addralign - 1);
|
2012-03-04 01:10:15 +08:00
|
|
|
file_offset += (int) ( addr - tmp );
|
2002-08-18 21:17:59 +08:00
|
|
|
s->sh_offset = file_offset;
|
|
|
|
s->sh_addr = addr;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* update program header infos */
|
|
|
|
if (ph->p_offset == 0) {
|
|
|
|
ph->p_offset = file_offset;
|
|
|
|
ph->p_vaddr = addr;
|
|
|
|
ph->p_paddr = ph->p_vaddr;
|
|
|
|
}
|
|
|
|
/* update dynamic relocation infos */
|
2008-11-30 07:14:07 +08:00
|
|
|
if (s->sh_type == SHT_RELX) {
|
2010-09-11 03:09:07 +08:00
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
2013-12-17 20:59:14 +08:00
|
|
|
if (!strcmp(strsec->data + s->sh_name, ".rel.got")) {
|
2013-12-18 11:17:17 +08:00
|
|
|
dyninf->rel_addr = addr;
|
|
|
|
dyninf->rel_size += s->sh_size; /* XXX only first rel. */
|
2013-12-17 20:59:14 +08:00
|
|
|
}
|
|
|
|
if (!strcmp(strsec->data + s->sh_name, ".rel.bss")) {
|
2013-12-18 11:17:17 +08:00
|
|
|
dyninf->bss_addr = addr;
|
|
|
|
dyninf->bss_size = s->sh_size; /* XXX only first rel. */
|
2013-12-17 20:59:14 +08:00
|
|
|
}
|
2009-11-29 10:25:29 +08:00
|
|
|
#else
|
2013-12-18 11:17:17 +08:00
|
|
|
if (dyninf->rel_size == 0)
|
|
|
|
dyninf->rel_addr = addr;
|
|
|
|
dyninf->rel_size += s->sh_size;
|
2009-11-29 10:25:29 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
addr += s->sh_size;
|
|
|
|
if (s->sh_type != SHT_NOBITS)
|
|
|
|
file_offset += s->sh_size;
|
|
|
|
}
|
|
|
|
}
|
2015-07-30 04:53:57 +08:00
|
|
|
if (j == 0) {
|
|
|
|
/* Make the first PT_LOAD segment include the program
|
|
|
|
headers itself (and the ELF header as well), it'll
|
|
|
|
come out with same memory use but will make various
|
|
|
|
tools like binutils strip work better. */
|
|
|
|
ph->p_offset &= ~(ph->p_align - 1);
|
|
|
|
ph->p_vaddr &= ~(ph->p_align - 1);
|
|
|
|
ph->p_paddr &= ~(ph->p_align - 1);
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
ph->p_filesz = file_offset - ph->p_offset;
|
|
|
|
ph->p_memsz = addr - ph->p_vaddr;
|
|
|
|
ph++;
|
2004-10-24 06:53:42 +08:00
|
|
|
if (j == 0) {
|
|
|
|
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
|
|
|
|
/* if in the middle of a page, we duplicate the page in
|
|
|
|
memory so that one copy is RX and the other is RW */
|
2014-05-08 23:32:29 +08:00
|
|
|
if ((addr & (s_align - 1)) != 0)
|
|
|
|
addr += s_align;
|
2004-10-24 06:53:42 +08:00
|
|
|
} else {
|
2014-05-08 23:32:29 +08:00
|
|
|
addr = (addr + s_align - 1) & ~(s_align - 1);
|
|
|
|
file_offset = (file_offset + s_align - 1) & ~(s_align - 1);
|
2004-10-24 06:53:42 +08:00
|
|
|
}
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* all other sections come after */
|
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
|
|
|
if (phnum > 0 && (s->sh_flags & SHF_ALLOC))
|
|
|
|
continue;
|
|
|
|
sec_order[sh_order_index++] = i;
|
2009-11-29 10:25:29 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
file_offset = (file_offset + s->sh_addralign - 1) &
|
|
|
|
~(s->sh_addralign - 1);
|
|
|
|
s->sh_offset = file_offset;
|
|
|
|
if (s->sh_type != SHT_NOBITS)
|
|
|
|
file_offset += s->sh_size;
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
return file_offset;
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2020-05-09 07:40:36 +08:00
|
|
|
/* put dynamic tag */
|
|
|
|
static void put_dt(Section *dynamic, int dt, addr_t val)
|
|
|
|
{
|
|
|
|
ElfW(Dyn) *dyn;
|
|
|
|
dyn = section_ptr_add(dynamic, sizeof(ElfW(Dyn)));
|
|
|
|
dyn->d_tag = dt;
|
|
|
|
dyn->d_un.d_val = val;
|
|
|
|
}
|
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
static void fill_unloadable_phdr(ElfW(Phdr) *phdr, int phnum, Section *interp,
|
|
|
|
Section *dynamic)
|
|
|
|
{
|
|
|
|
ElfW(Phdr) *ph;
|
|
|
|
|
|
|
|
/* if interpreter, then add corresponding program header */
|
|
|
|
if (interp) {
|
|
|
|
ph = &phdr[0];
|
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
ph->p_type = PT_PHDR;
|
|
|
|
ph->p_offset = sizeof(ElfW(Ehdr));
|
|
|
|
ph->p_filesz = ph->p_memsz = phnum * sizeof(ElfW(Phdr));
|
|
|
|
ph->p_vaddr = interp->sh_addr - ph->p_filesz;
|
|
|
|
ph->p_paddr = ph->p_vaddr;
|
|
|
|
ph->p_flags = PF_R | PF_X;
|
|
|
|
ph->p_align = 4; /* interp->sh_addralign; */
|
|
|
|
ph++;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
ph->p_type = PT_INTERP;
|
|
|
|
ph->p_offset = interp->sh_offset;
|
|
|
|
ph->p_vaddr = interp->sh_addr;
|
|
|
|
ph->p_paddr = ph->p_vaddr;
|
|
|
|
ph->p_filesz = interp->sh_size;
|
|
|
|
ph->p_memsz = interp->sh_size;
|
|
|
|
ph->p_flags = PF_R;
|
|
|
|
ph->p_align = interp->sh_addralign;
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* if dynamic section, then add corresponding program header */
|
|
|
|
if (dynamic) {
|
|
|
|
ph = &phdr[phnum - 1];
|
|
|
|
|
|
|
|
ph->p_type = PT_DYNAMIC;
|
|
|
|
ph->p_offset = dynamic->sh_offset;
|
|
|
|
ph->p_vaddr = dynamic->sh_addr;
|
|
|
|
ph->p_paddr = ph->p_vaddr;
|
|
|
|
ph->p_filesz = dynamic->sh_size;
|
|
|
|
ph->p_memsz = dynamic->sh_size;
|
|
|
|
ph->p_flags = PF_R | PF_W;
|
|
|
|
ph->p_align = dynamic->sh_addralign;
|
|
|
|
}
|
|
|
|
}
|
2003-04-13 22:38:05 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Fill the dynamic section with tags describing the address and size of
|
|
|
|
sections */
|
|
|
|
static void fill_dynamic(TCCState *s1, struct dyn_inf *dyninf)
|
|
|
|
{
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
Section *dynamic = dyninf->dynamic;
|
2019-10-29 14:02:58 +08:00
|
|
|
Section *s;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* put dynamic section entries */
|
|
|
|
put_dt(dynamic, DT_HASH, s1->dynsym->hash->sh_addr);
|
|
|
|
put_dt(dynamic, DT_STRTAB, dyninf->dynstr->sh_addr);
|
|
|
|
put_dt(dynamic, DT_SYMTAB, s1->dynsym->sh_addr);
|
|
|
|
put_dt(dynamic, DT_STRSZ, dyninf->dynstr->data_offset);
|
|
|
|
put_dt(dynamic, DT_SYMENT, sizeof(ElfW(Sym)));
|
2017-05-13 14:59:06 +08:00
|
|
|
#if PTR_SIZE == 8
|
2013-12-18 11:17:17 +08:00
|
|
|
put_dt(dynamic, DT_RELA, dyninf->rel_addr);
|
|
|
|
put_dt(dynamic, DT_RELASZ, dyninf->rel_size);
|
|
|
|
put_dt(dynamic, DT_RELAENT, sizeof(ElfW_Rel));
|
2009-11-29 10:25:29 +08:00
|
|
|
#else
|
2010-09-11 03:09:07 +08:00
|
|
|
#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
|
2013-12-18 11:17:17 +08:00
|
|
|
put_dt(dynamic, DT_PLTGOT, s1->got->sh_addr);
|
|
|
|
put_dt(dynamic, DT_PLTRELSZ, dyninf->rel_size);
|
|
|
|
put_dt(dynamic, DT_JMPREL, dyninf->rel_addr);
|
|
|
|
put_dt(dynamic, DT_PLTREL, DT_REL);
|
|
|
|
put_dt(dynamic, DT_REL, dyninf->bss_addr);
|
|
|
|
put_dt(dynamic, DT_RELSZ, dyninf->bss_size);
|
2008-12-02 02:19:25 +08:00
|
|
|
#else
|
2013-12-18 11:17:17 +08:00
|
|
|
put_dt(dynamic, DT_REL, dyninf->rel_addr);
|
|
|
|
put_dt(dynamic, DT_RELSZ, dyninf->rel_size);
|
|
|
|
put_dt(dynamic, DT_RELENT, sizeof(ElfW_Rel));
|
2009-11-29 10:25:29 +08:00
|
|
|
#endif
|
2008-12-02 02:19:25 +08:00
|
|
|
#endif
|
2020-01-20 12:31:09 +08:00
|
|
|
if (versym_section)
|
|
|
|
put_dt(dynamic, DT_VERSYM, versym_section->sh_addr);
|
|
|
|
if (verneed_section) {
|
2019-12-10 03:32:13 +08:00
|
|
|
put_dt(dynamic, DT_VERNEED, verneed_section->sh_addr);
|
|
|
|
put_dt(dynamic, DT_VERNEEDNUM, dt_verneednum);
|
|
|
|
}
|
2019-10-29 14:02:58 +08:00
|
|
|
s = find_section_create (s1, ".preinit_array", 0);
|
|
|
|
if (s && s->data_offset) {
|
|
|
|
put_dt(dynamic, DT_PREINIT_ARRAY, s->sh_addr);
|
|
|
|
put_dt(dynamic, DT_PREINIT_ARRAYSZ, s->data_offset);
|
|
|
|
}
|
|
|
|
s = find_section_create (s1, ".init_array", 0);
|
|
|
|
if (s && s->data_offset) {
|
|
|
|
put_dt(dynamic, DT_INIT_ARRAY, s->sh_addr);
|
|
|
|
put_dt(dynamic, DT_INIT_ARRAYSZ, s->data_offset);
|
|
|
|
}
|
|
|
|
s = find_section_create (s1, ".fini_array", 0);
|
|
|
|
if (s && s->data_offset) {
|
|
|
|
put_dt(dynamic, DT_FINI_ARRAY, s->sh_addr);
|
|
|
|
put_dt(dynamic, DT_FINI_ARRAYSZ, s->data_offset);
|
|
|
|
}
|
|
|
|
s = find_section_create (s1, ".init", 0);
|
|
|
|
if (s && s->data_offset) {
|
|
|
|
put_dt(dynamic, DT_INIT, s->sh_addr);
|
|
|
|
}
|
|
|
|
s = find_section_create (s1, ".fini", 0);
|
|
|
|
if (s && s->data_offset) {
|
|
|
|
put_dt(dynamic, DT_FINI, s->sh_addr);
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
if (s1->do_debug)
|
|
|
|
put_dt(dynamic, DT_DEBUG, 0);
|
|
|
|
put_dt(dynamic, DT_NULL, 0);
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Relocate remaining sections and symbols (that is those not related to
|
|
|
|
dynamic linking) */
|
|
|
|
static int final_sections_reloc(TCCState *s1)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
Section *s;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2016-11-12 23:16:09 +08:00
|
|
|
relocate_syms(s1, s1->symtab, 0);
|
2013-12-18 11:17:17 +08:00
|
|
|
|
|
|
|
if (s1->nb_errors != 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
/* relocate sections */
|
|
|
|
/* XXX: ignore sections with allocated relocations ? */
|
2013-12-18 11:17:17 +08:00
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
2019-01-13 13:00:51 +08:00
|
|
|
if (s->reloc && (s != s1->got || s1->static_link))
|
2013-12-18 11:17:17 +08:00
|
|
|
relocate_section(s1, s);
|
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* relocate relocation entries if the relocation tables are
|
|
|
|
allocated in the executable */
|
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[i];
|
|
|
|
if ((s->sh_flags & SHF_ALLOC) &&
|
|
|
|
s->sh_type == SHT_RELX) {
|
|
|
|
relocate_rel(s1, s);
|
|
|
|
}
|
2014-02-02 20:02:11 +08:00
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
return 0;
|
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2002-11-02 22:13:21 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Create an ELF file on disk.
|
|
|
|
This function handle ELF specific layout requirements */
|
|
|
|
static void tcc_output_elf(TCCState *s1, FILE *f, int phnum, ElfW(Phdr) *phdr,
|
|
|
|
int file_offset, int *sec_order)
|
|
|
|
{
|
|
|
|
int i, shnum, offset, size, file_type;
|
|
|
|
Section *s;
|
|
|
|
ElfW(Ehdr) ehdr;
|
|
|
|
ElfW(Shdr) shdr, *sh;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
file_type = s1->output_type;
|
|
|
|
shnum = s1->nb_sections;
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
memset(&ehdr, 0, sizeof(ehdr));
|
|
|
|
|
|
|
|
if (phnum > 0) {
|
|
|
|
ehdr.e_phentsize = sizeof(ElfW(Phdr));
|
|
|
|
ehdr.e_phnum = phnum;
|
|
|
|
ehdr.e_phoff = sizeof(ElfW(Ehdr));
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* align to 4 */
|
|
|
|
file_offset = (file_offset + 3) & -4;
|
|
|
|
|
|
|
|
/* fill header */
|
|
|
|
ehdr.e_ident[0] = ELFMAG0;
|
|
|
|
ehdr.e_ident[1] = ELFMAG1;
|
|
|
|
ehdr.e_ident[2] = ELFMAG2;
|
|
|
|
ehdr.e_ident[3] = ELFMAG3;
|
|
|
|
ehdr.e_ident[4] = ELFCLASSW;
|
|
|
|
ehdr.e_ident[5] = ELFDATA2LSB;
|
|
|
|
ehdr.e_ident[6] = EV_CURRENT;
|
2017-09-25 23:39:35 +08:00
|
|
|
#if !defined(TCC_TARGET_PE) && (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
|
|
|
|
/* FIXME: should set only for freebsd _target_, but we exclude only PE target */
|
2013-12-18 11:17:17 +08:00
|
|
|
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
|
|
|
#endif
|
|
|
|
#ifdef TCC_TARGET_ARM
|
|
|
|
#ifdef TCC_ARM_EABI
|
|
|
|
ehdr.e_ident[EI_OSABI] = 0;
|
|
|
|
ehdr.e_flags = EF_ARM_EABI_VER4;
|
|
|
|
if (file_type == TCC_OUTPUT_EXE || file_type == TCC_OUTPUT_DLL)
|
|
|
|
ehdr.e_flags |= EF_ARM_HASENTRY;
|
|
|
|
if (s1->float_abi == ARM_HARD_FLOAT)
|
|
|
|
ehdr.e_flags |= EF_ARM_VFP_FLOAT;
|
|
|
|
else
|
|
|
|
ehdr.e_flags |= EF_ARM_SOFT_FLOAT;
|
|
|
|
#else
|
|
|
|
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
|
|
|
|
#endif
|
2019-07-16 05:15:51 +08:00
|
|
|
#elif defined TCC_TARGET_RISCV64
|
|
|
|
ehdr.e_flags = EF_RISCV_FLOAT_ABI_DOUBLE;
|
2013-12-18 11:17:17 +08:00
|
|
|
#endif
|
|
|
|
switch(file_type) {
|
|
|
|
default:
|
|
|
|
case TCC_OUTPUT_EXE:
|
|
|
|
ehdr.e_type = ET_EXEC;
|
2020-05-22 10:28:02 +08:00
|
|
|
ehdr.e_entry = get_sym_addr(s1, "_start", 1, 0);
|
2013-12-18 11:17:17 +08:00
|
|
|
break;
|
|
|
|
case TCC_OUTPUT_DLL:
|
|
|
|
ehdr.e_type = ET_DYN;
|
|
|
|
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
|
|
|
|
break;
|
|
|
|
case TCC_OUTPUT_OBJ:
|
|
|
|
ehdr.e_type = ET_REL;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
ehdr.e_machine = EM_TCC_TARGET;
|
|
|
|
ehdr.e_version = EV_CURRENT;
|
|
|
|
ehdr.e_shoff = file_offset;
|
|
|
|
ehdr.e_ehsize = sizeof(ElfW(Ehdr));
|
|
|
|
ehdr.e_shentsize = sizeof(ElfW(Shdr));
|
|
|
|
ehdr.e_shnum = shnum;
|
|
|
|
ehdr.e_shstrndx = shnum - 1;
|
|
|
|
|
|
|
|
fwrite(&ehdr, 1, sizeof(ElfW(Ehdr)), f);
|
|
|
|
fwrite(phdr, 1, phnum * sizeof(ElfW(Phdr)), f);
|
|
|
|
offset = sizeof(ElfW(Ehdr)) + phnum * sizeof(ElfW(Phdr));
|
|
|
|
|
|
|
|
sort_syms(s1, symtab_section);
|
|
|
|
for(i = 1; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[sec_order[i]];
|
|
|
|
if (s->sh_type != SHT_NOBITS) {
|
|
|
|
while (offset < s->sh_offset) {
|
|
|
|
fputc(0, f);
|
|
|
|
offset++;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
size = s->sh_size;
|
2015-11-10 06:57:58 +08:00
|
|
|
if (size)
|
|
|
|
fwrite(s->data, 1, size, f);
|
2013-12-18 11:17:17 +08:00
|
|
|
offset += size;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* output section headers */
|
|
|
|
while (offset < ehdr.e_shoff) {
|
|
|
|
fputc(0, f);
|
|
|
|
offset++;
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
for(i = 0; i < s1->nb_sections; i++) {
|
|
|
|
sh = &shdr;
|
|
|
|
memset(sh, 0, sizeof(ElfW(Shdr)));
|
|
|
|
s = s1->sections[i];
|
|
|
|
if (s) {
|
|
|
|
sh->sh_name = s->sh_name;
|
|
|
|
sh->sh_type = s->sh_type;
|
|
|
|
sh->sh_flags = s->sh_flags;
|
|
|
|
sh->sh_entsize = s->sh_entsize;
|
|
|
|
sh->sh_info = s->sh_info;
|
|
|
|
if (s->link)
|
|
|
|
sh->sh_link = s->link->sh_num;
|
|
|
|
sh->sh_addralign = s->sh_addralign;
|
|
|
|
sh->sh_addr = s->sh_addr;
|
|
|
|
sh->sh_offset = s->sh_offset;
|
|
|
|
sh->sh_size = s->sh_size;
|
|
|
|
}
|
|
|
|
fwrite(sh, 1, sizeof(ElfW(Shdr)), f);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Write an elf, coff or "binary" file */
|
|
|
|
static int tcc_write_elf_file(TCCState *s1, const char *filename, int phnum,
|
|
|
|
ElfW(Phdr) *phdr, int file_offset, int *sec_order)
|
|
|
|
{
|
|
|
|
int fd, mode, file_type;
|
|
|
|
FILE *f;
|
|
|
|
|
|
|
|
file_type = s1->output_type;
|
2002-08-18 21:17:59 +08:00
|
|
|
if (file_type == TCC_OUTPUT_OBJ)
|
|
|
|
mode = 0666;
|
|
|
|
else
|
|
|
|
mode = 0777;
|
2011-03-03 21:09:18 +08:00
|
|
|
unlink(filename);
|
2013-12-17 20:59:14 +08:00
|
|
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
|
2002-11-02 22:13:21 +08:00
|
|
|
if (fd < 0) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("could not write '%s'", filename);
|
2013-12-18 11:17:17 +08:00
|
|
|
return -1;
|
2002-11-02 22:13:21 +08:00
|
|
|
}
|
2004-10-24 06:53:42 +08:00
|
|
|
f = fdopen(fd, "wb");
|
2009-05-12 00:45:44 +08:00
|
|
|
if (s1->verbose)
|
2008-04-01 03:49:14 +08:00
|
|
|
printf("<- %s\n", filename);
|
2004-10-24 06:53:42 +08:00
|
|
|
|
|
|
|
#ifdef TCC_TARGET_COFF
|
2013-12-18 11:17:17 +08:00
|
|
|
if (s1->output_format == TCC_OUTPUT_FORMAT_COFF)
|
2004-10-24 06:53:42 +08:00
|
|
|
tcc_output_coff(s1, f);
|
2013-12-18 11:17:17 +08:00
|
|
|
else
|
2014-02-02 20:02:11 +08:00
|
|
|
#endif
|
2013-12-18 11:17:17 +08:00
|
|
|
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF)
|
|
|
|
tcc_output_elf(s1, f, phnum, phdr, file_offset, sec_order);
|
|
|
|
else
|
|
|
|
tcc_output_binary(s1, f, sec_order);
|
|
|
|
fclose(f);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2017-01-23 08:11:38 +08:00
|
|
|
/* Sort section headers by assigned sh_addr, remove sections
|
|
|
|
that we aren't going to output. */
|
|
|
|
static void tidy_section_headers(TCCState *s1, int *sec_order)
|
|
|
|
{
|
|
|
|
int i, nnew, l, *backmap;
|
|
|
|
Section **snew, *s;
|
|
|
|
ElfW(Sym) *sym;
|
|
|
|
|
|
|
|
snew = tcc_malloc(s1->nb_sections * sizeof(snew[0]));
|
|
|
|
backmap = tcc_malloc(s1->nb_sections * sizeof(backmap[0]));
|
|
|
|
for (i = 0, nnew = 0, l = s1->nb_sections; i < s1->nb_sections; i++) {
|
|
|
|
s = s1->sections[sec_order[i]];
|
|
|
|
if (!i || s->sh_name) {
|
|
|
|
backmap[sec_order[i]] = nnew;
|
|
|
|
snew[nnew] = s;
|
|
|
|
++nnew;
|
|
|
|
} else {
|
|
|
|
backmap[sec_order[i]] = 0;
|
|
|
|
snew[--l] = s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (i = 0; i < nnew; i++) {
|
|
|
|
s = snew[i];
|
|
|
|
if (s) {
|
|
|
|
s->sh_num = i;
|
|
|
|
if (s->sh_type == SHT_RELX)
|
|
|
|
s->sh_info = backmap[s->sh_info];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
for_each_elem(symtab_section, 1, sym, ElfW(Sym))
|
|
|
|
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
|
|
|
|
sym->st_shndx = backmap[sym->st_shndx];
|
2017-06-10 02:44:29 +08:00
|
|
|
if( !s1->static_link ) {
|
|
|
|
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym))
|
|
|
|
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE)
|
|
|
|
sym->st_shndx = backmap[sym->st_shndx];
|
|
|
|
}
|
2017-01-23 08:11:38 +08:00
|
|
|
for (i = 0; i < s1->nb_sections; i++)
|
|
|
|
sec_order[i] = i;
|
|
|
|
tcc_free(s1->sections);
|
|
|
|
s1->sections = snew;
|
|
|
|
s1->nb_sections = nnew;
|
|
|
|
tcc_free(backmap);
|
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2017-01-23 08:11:38 +08:00
|
|
|
|
2020-08-04 15:15:42 +08:00
|
|
|
#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
|
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Output an elf, coff or binary file */
|
|
|
|
/* XXX: suppress unneeded sections */
|
|
|
|
static int elf_output_file(TCCState *s1, const char *filename)
|
|
|
|
{
|
2019-12-10 03:32:13 +08:00
|
|
|
int ret, phnum, shnum, file_type, file_offset, *sec_order;
|
2017-02-14 01:23:43 +08:00
|
|
|
struct dyn_inf dyninf = {0};
|
2013-12-18 11:17:17 +08:00
|
|
|
ElfW(Phdr) *phdr;
|
|
|
|
Section *strsec, *interp, *dynamic, *dynstr;
|
|
|
|
|
2020-08-04 15:15:42 +08:00
|
|
|
#ifdef TCC_TARGET_ARM
|
|
|
|
create_arm_attribute_section (s1);
|
|
|
|
#endif
|
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
file_type = s1->output_type;
|
|
|
|
s1->nb_errors = 0;
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
ret = -1;
|
2013-12-18 11:17:17 +08:00
|
|
|
phdr = NULL;
|
|
|
|
sec_order = NULL;
|
|
|
|
interp = dynamic = dynstr = NULL; /* avoid warning */
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2013-12-18 11:17:17 +08:00
|
|
|
if (file_type != TCC_OUTPUT_OBJ) {
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
/* if linking, also link in runtime libraries (libc, libgcc, etc.) */
|
|
|
|
tcc_add_runtime(s1);
|
2017-12-13 00:33:37 +08:00
|
|
|
resolve_common_syms(s1);
|
2013-12-18 11:17:17 +08:00
|
|
|
|
|
|
|
if (!s1->static_link) {
|
|
|
|
if (file_type == TCC_OUTPUT_EXE) {
|
|
|
|
char *ptr;
|
|
|
|
/* allow override the dynamic loader */
|
|
|
|
const char *elfint = getenv("LD_SO");
|
|
|
|
if (elfint == NULL)
|
|
|
|
elfint = DEFAULT_ELFINTERP(s1);
|
|
|
|
/* add interpreter section only if executable */
|
|
|
|
interp = new_section(s1, ".interp", SHT_PROGBITS, SHF_ALLOC);
|
|
|
|
interp->sh_addralign = 1;
|
|
|
|
ptr = section_ptr_add(interp, 1 + strlen(elfint));
|
|
|
|
strcpy(ptr, elfint);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* add dynamic symbol table */
|
|
|
|
s1->dynsym = new_symtab(s1, ".dynsym", SHT_DYNSYM, SHF_ALLOC,
|
|
|
|
".dynstr",
|
|
|
|
".hash", SHF_ALLOC);
|
|
|
|
dynstr = s1->dynsym->link;
|
|
|
|
/* add dynamic section */
|
|
|
|
dynamic = new_section(s1, ".dynamic", SHT_DYNAMIC,
|
|
|
|
SHF_ALLOC | SHF_WRITE);
|
|
|
|
dynamic->link = dynstr;
|
|
|
|
dynamic->sh_entsize = sizeof(ElfW(Dyn));
|
|
|
|
|
|
|
|
build_got(s1);
|
|
|
|
|
|
|
|
if (file_type == TCC_OUTPUT_EXE) {
|
|
|
|
bind_exe_dynsyms(s1);
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (s1->nb_errors)
|
2013-12-18 11:17:17 +08:00
|
|
|
goto the_end;
|
|
|
|
bind_libs_dynsyms(s1);
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
} else {
|
|
|
|
/* shared library case: simply export all global symbols */
|
2013-12-18 11:17:17 +08:00
|
|
|
export_global_syms(s1);
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
build_got_entries(s1);
|
2019-10-22 22:55:20 +08:00
|
|
|
version_add (s1);
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
|
|
|
|
/* we add a section for symbols */
|
|
|
|
strsec = new_section(s1, ".shstrtab", SHT_STRTAB, 0);
|
|
|
|
put_elf_str(strsec, "");
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
/* Allocate strings for section names */
|
2019-12-10 03:32:13 +08:00
|
|
|
ret = alloc_sec_names(s1, file_type, strsec);
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (dynamic) {
|
2019-12-10 03:32:13 +08:00
|
|
|
int i;
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
/* add a list of needed dlls */
|
|
|
|
for(i = 0; i < s1->nb_loaded_dlls; i++) {
|
|
|
|
DLLReference *dllref = s1->loaded_dlls[i];
|
|
|
|
if (dllref->level == 0)
|
|
|
|
put_dt(dynamic, DT_NEEDED, put_elf_str(dynstr, dllref->name));
|
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (s1->rpath)
|
|
|
|
put_dt(dynamic, s1->enable_new_dtags ? DT_RUNPATH : DT_RPATH,
|
|
|
|
put_elf_str(dynstr, s1->rpath));
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (file_type == TCC_OUTPUT_DLL) {
|
|
|
|
if (s1->soname)
|
|
|
|
put_dt(dynamic, DT_SONAME, put_elf_str(dynstr, s1->soname));
|
2013-12-18 11:17:17 +08:00
|
|
|
/* XXX: currently, since we do not handle PIC code, we
|
|
|
|
must relocate the readonly segments */
|
2019-12-10 03:32:13 +08:00
|
|
|
if (ret)
|
2013-12-18 11:17:17 +08:00
|
|
|
put_dt(dynamic, DT_TEXTREL, 0);
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
}
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (s1->symbolic)
|
|
|
|
put_dt(dynamic, DT_SYMBOLIC, 0);
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
dyninf.dynamic = dynamic;
|
|
|
|
dyninf.dynstr = dynstr;
|
|
|
|
/* remember offset and reserve space for 2nd call below */
|
|
|
|
dyninf.data_offset = dynamic->data_offset;
|
|
|
|
fill_dynamic(s1, &dyninf);
|
|
|
|
dynamic->sh_size = dynamic->data_offset;
|
|
|
|
dynstr->sh_size = dynstr->data_offset;
|
2013-12-18 11:17:17 +08:00
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
/* compute number of program headers */
|
|
|
|
if (file_type == TCC_OUTPUT_OBJ)
|
|
|
|
phnum = 0;
|
|
|
|
else if (file_type == TCC_OUTPUT_DLL)
|
|
|
|
phnum = 3;
|
|
|
|
else if (s1->static_link)
|
|
|
|
phnum = 2;
|
2020-09-08 20:31:58 +08:00
|
|
|
else {
|
|
|
|
int i;
|
|
|
|
for (i = 1; i < s1->nb_sections &&
|
|
|
|
!(s1->sections[i]->sh_flags & SHF_TLS); i++);
|
|
|
|
phnum = i < s1->nb_sections ? 6 : 5;
|
|
|
|
}
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
|
|
|
|
/* allocate program segment headers */
|
|
|
|
phdr = tcc_mallocz(phnum * sizeof(ElfW(Phdr)));
|
2013-12-18 11:17:17 +08:00
|
|
|
|
|
|
|
/* compute number of sections */
|
|
|
|
shnum = s1->nb_sections;
|
|
|
|
|
|
|
|
/* this array is used to reorder sections in the output file */
|
|
|
|
sec_order = tcc_malloc(sizeof(int) * shnum);
|
|
|
|
sec_order[0] = 0;
|
|
|
|
|
|
|
|
/* compute section to program header mapping */
|
2014-09-07 23:29:38 +08:00
|
|
|
file_offset = layout_sections(s1, phdr, phnum, interp, strsec, &dyninf,
|
|
|
|
sec_order);
|
2013-12-18 11:17:17 +08:00
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2013-12-18 11:17:17 +08:00
|
|
|
/* Fill remaining program header and finalize relocation related to dynamic
|
|
|
|
linking. */
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
if (file_type != TCC_OUTPUT_OBJ) {
|
2013-12-18 11:17:17 +08:00
|
|
|
fill_unloadable_phdr(phdr, phnum, interp, dynamic);
|
|
|
|
if (dynamic) {
|
2019-12-10 03:32:13 +08:00
|
|
|
ElfW(Sym) *sym;
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
dynamic->data_offset = dyninf.data_offset;
|
2013-12-18 11:17:17 +08:00
|
|
|
fill_dynamic(s1, &dyninf);
|
|
|
|
|
|
|
|
/* put in GOT the dynamic section address and relocate PLT */
|
2015-11-20 02:21:14 +08:00
|
|
|
write32le(s1->got->data, dynamic->sh_addr);
|
2013-12-18 11:17:17 +08:00
|
|
|
if (file_type == TCC_OUTPUT_EXE
|
2016-12-16 00:01:22 +08:00
|
|
|
|| (RELOCATE_DLLPLT && file_type == TCC_OUTPUT_DLL))
|
2013-12-18 11:17:17 +08:00
|
|
|
relocate_plt(s1);
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2013-12-18 11:17:17 +08:00
|
|
|
/* relocate symbols in .dynsym now that final addresses are known */
|
|
|
|
for_each_elem(s1->dynsym, 1, sym, ElfW(Sym)) {
|
2016-12-16 00:01:22 +08:00
|
|
|
if (sym->st_shndx != SHN_UNDEF && sym->st_shndx < SHN_LORESERVE) {
|
2013-12-18 11:17:17 +08:00
|
|
|
/* do symbol relocation */
|
|
|
|
sym->st_value += s1->sections[sym->st_shndx]->sh_addr;
|
|
|
|
}
|
2004-10-24 06:53:42 +08:00
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
/* if building executable or DLL, then relocate each section
|
|
|
|
except the GOT which is already relocated */
|
2013-12-18 11:17:17 +08:00
|
|
|
ret = final_sections_reloc(s1);
|
|
|
|
if (ret)
|
|
|
|
goto the_end;
|
2017-01-23 08:11:38 +08:00
|
|
|
tidy_section_headers(s1, sec_order);
|
2013-12-18 11:17:17 +08:00
|
|
|
|
various stuff
win32/Makefile ("for cygwin") removed
- On cygwin, the normal ./configure && make can be used with either
cygwin's "GCC for Win32 Toolchain"
./configure --cross-prefix=i686-w64-mingw32-
or with an existing tcc:
./configure --cc=<old-tccdir>/tcc.exe
tcctest.c:
- exclude test_high_clobbers() on _WIN64 (does not work)
tests2/95_bitfield.c:
- use 'signed char' for ARM (where default 'char' is unsigned)
tests:
- remove -I "expr" diff option to allow tests with
busybox-diff.
libtcc.c, tcc.c:
- removed -iwithprefix option. It is supposed to be
combined with -iprefix which we don't have either.
tccgen.c:
- fix assignments and return of 'void', as in
void f() {
void *p, *q;
*p = *q:
return *p;
}
This appears to be allowed but should do nothing.
tcc.h, libtcc.c, tccpp.c:
- Revert "Introduce VIP sysinclude paths which are always searched first"
This reverts commit 1d5e386b0a78393ac6b670c209a185849ec798a1.
The patch was giving tcc's system includes priority over -I which
is not how it should be.
tccelf.c:
- add DT_TEXTREL tag only if text relocations are actually
used (which is likely not the case on x86_64)
- prepare_dynamic_rel(): avoid relocation of unresolved
(weak) symbols
tccrun.c:
- for HAVE_SELINUX, use two mappings to the same (real) file.
(it was so once except the RX mapping wasn't used at all).
tccpe.c:
- fix relocation constant used for x86_64 (by Andrei E. Warentin)
- #ifndef _WIN32 do "chmod 755 ..." to get runnable exes on cygwin.
tccasm.c:
- keep forward asm labels static, otherwise they will endup
in dynsym eventually.
configure, Makefile:
- mingw32: respect ./configure options --bindir --docdir --libdir
- allow overriding tcc when building libtcc1.a and libtcc.def with
make XTCC=<tcc program to use>
- use $(wildcard ...) for install to allow installing just
a cross compiler for example
make cross-arm
make install
- use name <target>-libtcc1.a
build-tcc.bat:
- add options: -clean, -b bindir
2017-10-12 00:13:43 +08:00
|
|
|
/* Perform relocation to GOT or PLT entries */
|
|
|
|
if (file_type == TCC_OUTPUT_EXE && s1->static_link)
|
|
|
|
fill_got(s1);
|
|
|
|
else if (s1->got)
|
|
|
|
fill_local_got_entries(s1);
|
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif
|
2013-12-18 11:17:17 +08:00
|
|
|
|
|
|
|
/* Create the ELF file with name 'filename' */
|
|
|
|
ret = tcc_write_elf_file(s1, filename, phnum, phdr, file_offset, sec_order);
|
2017-01-23 08:11:38 +08:00
|
|
|
s1->nb_sections = shnum;
|
2019-12-10 03:32:13 +08:00
|
|
|
goto the_end;
|
2002-11-02 22:13:21 +08:00
|
|
|
the_end:
|
2013-12-18 11:17:17 +08:00
|
|
|
tcc_free(sec_order);
|
2002-08-18 21:17:59 +08:00
|
|
|
tcc_free(phdr);
|
2002-11-02 22:13:21 +08:00
|
|
|
return ret;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2009-12-20 08:53:49 +08:00
|
|
|
LIBTCCAPI int tcc_output_file(TCCState *s, const char *filename)
|
2008-05-06 06:39:43 +08:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
#ifdef TCC_TARGET_PE
|
|
|
|
if (s->output_type != TCC_OUTPUT_OBJ) {
|
|
|
|
ret = pe_output_file(s, filename);
|
|
|
|
} else
|
2020-05-15 09:46:55 +08:00
|
|
|
#elif TCC_TARGET_MACHO
|
|
|
|
if (s->output_type != TCC_OUTPUT_OBJ) {
|
|
|
|
ret = macho_output_file(s, filename);
|
|
|
|
} else
|
2008-05-06 06:39:43 +08:00
|
|
|
#endif
|
|
|
|
ret = elf_output_file(s, filename);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2020-05-25 23:27:01 +08:00
|
|
|
ST_FUNC ssize_t full_read(int fd, void *buf, size_t count) {
|
2019-01-13 17:29:25 +08:00
|
|
|
char *cbuf = buf;
|
|
|
|
size_t rnum = 0;
|
|
|
|
while (1) {
|
|
|
|
ssize_t num = read(fd, cbuf, count-rnum);
|
|
|
|
if (num < 0) return num;
|
|
|
|
if (num == 0) return rnum;
|
|
|
|
rnum += num;
|
|
|
|
cbuf += num;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-25 23:27:01 +08:00
|
|
|
ST_FUNC void *load_data(int fd, unsigned long file_offset, unsigned long size)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
void *data;
|
|
|
|
|
|
|
|
data = tcc_malloc(size);
|
2013-01-15 00:34:07 +08:00
|
|
|
lseek(fd, file_offset, SEEK_SET);
|
2019-01-13 17:29:25 +08:00
|
|
|
full_read(fd, data, size);
|
2002-08-18 21:17:59 +08:00
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct SectionMergeInfo {
|
|
|
|
Section *s; /* corresponding existing section */
|
|
|
|
unsigned long offset; /* offset of the new section in the existing section */
|
2003-10-04 22:45:23 +08:00
|
|
|
uint8_t new_section; /* true if section 's' was added */
|
|
|
|
uint8_t link_once; /* true if link once section */
|
2002-08-18 21:17:59 +08:00
|
|
|
} SectionMergeInfo;
|
|
|
|
|
2016-10-02 02:54:45 +08:00
|
|
|
ST_FUNC int tcc_object_type(int fd, ElfW(Ehdr) *h)
|
|
|
|
{
|
2019-01-13 17:29:25 +08:00
|
|
|
int size = full_read(fd, h, sizeof *h);
|
2016-10-02 02:54:45 +08:00
|
|
|
if (size == sizeof *h && 0 == memcmp(h, ELFMAG, 4)) {
|
|
|
|
if (h->e_type == ET_REL)
|
|
|
|
return AFF_BINTYPE_REL;
|
|
|
|
if (h->e_type == ET_DYN)
|
|
|
|
return AFF_BINTYPE_DYN;
|
|
|
|
} else if (size >= 8) {
|
|
|
|
if (0 == memcmp(h, ARMAG, 8))
|
|
|
|
return AFF_BINTYPE_AR;
|
|
|
|
#ifdef TCC_TARGET_COFF
|
|
|
|
if (((struct filehdr*)h)->f_magic == COFF_C67_MAGIC)
|
|
|
|
return AFF_BINTYPE_C67;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* load an object file and merge it with current files */
|
|
|
|
/* XXX: handle correctly stab (debug) info */
|
2013-12-17 20:59:14 +08:00
|
|
|
ST_FUNC int tcc_load_object_file(TCCState *s1,
|
2013-01-15 00:34:07 +08:00
|
|
|
int fd, unsigned long file_offset)
|
2013-12-17 20:59:14 +08:00
|
|
|
{
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Ehdr) ehdr;
|
|
|
|
ElfW(Shdr) *shdr, *sh;
|
2017-05-06 13:30:44 +08:00
|
|
|
int size, i, j, offset, offseti, nb_syms, sym_index, ret, seencompressed;
|
2019-01-05 07:10:37 +08:00
|
|
|
char *strsec, *strtab;
|
2019-12-14 19:36:12 +08:00
|
|
|
int stab_index, stabstr_index;
|
2002-08-18 21:17:59 +08:00
|
|
|
int *old_to_new_syms;
|
|
|
|
char *sh_name, *name;
|
|
|
|
SectionMergeInfo *sm_table, *sm;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym, *symtab;
|
2013-12-17 21:02:51 +08:00
|
|
|
ElfW_Rel *rel;
|
2002-08-18 21:17:59 +08:00
|
|
|
Section *s;
|
|
|
|
|
2016-10-02 02:54:45 +08:00
|
|
|
lseek(fd, file_offset, SEEK_SET);
|
|
|
|
if (tcc_object_type(fd, &ehdr) != AFF_BINTYPE_REL)
|
2002-11-02 22:13:21 +08:00
|
|
|
goto fail1;
|
2002-08-18 21:17:59 +08:00
|
|
|
/* test CPU specific stuff */
|
|
|
|
if (ehdr.e_ident[5] != ELFDATA2LSB ||
|
2003-10-15 06:15:56 +08:00
|
|
|
ehdr.e_machine != EM_TCC_TARGET) {
|
2002-11-02 22:13:21 +08:00
|
|
|
fail1:
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("invalid object file");
|
2002-11-02 22:13:21 +08:00
|
|
|
return -1;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
/* read sections */
|
2013-12-17 20:59:14 +08:00
|
|
|
shdr = load_data(fd, file_offset + ehdr.e_shoff,
|
2008-11-30 07:14:07 +08:00
|
|
|
sizeof(ElfW(Shdr)) * ehdr.e_shnum);
|
2002-08-18 21:17:59 +08:00
|
|
|
sm_table = tcc_mallocz(sizeof(SectionMergeInfo) * ehdr.e_shnum);
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* load section names */
|
|
|
|
sh = &shdr[ehdr.e_shstrndx];
|
|
|
|
strsec = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
|
|
|
|
|
|
|
|
/* load symtab and strtab */
|
2002-11-02 22:13:21 +08:00
|
|
|
old_to_new_syms = NULL;
|
2002-08-18 21:17:59 +08:00
|
|
|
symtab = NULL;
|
|
|
|
strtab = NULL;
|
|
|
|
nb_syms = 0;
|
2017-05-06 13:30:44 +08:00
|
|
|
seencompressed = 0;
|
2019-12-14 19:36:12 +08:00
|
|
|
stab_index = stabstr_index = 0;
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
for(i = 1; i < ehdr.e_shnum; i++) {
|
|
|
|
sh = &shdr[i];
|
|
|
|
if (sh->sh_type == SHT_SYMTAB) {
|
2002-11-02 22:13:21 +08:00
|
|
|
if (symtab) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("object must contain only one symtab");
|
2002-11-02 22:13:21 +08:00
|
|
|
fail:
|
|
|
|
ret = -1;
|
|
|
|
goto the_end;
|
|
|
|
}
|
2008-11-30 07:14:07 +08:00
|
|
|
nb_syms = sh->sh_size / sizeof(ElfW(Sym));
|
2002-08-18 21:17:59 +08:00
|
|
|
symtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
|
|
|
|
sm_table[i].s = symtab_section;
|
|
|
|
|
|
|
|
/* now load strtab */
|
|
|
|
sh = &shdr[sh->sh_link];
|
|
|
|
strtab = load_data(fd, file_offset + sh->sh_offset, sh->sh_size);
|
|
|
|
}
|
2017-05-06 13:30:44 +08:00
|
|
|
if (sh->sh_flags & SHF_COMPRESSED)
|
|
|
|
seencompressed = 1;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* now examine each section and try to merge its content with the
|
|
|
|
ones in memory */
|
|
|
|
for(i = 1; i < ehdr.e_shnum; i++) {
|
|
|
|
/* no need to examine section name strtab */
|
|
|
|
if (i == ehdr.e_shstrndx)
|
|
|
|
continue;
|
|
|
|
sh = &shdr[i];
|
2019-01-05 07:10:37 +08:00
|
|
|
if (sh->sh_type == SHT_RELX)
|
|
|
|
sh = &shdr[sh->sh_info];
|
|
|
|
/* ignore sections types we do not handle (plus relocs to those) */
|
2002-08-18 21:17:59 +08:00
|
|
|
if (sh->sh_type != SHT_PROGBITS &&
|
2007-12-05 04:38:09 +08:00
|
|
|
#ifdef TCC_ARM_EABI
|
2007-12-20 01:36:42 +08:00
|
|
|
sh->sh_type != SHT_ARM_EXIDX &&
|
2007-12-05 04:38:09 +08:00
|
|
|
#endif
|
2013-12-17 20:59:14 +08:00
|
|
|
sh->sh_type != SHT_NOBITS &&
|
2010-05-15 07:26:56 +08:00
|
|
|
sh->sh_type != SHT_PREINIT_ARRAY &&
|
|
|
|
sh->sh_type != SHT_INIT_ARRAY &&
|
|
|
|
sh->sh_type != SHT_FINI_ARRAY &&
|
2019-01-05 07:10:37 +08:00
|
|
|
strcmp(strsec + sh->sh_name, ".stabstr")
|
2008-04-28 02:49:31 +08:00
|
|
|
)
|
2002-08-18 21:17:59 +08:00
|
|
|
continue;
|
2017-05-06 13:30:44 +08:00
|
|
|
if (seencompressed
|
2019-01-05 07:10:37 +08:00
|
|
|
&& !strncmp(strsec + sh->sh_name, ".debug_", sizeof(".debug_")-1))
|
2017-05-06 13:30:44 +08:00
|
|
|
continue;
|
2019-01-05 07:10:37 +08:00
|
|
|
|
|
|
|
sh = &shdr[i];
|
|
|
|
sh_name = strsec + sh->sh_name;
|
2002-08-18 21:17:59 +08:00
|
|
|
if (sh->sh_addralign < 1)
|
|
|
|
sh->sh_addralign = 1;
|
|
|
|
/* find corresponding section, if any */
|
2002-11-02 22:13:21 +08:00
|
|
|
for(j = 1; j < s1->nb_sections;j++) {
|
|
|
|
s = s1->sections[j];
|
2003-10-04 22:45:23 +08:00
|
|
|
if (!strcmp(s->name, sh_name)) {
|
2013-12-17 20:59:14 +08:00
|
|
|
if (!strncmp(sh_name, ".gnu.linkonce",
|
2003-10-04 22:45:23 +08:00
|
|
|
sizeof(".gnu.linkonce") - 1)) {
|
|
|
|
/* if a 'linkonce' section is already present, we
|
|
|
|
do not add it again. It is a little tricky as
|
|
|
|
symbols can still be defined in
|
|
|
|
it. */
|
|
|
|
sm_table[i].link_once = 1;
|
|
|
|
goto next;
|
|
|
|
}
|
2019-12-14 19:36:12 +08:00
|
|
|
if (stab_section) {
|
|
|
|
if (s == stab_section)
|
|
|
|
stab_index = i;
|
|
|
|
if (s == stab_section->link)
|
|
|
|
stabstr_index = i;
|
|
|
|
}
|
|
|
|
goto found;
|
2003-10-04 22:45:23 +08:00
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
/* not found: create new section */
|
2016-11-26 05:29:01 +08:00
|
|
|
s = new_section(s1, sh_name, sh->sh_type, sh->sh_flags & ~SHF_GROUP);
|
2002-08-18 21:17:59 +08:00
|
|
|
/* take as much info as possible from the section. sh_link and
|
|
|
|
sh_info will be updated later */
|
|
|
|
s->sh_addralign = sh->sh_addralign;
|
|
|
|
s->sh_entsize = sh->sh_entsize;
|
|
|
|
sm_table[i].new_section = 1;
|
|
|
|
found:
|
2002-11-02 22:13:21 +08:00
|
|
|
if (sh->sh_type != s->sh_type) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("invalid section type");
|
2002-08-18 21:17:59 +08:00
|
|
|
goto fail;
|
2002-11-02 22:13:21 +08:00
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
/* align start of section */
|
2019-12-14 19:36:12 +08:00
|
|
|
s->data_offset += -s->data_offset & (sh->sh_addralign - 1);
|
2002-08-18 21:17:59 +08:00
|
|
|
if (sh->sh_addralign > s->sh_addralign)
|
|
|
|
s->sh_addralign = sh->sh_addralign;
|
2019-12-14 19:36:12 +08:00
|
|
|
sm_table[i].offset = s->data_offset;
|
2002-08-18 21:17:59 +08:00
|
|
|
sm_table[i].s = s;
|
|
|
|
/* concatenate sections */
|
|
|
|
size = sh->sh_size;
|
|
|
|
if (sh->sh_type != SHT_NOBITS) {
|
|
|
|
unsigned char *ptr;
|
2013-01-15 00:34:07 +08:00
|
|
|
lseek(fd, file_offset + sh->sh_offset, SEEK_SET);
|
2002-08-18 22:34:57 +08:00
|
|
|
ptr = section_ptr_add(s, size);
|
2019-01-13 17:29:25 +08:00
|
|
|
full_read(fd, ptr, size);
|
2002-08-18 22:34:57 +08:00
|
|
|
} else {
|
|
|
|
s->data_offset += size;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2003-10-04 22:45:23 +08:00
|
|
|
next: ;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2013-12-17 20:59:14 +08:00
|
|
|
/* gr relocate stab strings */
|
2008-04-28 02:49:31 +08:00
|
|
|
if (stab_index && stabstr_index) {
|
|
|
|
Stab_Sym *a, *b;
|
|
|
|
unsigned o;
|
|
|
|
s = sm_table[stab_index].s;
|
|
|
|
a = (Stab_Sym *)(s->data + sm_table[stab_index].offset);
|
|
|
|
b = (Stab_Sym *)(s->data + s->data_offset);
|
|
|
|
o = sm_table[stabstr_index].offset;
|
2018-06-01 05:51:51 +08:00
|
|
|
while (a < b) {
|
|
|
|
if (a->n_strx)
|
|
|
|
a->n_strx += o;
|
|
|
|
a++;
|
|
|
|
}
|
2008-04-28 02:49:31 +08:00
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* second short pass to update sh_link and sh_info fields of new
|
|
|
|
sections */
|
|
|
|
for(i = 1; i < ehdr.e_shnum; i++) {
|
|
|
|
s = sm_table[i].s;
|
|
|
|
if (!s || !sm_table[i].new_section)
|
|
|
|
continue;
|
|
|
|
sh = &shdr[i];
|
|
|
|
if (sh->sh_link > 0)
|
|
|
|
s->link = sm_table[sh->sh_link].s;
|
2008-11-30 07:14:07 +08:00
|
|
|
if (sh->sh_type == SHT_RELX) {
|
2019-06-17 04:50:06 +08:00
|
|
|
s->sh_info = sm_table[sh->sh_info].s->sh_num;
|
|
|
|
/* update backward link */
|
|
|
|
s1->sections[s->sh_info]->reloc = s;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* resolve symbols */
|
|
|
|
old_to_new_syms = tcc_mallocz(nb_syms * sizeof(int));
|
|
|
|
|
|
|
|
sym = symtab + 1;
|
|
|
|
for(i = 1; i < nb_syms; i++, sym++) {
|
|
|
|
if (sym->st_shndx != SHN_UNDEF &&
|
|
|
|
sym->st_shndx < SHN_LORESERVE) {
|
|
|
|
sm = &sm_table[sym->st_shndx];
|
2003-10-04 22:45:23 +08:00
|
|
|
if (sm->link_once) {
|
|
|
|
/* if a symbol is in a link once section, we use the
|
|
|
|
already defined symbol. It is very important to get
|
|
|
|
correct relocations */
|
2008-11-30 07:14:07 +08:00
|
|
|
if (ELFW(ST_BIND)(sym->st_info) != STB_LOCAL) {
|
2019-01-05 07:10:37 +08:00
|
|
|
name = strtab + sym->st_name;
|
2003-10-04 22:45:23 +08:00
|
|
|
sym_index = find_elf_sym(symtab_section, name);
|
|
|
|
if (sym_index)
|
|
|
|
old_to_new_syms[i] = sym_index;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
/* if no corresponding section added, no need to add symbol */
|
|
|
|
if (!sm->s)
|
|
|
|
continue;
|
|
|
|
/* convert section number */
|
|
|
|
sym->st_shndx = sm->s->sh_num;
|
|
|
|
/* offset value */
|
|
|
|
sym->st_value += sm->offset;
|
|
|
|
}
|
|
|
|
/* add symbol */
|
2019-01-05 07:10:37 +08:00
|
|
|
name = strtab + sym->st_name;
|
2016-11-12 23:16:04 +08:00
|
|
|
sym_index = set_elf_sym(symtab_section, sym->st_value, sym->st_size,
|
2013-12-17 20:59:14 +08:00
|
|
|
sym->st_info, sym->st_other,
|
2005-04-14 05:37:06 +08:00
|
|
|
sym->st_shndx, name);
|
2002-08-18 21:17:59 +08:00
|
|
|
old_to_new_syms[i] = sym_index;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* third pass to patch relocation entries */
|
|
|
|
for(i = 1; i < ehdr.e_shnum; i++) {
|
|
|
|
s = sm_table[i].s;
|
|
|
|
if (!s)
|
|
|
|
continue;
|
|
|
|
sh = &shdr[i];
|
|
|
|
offset = sm_table[i].offset;
|
|
|
|
switch(s->sh_type) {
|
2008-11-30 07:14:07 +08:00
|
|
|
case SHT_RELX:
|
2002-08-18 21:17:59 +08:00
|
|
|
/* take relocation offset information */
|
|
|
|
offseti = sm_table[sh->sh_info].offset;
|
2013-12-17 21:02:51 +08:00
|
|
|
for_each_elem(s, (offset / sizeof(*rel)), rel, ElfW_Rel) {
|
2002-08-18 21:17:59 +08:00
|
|
|
int type;
|
|
|
|
unsigned sym_index;
|
|
|
|
/* convert symbol index */
|
2008-11-30 07:14:07 +08:00
|
|
|
type = ELFW(R_TYPE)(rel->r_info);
|
|
|
|
sym_index = ELFW(R_SYM)(rel->r_info);
|
2002-08-18 21:17:59 +08:00
|
|
|
/* NOTE: only one symtab assumed */
|
|
|
|
if (sym_index >= nb_syms)
|
|
|
|
goto invalid_reloc;
|
|
|
|
sym_index = old_to_new_syms[sym_index];
|
2007-11-22 01:16:31 +08:00
|
|
|
/* ignore link_once in rel section. */
|
2019-12-14 19:36:12 +08:00
|
|
|
if (!sym_index && !sm_table[sh->sh_info].link_once
|
2010-05-15 07:23:34 +08:00
|
|
|
#ifdef TCC_TARGET_ARM
|
|
|
|
&& type != R_ARM_V4BX
|
2019-06-23 08:10:10 +08:00
|
|
|
#elif defined TCC_TARGET_RISCV64
|
|
|
|
&& type != R_RISCV_ALIGN
|
|
|
|
&& type != R_RISCV_RELAX
|
2010-05-15 07:23:34 +08:00
|
|
|
#endif
|
|
|
|
) {
|
2002-08-18 21:17:59 +08:00
|
|
|
invalid_reloc:
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("Invalid relocation entry [%2d] '%s' @ %.8x",
|
2020-05-05 15:00:24 +08:00
|
|
|
i, strsec + sh->sh_name, (int)rel->r_offset);
|
2002-11-02 22:13:21 +08:00
|
|
|
goto fail;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2008-11-30 07:14:07 +08:00
|
|
|
rel->r_info = ELFW(R_INFO)(sym_index, type);
|
2002-08-18 21:17:59 +08:00
|
|
|
/* offset the relocation offset */
|
|
|
|
rel->r_offset += offseti;
|
2012-11-04 07:40:05 +08:00
|
|
|
#ifdef TCC_TARGET_ARM
|
|
|
|
/* Jumps and branches from a Thumb code to a PLT entry need
|
|
|
|
special handling since PLT entries are ARM code.
|
|
|
|
Unconditional bl instructions referencing PLT entries are
|
|
|
|
handled by converting these instructions into blx
|
|
|
|
instructions. Other case of instructions referencing a PLT
|
|
|
|
entry require to add a Thumb stub before the PLT entry to
|
2013-12-18 11:17:17 +08:00
|
|
|
switch to ARM mode. We set bit plt_thumb_stub of the
|
|
|
|
attribute of a symbol to indicate such a case. */
|
2012-11-04 07:40:05 +08:00
|
|
|
if (type == R_ARM_THM_JUMP24)
|
2016-11-12 23:16:07 +08:00
|
|
|
get_sym_attr(s1, sym_index, 1)->plt_thumb_stub = 1;
|
2012-11-04 07:40:05 +08:00
|
|
|
#endif
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-11-02 22:13:21 +08:00
|
|
|
ret = 0;
|
|
|
|
the_end:
|
2002-08-18 21:17:59 +08:00
|
|
|
tcc_free(symtab);
|
|
|
|
tcc_free(strtab);
|
|
|
|
tcc_free(old_to_new_syms);
|
|
|
|
tcc_free(sm_table);
|
2002-11-02 22:13:21 +08:00
|
|
|
tcc_free(strsec);
|
2002-08-18 21:17:59 +08:00
|
|
|
tcc_free(shdr);
|
2002-11-02 22:13:21 +08:00
|
|
|
return ret;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
typedef struct ArchiveHeader {
|
2007-12-20 01:36:42 +08:00
|
|
|
char ar_name[16]; /* name of this member */
|
|
|
|
char ar_date[12]; /* file mtime */
|
|
|
|
char ar_uid[6]; /* owner uid; printed as decimal */
|
|
|
|
char ar_gid[6]; /* owner gid; printed as decimal */
|
|
|
|
char ar_mode[8]; /* file mode, printed as octal */
|
|
|
|
char ar_size[10]; /* file size, printed as decimal */
|
|
|
|
char ar_fmag[2]; /* should contain ARFMAG */
|
2002-08-18 21:17:59 +08:00
|
|
|
} ArchiveHeader;
|
|
|
|
|
2019-12-11 03:50:45 +08:00
|
|
|
#define ARFMAG "`\n"
|
|
|
|
|
|
|
|
static unsigned long long get_be(const uint8_t *b, int n)
|
2003-04-29 06:06:38 +08:00
|
|
|
{
|
2019-12-11 03:50:45 +08:00
|
|
|
unsigned long long ret = 0;
|
|
|
|
while (n)
|
|
|
|
ret = (ret << 8) | *b++, --n;
|
|
|
|
return ret;
|
2003-04-29 06:06:38 +08:00
|
|
|
}
|
|
|
|
|
2019-12-11 03:50:45 +08:00
|
|
|
static int read_ar_header(int fd, int offset, ArchiveHeader *hdr)
|
2016-10-14 22:44:41 +08:00
|
|
|
{
|
2019-12-11 03:50:45 +08:00
|
|
|
char *p, *e;
|
|
|
|
int len;
|
|
|
|
lseek(fd, offset, SEEK_SET);
|
|
|
|
len = full_read(fd, hdr, sizeof(ArchiveHeader));
|
|
|
|
if (len != sizeof(ArchiveHeader))
|
|
|
|
return len ? -1 : 0;
|
|
|
|
p = hdr->ar_name;
|
|
|
|
for (e = p + sizeof hdr->ar_name; e > p && e[-1] == ' ';)
|
|
|
|
--e;
|
|
|
|
*e = '\0';
|
|
|
|
hdr->ar_size[sizeof hdr->ar_size-1] = 0;
|
|
|
|
return len;
|
2016-10-14 22:44:41 +08:00
|
|
|
}
|
|
|
|
|
2003-04-29 06:06:38 +08:00
|
|
|
/* load only the objects which resolve undefined symbols */
|
2016-10-14 22:44:41 +08:00
|
|
|
static int tcc_load_alacarte(TCCState *s1, int fd, int size, int entrysize)
|
2003-04-29 06:06:38 +08:00
|
|
|
{
|
2019-12-11 03:50:45 +08:00
|
|
|
int i, bound, nsyms, sym_index, len, ret = -1;
|
|
|
|
unsigned long long off;
|
2003-04-29 06:06:38 +08:00
|
|
|
uint8_t *data;
|
|
|
|
const char *ar_names, *p;
|
|
|
|
const uint8_t *ar_index;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym;
|
2019-12-11 03:50:45 +08:00
|
|
|
ArchiveHeader hdr;
|
2003-04-29 06:06:38 +08:00
|
|
|
|
|
|
|
data = tcc_malloc(size);
|
2019-01-13 17:29:25 +08:00
|
|
|
if (full_read(fd, data, size) != size)
|
2019-12-11 03:50:45 +08:00
|
|
|
goto the_end;
|
|
|
|
nsyms = get_be(data, entrysize);
|
2016-10-14 22:44:41 +08:00
|
|
|
ar_index = data + entrysize;
|
|
|
|
ar_names = (char *) ar_index + nsyms * entrysize;
|
2003-04-29 06:06:38 +08:00
|
|
|
|
|
|
|
do {
|
2007-12-20 01:36:42 +08:00
|
|
|
bound = 0;
|
2019-12-11 03:50:45 +08:00
|
|
|
for (p = ar_names, i = 0; i < nsyms; i++, p += strlen(p)+1) {
|
|
|
|
Section *s = symtab_section;
|
2019-12-10 15:07:25 +08:00
|
|
|
sym_index = find_elf_sym(s, p);
|
2019-12-11 03:50:45 +08:00
|
|
|
if (!sym_index)
|
|
|
|
continue;
|
|
|
|
sym = &((ElfW(Sym) *)s->data)[sym_index];
|
|
|
|
if(sym->st_shndx != SHN_UNDEF)
|
|
|
|
continue;
|
|
|
|
off = get_be(ar_index + i * entrysize, entrysize);
|
|
|
|
len = read_ar_header(fd, off, &hdr);
|
|
|
|
if (len <= 0 || memcmp(hdr.ar_fmag, ARFMAG, 2)) {
|
|
|
|
tcc_error_noabort("invalid archive");
|
|
|
|
goto the_end;
|
2007-12-20 01:36:42 +08:00
|
|
|
}
|
2019-12-11 03:50:45 +08:00
|
|
|
off += len;
|
|
|
|
if (s1->verbose == 2)
|
|
|
|
printf(" -> %s\n", hdr.ar_name);
|
|
|
|
if (tcc_load_object_file(s1, fd, off) < 0)
|
|
|
|
goto the_end;
|
|
|
|
++bound;
|
2007-12-20 01:36:42 +08:00
|
|
|
}
|
2003-04-29 06:06:38 +08:00
|
|
|
} while(bound);
|
|
|
|
ret = 0;
|
|
|
|
the_end:
|
|
|
|
tcc_free(data);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* load a '.a' file */
|
2018-06-01 05:51:59 +08:00
|
|
|
ST_FUNC int tcc_load_archive(TCCState *s1, int fd, int alacarte)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
ArchiveHeader hdr;
|
2019-12-11 03:50:45 +08:00
|
|
|
/* char magic[8]; */
|
|
|
|
int size, len;
|
2002-08-18 21:17:59 +08:00
|
|
|
unsigned long file_offset;
|
2019-12-11 03:50:45 +08:00
|
|
|
ElfW(Ehdr) ehdr;
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* skip magic which was already checked */
|
2019-12-11 03:50:45 +08:00
|
|
|
/* full_read(fd, magic, sizeof(magic)); */
|
|
|
|
file_offset = sizeof ARMAG - 1;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
for(;;) {
|
2019-12-11 03:50:45 +08:00
|
|
|
len = read_ar_header(fd, file_offset, &hdr);
|
2002-08-18 21:17:59 +08:00
|
|
|
if (len == 0)
|
2019-12-11 03:50:45 +08:00
|
|
|
return 0;
|
|
|
|
if (len < 0) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("invalid archive");
|
2002-11-02 22:13:21 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2019-12-11 03:50:45 +08:00
|
|
|
file_offset += len;
|
|
|
|
size = strtol(hdr.ar_size, NULL, 0);
|
2003-04-29 06:06:38 +08:00
|
|
|
/* align to even */
|
|
|
|
size = (size + 1) & ~1;
|
2019-12-11 03:50:45 +08:00
|
|
|
if (alacarte) {
|
2003-04-29 06:06:38 +08:00
|
|
|
/* coff symbol table : we handle it */
|
2019-12-11 03:50:45 +08:00
|
|
|
if (!strcmp(hdr.ar_name, "/"))
|
2016-10-14 22:44:41 +08:00
|
|
|
return tcc_load_alacarte(s1, fd, size, 4);
|
2019-12-11 03:50:45 +08:00
|
|
|
if (!strcmp(hdr.ar_name, "/SYM64/"))
|
2016-10-14 22:44:41 +08:00
|
|
|
return tcc_load_alacarte(s1, fd, size, 8);
|
2019-12-11 03:50:45 +08:00
|
|
|
} else if (tcc_object_type(fd, &ehdr) == AFF_BINTYPE_REL) {
|
|
|
|
if (s1->verbose == 2)
|
|
|
|
printf(" -> %s\n", hdr.ar_name);
|
|
|
|
if (tcc_load_object_file(s1, fd, file_offset) < 0)
|
|
|
|
return -1;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2019-12-11 03:50:45 +08:00
|
|
|
file_offset += size;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
#ifndef ELF_OBJ_ONLY
|
2019-11-26 04:06:07 +08:00
|
|
|
/* Set LV[I] to the global index of sym-version (LIB,VERSION). Maybe resizes
|
|
|
|
LV, maybe create a new entry for (LIB,VERSION). */
|
2019-12-10 03:32:13 +08:00
|
|
|
static void set_ver_to_ver(TCCState *s1, int *n, int **lv, int i, char *lib, char *version)
|
2019-11-26 04:06:07 +08:00
|
|
|
{
|
|
|
|
while (i >= *n) {
|
|
|
|
*lv = tcc_realloc(*lv, (*n + 1) * sizeof(**lv));
|
|
|
|
(*lv)[(*n)++] = -1;
|
|
|
|
}
|
|
|
|
if ((*lv)[i] == -1) {
|
|
|
|
int v, prev_same_lib = -1;
|
|
|
|
for (v = 0; v < nb_sym_versions; v++) {
|
|
|
|
if (strcmp(sym_versions[v].lib, lib))
|
|
|
|
continue;
|
|
|
|
prev_same_lib = v;
|
|
|
|
if (!strcmp(sym_versions[v].version, version))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (v == nb_sym_versions) {
|
|
|
|
sym_versions = tcc_realloc (sym_versions,
|
|
|
|
(v + 1) * sizeof(*sym_versions));
|
|
|
|
sym_versions[v].lib = tcc_strdup(lib);
|
|
|
|
sym_versions[v].version = tcc_strdup(version);
|
|
|
|
sym_versions[v].out_index = 0;
|
|
|
|
sym_versions[v].prev_same_lib = prev_same_lib;
|
|
|
|
nb_sym_versions++;
|
|
|
|
}
|
|
|
|
(*lv)[i] = v;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Associates symbol SYM_INDEX (in dynsymtab) with sym-version index
|
|
|
|
VERNDX. */
|
|
|
|
static void
|
2019-12-10 03:32:13 +08:00
|
|
|
set_sym_version(TCCState *s1, int sym_index, int verndx)
|
2019-11-26 04:06:07 +08:00
|
|
|
{
|
|
|
|
if (sym_index >= nb_sym_to_version) {
|
|
|
|
int newelems = sym_index ? sym_index * 2 : 1;
|
|
|
|
sym_to_version = tcc_realloc(sym_to_version,
|
|
|
|
newelems * sizeof(*sym_to_version));
|
|
|
|
memset(sym_to_version + nb_sym_to_version, -1,
|
|
|
|
(newelems - nb_sym_to_version) * sizeof(*sym_to_version));
|
|
|
|
nb_sym_to_version = newelems;
|
|
|
|
}
|
|
|
|
if (sym_to_version[sym_index] < 0)
|
|
|
|
sym_to_version[sym_index] = verndx;
|
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
struct versym_info {
|
|
|
|
int nb_versyms;
|
|
|
|
ElfW(Verdef) *verdef;
|
|
|
|
ElfW(Verneed) *verneed;
|
|
|
|
ElfW(Half) *versym;
|
|
|
|
int nb_local_ver, *local_ver;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void store_version(TCCState *s1, struct versym_info *v, char *dynstr)
|
|
|
|
{
|
|
|
|
char *lib, *version;
|
|
|
|
uint32_t next;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
#define DEBUG_VERSION 0
|
|
|
|
|
|
|
|
if (v->versym && v->verdef) {
|
|
|
|
ElfW(Verdef) *vdef = v->verdef;
|
|
|
|
lib = NULL;
|
|
|
|
do {
|
|
|
|
ElfW(Verdaux) *verdaux =
|
|
|
|
(ElfW(Verdaux) *) (((char *) vdef) + vdef->vd_aux);
|
|
|
|
|
|
|
|
#if DEBUG_VERSION
|
|
|
|
printf ("verdef: version:%u flags:%u index:%u, hash:%u\n",
|
|
|
|
vdef->vd_version, vdef->vd_flags, vdef->vd_ndx,
|
|
|
|
vdef->vd_hash);
|
|
|
|
#endif
|
|
|
|
if (vdef->vd_cnt) {
|
|
|
|
version = dynstr + verdaux->vda_name;
|
|
|
|
|
|
|
|
if (lib == NULL)
|
|
|
|
lib = version;
|
|
|
|
else
|
|
|
|
set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vdef->vd_ndx,
|
|
|
|
lib, version);
|
|
|
|
#if DEBUG_VERSION
|
|
|
|
printf (" verdaux(%u): %s\n", vdef->vd_ndx, version);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
next = vdef->vd_next;
|
|
|
|
vdef = (ElfW(Verdef) *) (((char *) vdef) + next);
|
|
|
|
} while (next);
|
|
|
|
}
|
|
|
|
if (v->versym && v->verneed) {
|
|
|
|
ElfW(Verneed) *vneed = v->verneed;
|
|
|
|
do {
|
|
|
|
ElfW(Vernaux) *vernaux =
|
|
|
|
(ElfW(Vernaux) *) (((char *) vneed) + vneed->vn_aux);
|
|
|
|
|
|
|
|
lib = dynstr + vneed->vn_file;
|
|
|
|
#if DEBUG_VERSION
|
|
|
|
printf ("verneed: %u %s\n", vneed->vn_version, lib);
|
|
|
|
#endif
|
|
|
|
for (i = 0; i < vneed->vn_cnt; i++) {
|
|
|
|
if ((vernaux->vna_other & 0x8000) == 0) { /* hidden */
|
|
|
|
version = dynstr + vernaux->vna_name;
|
|
|
|
set_ver_to_ver(s1, &v->nb_local_ver, &v->local_ver, vernaux->vna_other,
|
|
|
|
lib, version);
|
|
|
|
#if DEBUG_VERSION
|
|
|
|
printf (" vernaux(%u): %u %u %s\n",
|
|
|
|
vernaux->vna_other, vernaux->vna_hash,
|
|
|
|
vernaux->vna_flags, version);
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
vernaux = (ElfW(Vernaux) *) (((char *) vernaux) + vernaux->vna_next);
|
|
|
|
}
|
|
|
|
next = vneed->vn_next;
|
|
|
|
vneed = (ElfW(Verneed) *) (((char *) vneed) + next);
|
|
|
|
} while (next);
|
|
|
|
}
|
|
|
|
|
|
|
|
#if DEBUG_VERSION
|
|
|
|
for (i = 0; i < v->nb_local_ver; i++) {
|
|
|
|
if (v->local_ver[i] > 0) {
|
|
|
|
printf ("%d: lib: %s, version %s\n",
|
|
|
|
i, sym_versions[v->local_ver[i]].lib,
|
|
|
|
sym_versions[v->local_ver[i]].version);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* load a DLL and all referenced DLLs. 'level = 0' means that the DLL
|
|
|
|
is referenced by the user (so it should be added as DT_NEEDED in
|
|
|
|
the generated ELF file) */
|
2013-01-15 00:34:07 +08:00
|
|
|
ST_FUNC int tcc_load_dll(TCCState *s1, int fd, const char *filename, int level)
|
2013-12-17 20:59:14 +08:00
|
|
|
{
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Ehdr) ehdr;
|
|
|
|
ElfW(Shdr) *shdr, *sh, *sh1;
|
2005-10-31 05:53:14 +08:00
|
|
|
int i, j, nb_syms, nb_dts, sym_bind, ret;
|
2008-11-30 07:14:07 +08:00
|
|
|
ElfW(Sym) *sym, *dynsym;
|
|
|
|
ElfW(Dyn) *dt, *dynamic;
|
2019-12-10 03:32:13 +08:00
|
|
|
|
2019-11-26 04:06:07 +08:00
|
|
|
char *dynstr;
|
2019-10-22 22:55:20 +08:00
|
|
|
int sym_index;
|
2007-12-20 01:36:42 +08:00
|
|
|
const char *name, *soname;
|
2002-08-18 21:17:59 +08:00
|
|
|
DLLReference *dllref;
|
2019-12-10 03:32:13 +08:00
|
|
|
struct versym_info v;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2019-01-13 17:29:25 +08:00
|
|
|
full_read(fd, &ehdr, sizeof(ehdr));
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* test CPU specific stuff */
|
|
|
|
if (ehdr.e_ident[5] != ELFDATA2LSB ||
|
2003-10-15 06:15:56 +08:00
|
|
|
ehdr.e_machine != EM_TCC_TARGET) {
|
2020-06-17 14:21:37 +08:00
|
|
|
tcc_error_noabort("bad architecture");
|
2002-11-02 22:13:21 +08:00
|
|
|
return -1;
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* read sections */
|
2008-11-30 07:14:07 +08:00
|
|
|
shdr = load_data(fd, ehdr.e_shoff, sizeof(ElfW(Shdr)) * ehdr.e_shnum);
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* load dynamic section and dynamic symbols */
|
|
|
|
nb_syms = 0;
|
|
|
|
nb_dts = 0;
|
|
|
|
dynamic = NULL;
|
|
|
|
dynsym = NULL; /* avoid warning */
|
|
|
|
dynstr = NULL; /* avoid warning */
|
2019-12-10 03:32:13 +08:00
|
|
|
memset(&v, 0, sizeof v);
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
for(i = 0, sh = shdr; i < ehdr.e_shnum; i++, sh++) {
|
|
|
|
switch(sh->sh_type) {
|
|
|
|
case SHT_DYNAMIC:
|
2008-11-30 07:14:07 +08:00
|
|
|
nb_dts = sh->sh_size / sizeof(ElfW(Dyn));
|
2002-08-18 21:17:59 +08:00
|
|
|
dynamic = load_data(fd, sh->sh_offset, sh->sh_size);
|
|
|
|
break;
|
|
|
|
case SHT_DYNSYM:
|
2008-11-30 07:14:07 +08:00
|
|
|
nb_syms = sh->sh_size / sizeof(ElfW(Sym));
|
2002-08-18 21:17:59 +08:00
|
|
|
dynsym = load_data(fd, sh->sh_offset, sh->sh_size);
|
|
|
|
sh1 = &shdr[sh->sh_link];
|
|
|
|
dynstr = load_data(fd, sh1->sh_offset, sh1->sh_size);
|
|
|
|
break;
|
2019-10-22 22:55:20 +08:00
|
|
|
case SHT_GNU_verdef:
|
2019-12-10 03:32:13 +08:00
|
|
|
v.verdef = load_data(fd, sh->sh_offset, sh->sh_size);
|
2019-10-22 22:55:20 +08:00
|
|
|
break;
|
|
|
|
case SHT_GNU_verneed:
|
2019-12-10 03:32:13 +08:00
|
|
|
v.verneed = load_data(fd, sh->sh_offset, sh->sh_size);
|
2019-10-22 22:55:20 +08:00
|
|
|
break;
|
|
|
|
case SHT_GNU_versym:
|
2019-12-10 03:32:13 +08:00
|
|
|
v.nb_versyms = sh->sh_size / sizeof(ElfW(Half));
|
|
|
|
v.versym = load_data(fd, sh->sh_offset, sh->sh_size);
|
2019-10-22 22:55:20 +08:00
|
|
|
break;
|
2002-08-18 21:17:59 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* compute the real library name */
|
2007-12-20 01:36:42 +08:00
|
|
|
soname = tcc_basename(filename);
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
|
|
|
|
if (dt->d_tag == DT_SONAME) {
|
2019-11-26 04:06:07 +08:00
|
|
|
soname = dynstr + dt->d_un.d_val;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if the dll is already loaded, do not load it */
|
2002-11-02 22:13:21 +08:00
|
|
|
for(i = 0; i < s1->nb_loaded_dlls; i++) {
|
|
|
|
dllref = s1->loaded_dlls[i];
|
2002-08-18 21:17:59 +08:00
|
|
|
if (!strcmp(soname, dllref->name)) {
|
|
|
|
/* but update level if needed */
|
|
|
|
if (level < dllref->level)
|
|
|
|
dllref->level = level;
|
2002-11-02 22:13:21 +08:00
|
|
|
ret = 0;
|
2002-08-18 21:17:59 +08:00
|
|
|
goto the_end;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-12-10 03:32:13 +08:00
|
|
|
if (v.nb_versyms != nb_syms)
|
|
|
|
tcc_free (v.versym), v.versym = NULL;
|
|
|
|
else
|
|
|
|
store_version(s1, &v, dynstr);
|
2019-10-22 22:55:20 +08:00
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* add the dll and its level */
|
2008-05-06 06:40:49 +08:00
|
|
|
dllref = tcc_mallocz(sizeof(DLLReference) + strlen(soname));
|
2002-08-18 21:17:59 +08:00
|
|
|
dllref->level = level;
|
|
|
|
strcpy(dllref->name, soname);
|
2017-02-14 01:23:43 +08:00
|
|
|
dynarray_add(&s1->loaded_dlls, &s1->nb_loaded_dlls, dllref);
|
2002-08-18 21:17:59 +08:00
|
|
|
|
|
|
|
/* add dynamic symbols in dynsym_section */
|
2019-12-10 03:32:13 +08:00
|
|
|
for(i = 1, sym = dynsym + 1; i < nb_syms; i++, sym++) {
|
2008-11-30 07:14:07 +08:00
|
|
|
sym_bind = ELFW(ST_BIND)(sym->st_info);
|
2002-08-18 21:17:59 +08:00
|
|
|
if (sym_bind == STB_LOCAL)
|
|
|
|
continue;
|
2019-11-26 04:06:07 +08:00
|
|
|
name = dynstr + sym->st_name;
|
2019-10-22 22:55:20 +08:00
|
|
|
sym_index = set_elf_sym(s1->dynsymtab_section, sym->st_value, sym->st_size,
|
|
|
|
sym->st_info, sym->st_other, sym->st_shndx, name);
|
2019-12-10 03:32:13 +08:00
|
|
|
if (v.versym) {
|
|
|
|
ElfW(Half) vsym = v.versym[i];
|
|
|
|
if ((vsym & 0x8000) == 0 && vsym > 0 && vsym < v.nb_local_ver)
|
|
|
|
set_sym_version(s1, sym_index, v.local_ver[vsym]);
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* load all referenced DLLs */
|
|
|
|
for(i = 0, dt = dynamic; i < nb_dts; i++, dt++) {
|
|
|
|
switch(dt->d_tag) {
|
|
|
|
case DT_NEEDED:
|
2019-11-26 04:06:07 +08:00
|
|
|
name = dynstr + dt->d_un.d_val;
|
2005-10-31 05:53:14 +08:00
|
|
|
for(j = 0; j < s1->nb_loaded_dlls; j++) {
|
|
|
|
dllref = s1->loaded_dlls[j];
|
2002-08-18 21:17:59 +08:00
|
|
|
if (!strcmp(name, dllref->name))
|
|
|
|
goto already_loaded;
|
|
|
|
}
|
2002-11-02 22:13:21 +08:00
|
|
|
if (tcc_add_dll(s1, name, AFF_REFERENCED_DLL) < 0) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("referenced dll '%s' not found", name);
|
2002-11-02 22:13:21 +08:00
|
|
|
ret = -1;
|
|
|
|
goto the_end;
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
already_loaded:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-11-02 22:13:21 +08:00
|
|
|
ret = 0;
|
2002-08-18 21:17:59 +08:00
|
|
|
the_end:
|
2002-11-02 22:13:21 +08:00
|
|
|
tcc_free(dynstr);
|
|
|
|
tcc_free(dynsym);
|
|
|
|
tcc_free(dynamic);
|
2002-08-18 21:17:59 +08:00
|
|
|
tcc_free(shdr);
|
2019-12-10 03:32:13 +08:00
|
|
|
tcc_free(v.local_ver);
|
|
|
|
tcc_free(v.verdef);
|
|
|
|
tcc_free(v.verneed);
|
|
|
|
tcc_free(v.versym);
|
2002-11-02 22:13:21 +08:00
|
|
|
return ret;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
|
|
|
|
2002-11-23 02:12:41 +08:00
|
|
|
#define LD_TOK_NAME 256
|
|
|
|
#define LD_TOK_EOF (-1)
|
2002-08-18 21:17:59 +08:00
|
|
|
|
2019-12-11 07:37:18 +08:00
|
|
|
static int ld_inp(TCCState *s1)
|
|
|
|
{
|
|
|
|
char b;
|
|
|
|
if (s1->cc != -1) {
|
|
|
|
int c = s1->cc;
|
|
|
|
s1->cc = -1;
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
if (1 == read(s1->fd, &b, 1))
|
|
|
|
return b;
|
|
|
|
return CH_EOF;
|
|
|
|
}
|
|
|
|
|
2002-11-23 02:12:41 +08:00
|
|
|
/* return next ld script token */
|
2017-05-13 14:59:06 +08:00
|
|
|
static int ld_next(TCCState *s1, char *name, int name_size)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
2019-12-11 07:37:18 +08:00
|
|
|
int c, d, ch;
|
2002-08-18 21:17:59 +08:00
|
|
|
char *q;
|
|
|
|
|
2002-11-23 02:12:41 +08:00
|
|
|
redo:
|
2019-12-11 07:37:18 +08:00
|
|
|
ch = ld_inp(s1);
|
2002-11-23 02:12:41 +08:00
|
|
|
switch(ch) {
|
|
|
|
case ' ':
|
|
|
|
case '\t':
|
|
|
|
case '\f':
|
|
|
|
case '\v':
|
|
|
|
case '\r':
|
|
|
|
case '\n':
|
|
|
|
goto redo;
|
|
|
|
case '/':
|
2019-12-11 07:37:18 +08:00
|
|
|
ch = ld_inp(s1);
|
|
|
|
if (ch == '*') { /* comment */
|
|
|
|
for (d = 0;; d = ch) {
|
|
|
|
ch = ld_inp(s1);
|
|
|
|
if (ch == CH_EOF || (ch == '/' && d == '*'))
|
|
|
|
break;
|
|
|
|
}
|
2002-11-23 02:12:41 +08:00
|
|
|
goto redo;
|
|
|
|
} else {
|
|
|
|
q = name;
|
|
|
|
*q++ = '/';
|
|
|
|
goto parse_name;
|
|
|
|
}
|
|
|
|
break;
|
2015-05-01 05:31:32 +08:00
|
|
|
case '\\':
|
2008-03-26 05:04:47 +08:00
|
|
|
/* case 'a' ... 'z': */
|
|
|
|
case 'a':
|
|
|
|
case 'b':
|
|
|
|
case 'c':
|
|
|
|
case 'd':
|
|
|
|
case 'e':
|
|
|
|
case 'f':
|
|
|
|
case 'g':
|
|
|
|
case 'h':
|
|
|
|
case 'i':
|
|
|
|
case 'j':
|
|
|
|
case 'k':
|
|
|
|
case 'l':
|
|
|
|
case 'm':
|
|
|
|
case 'n':
|
|
|
|
case 'o':
|
|
|
|
case 'p':
|
|
|
|
case 'q':
|
|
|
|
case 'r':
|
|
|
|
case 's':
|
|
|
|
case 't':
|
|
|
|
case 'u':
|
|
|
|
case 'v':
|
|
|
|
case 'w':
|
|
|
|
case 'x':
|
|
|
|
case 'y':
|
|
|
|
case 'z':
|
|
|
|
/* case 'A' ... 'z': */
|
|
|
|
case 'A':
|
|
|
|
case 'B':
|
|
|
|
case 'C':
|
|
|
|
case 'D':
|
|
|
|
case 'E':
|
|
|
|
case 'F':
|
|
|
|
case 'G':
|
|
|
|
case 'H':
|
|
|
|
case 'I':
|
|
|
|
case 'J':
|
|
|
|
case 'K':
|
|
|
|
case 'L':
|
|
|
|
case 'M':
|
|
|
|
case 'N':
|
|
|
|
case 'O':
|
|
|
|
case 'P':
|
|
|
|
case 'Q':
|
|
|
|
case 'R':
|
|
|
|
case 'S':
|
|
|
|
case 'T':
|
|
|
|
case 'U':
|
|
|
|
case 'V':
|
|
|
|
case 'W':
|
|
|
|
case 'X':
|
|
|
|
case 'Y':
|
|
|
|
case 'Z':
|
2002-11-23 02:12:41 +08:00
|
|
|
case '_':
|
|
|
|
case '.':
|
|
|
|
case '$':
|
|
|
|
case '~':
|
|
|
|
q = name;
|
|
|
|
parse_name:
|
|
|
|
for(;;) {
|
|
|
|
if (!((ch >= 'a' && ch <= 'z') ||
|
|
|
|
(ch >= 'A' && ch <= 'Z') ||
|
|
|
|
(ch >= '0' && ch <= '9') ||
|
|
|
|
strchr("/.-_+=$:\\,~", ch)))
|
|
|
|
break;
|
|
|
|
if ((q - name) < name_size - 1) {
|
|
|
|
*q++ = ch;
|
|
|
|
}
|
2019-12-11 07:37:18 +08:00
|
|
|
ch = ld_inp(s1);
|
2002-11-23 02:12:41 +08:00
|
|
|
}
|
2019-12-11 07:37:18 +08:00
|
|
|
s1->cc = ch;
|
2002-11-23 02:12:41 +08:00
|
|
|
*q = '\0';
|
|
|
|
c = LD_TOK_NAME;
|
|
|
|
break;
|
|
|
|
case CH_EOF:
|
|
|
|
c = LD_TOK_EOF;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
c = ch;
|
|
|
|
break;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2002-11-23 02:12:41 +08:00
|
|
|
return c;
|
2002-08-18 21:17:59 +08:00
|
|
|
}
|
2002-11-23 02:12:41 +08:00
|
|
|
|
2012-01-04 21:29:08 +08:00
|
|
|
static int ld_add_file(TCCState *s1, const char filename[])
|
2005-09-04 05:32:06 +08:00
|
|
|
{
|
2017-02-23 15:41:57 +08:00
|
|
|
if (filename[0] == '/') {
|
|
|
|
if (CONFIG_SYSROOT[0] == '\0'
|
|
|
|
&& tcc_add_file_internal(s1, filename, AFF_TYPE_BIN) == 0)
|
|
|
|
return 0;
|
|
|
|
filename = tcc_basename(filename);
|
|
|
|
}
|
|
|
|
return tcc_add_dll(s1, filename, 0);
|
2010-04-20 21:49:34 +08:00
|
|
|
}
|
2005-09-04 05:32:06 +08:00
|
|
|
|
2010-04-20 21:49:34 +08:00
|
|
|
static int ld_add_file_list(TCCState *s1, const char *cmd, int as_needed)
|
|
|
|
{
|
|
|
|
char filename[1024], libname[1024];
|
|
|
|
int t, group, nblibs = 0, ret = 0;
|
|
|
|
char **libs = NULL;
|
|
|
|
|
|
|
|
group = !strcmp(cmd, "GROUP");
|
|
|
|
if (!as_needed)
|
2019-12-11 07:37:18 +08:00
|
|
|
s1->new_undef_sym = 0;
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, filename, sizeof(filename));
|
2019-12-14 19:31:03 +08:00
|
|
|
if (t != '(') {
|
|
|
|
tcc_error_noabort("( expected");
|
|
|
|
ret = -1;
|
|
|
|
goto lib_parse_error;
|
|
|
|
}
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, filename, sizeof(filename));
|
2005-09-04 05:32:06 +08:00
|
|
|
for(;;) {
|
2010-03-30 15:45:31 +08:00
|
|
|
libname[0] = '\0';
|
2005-09-04 05:32:06 +08:00
|
|
|
if (t == LD_TOK_EOF) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("unexpected end of file");
|
2010-04-20 21:49:34 +08:00
|
|
|
ret = -1;
|
|
|
|
goto lib_parse_error;
|
2005-09-04 05:32:06 +08:00
|
|
|
} else if (t == ')') {
|
|
|
|
break;
|
2010-03-30 15:45:31 +08:00
|
|
|
} else if (t == '-') {
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, filename, sizeof(filename));
|
2010-03-30 15:45:31 +08:00
|
|
|
if ((t != LD_TOK_NAME) || (filename[0] != 'l')) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("library name expected");
|
2010-04-20 21:49:34 +08:00
|
|
|
ret = -1;
|
|
|
|
goto lib_parse_error;
|
2010-03-30 15:45:31 +08:00
|
|
|
}
|
2013-01-31 18:29:45 +08:00
|
|
|
pstrcpy(libname, sizeof libname, &filename[1]);
|
|
|
|
if (s1->static_link) {
|
|
|
|
snprintf(filename, sizeof filename, "lib%s.a", libname);
|
|
|
|
} else {
|
|
|
|
snprintf(filename, sizeof filename, "lib%s.so", libname);
|
|
|
|
}
|
2005-09-04 05:32:06 +08:00
|
|
|
} else if (t != LD_TOK_NAME) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("filename expected");
|
2010-04-20 21:49:34 +08:00
|
|
|
ret = -1;
|
|
|
|
goto lib_parse_error;
|
2012-01-04 21:29:08 +08:00
|
|
|
}
|
2005-09-04 05:32:06 +08:00
|
|
|
if (!strcmp(filename, "AS_NEEDED")) {
|
2010-04-20 21:49:34 +08:00
|
|
|
ret = ld_add_file_list(s1, cmd, 1);
|
2005-09-04 05:32:06 +08:00
|
|
|
if (ret)
|
2010-04-20 21:49:34 +08:00
|
|
|
goto lib_parse_error;
|
2005-09-04 05:32:06 +08:00
|
|
|
} else {
|
|
|
|
/* TODO: Implement AS_NEEDED support. Ignore it for now */
|
2010-03-30 15:45:31 +08:00
|
|
|
if (!as_needed) {
|
2012-01-04 21:29:08 +08:00
|
|
|
ret = ld_add_file(s1, filename);
|
2010-04-20 21:49:34 +08:00
|
|
|
if (ret)
|
|
|
|
goto lib_parse_error;
|
|
|
|
if (group) {
|
2010-04-21 04:25:16 +08:00
|
|
|
/* Add the filename *and* the libname to avoid future conversions */
|
2017-02-14 01:23:43 +08:00
|
|
|
dynarray_add(&libs, &nblibs, tcc_strdup(filename));
|
2012-01-04 21:29:08 +08:00
|
|
|
if (libname[0] != '\0')
|
2017-02-14 01:23:43 +08:00
|
|
|
dynarray_add(&libs, &nblibs, tcc_strdup(libname));
|
2010-04-20 21:49:34 +08:00
|
|
|
}
|
2010-03-30 15:45:31 +08:00
|
|
|
}
|
2005-09-04 05:32:06 +08:00
|
|
|
}
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, filename, sizeof(filename));
|
2005-09-04 05:32:06 +08:00
|
|
|
if (t == ',') {
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, filename, sizeof(filename));
|
2005-09-04 05:32:06 +08:00
|
|
|
}
|
|
|
|
}
|
2010-04-20 21:49:34 +08:00
|
|
|
if (group && !as_needed) {
|
2019-12-11 07:37:18 +08:00
|
|
|
while (s1->new_undef_sym) {
|
2010-04-20 21:49:34 +08:00
|
|
|
int i;
|
2019-12-11 07:37:18 +08:00
|
|
|
s1->new_undef_sym = 0;
|
2012-01-04 21:29:08 +08:00
|
|
|
for (i = 0; i < nblibs; i ++)
|
|
|
|
ld_add_file(s1, libs[i]);
|
2010-04-20 21:49:34 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
lib_parse_error:
|
|
|
|
dynarray_reset(&libs, &nblibs);
|
2010-03-30 15:45:31 +08:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2002-08-18 21:17:59 +08:00
|
|
|
/* interpret a subset of GNU ldscripts to handle the dummy libc.so
|
|
|
|
files */
|
2019-12-11 07:37:18 +08:00
|
|
|
ST_FUNC int tcc_load_ldscript(TCCState *s1, int fd)
|
2002-08-18 21:17:59 +08:00
|
|
|
{
|
|
|
|
char cmd[64];
|
|
|
|
char filename[1024];
|
2005-09-04 05:32:06 +08:00
|
|
|
int t, ret;
|
2013-12-17 20:59:14 +08:00
|
|
|
|
2019-12-11 07:37:18 +08:00
|
|
|
s1->fd = fd;
|
|
|
|
s1->cc = -1;
|
2002-08-18 21:17:59 +08:00
|
|
|
for(;;) {
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, cmd, sizeof(cmd));
|
2002-11-23 02:12:41 +08:00
|
|
|
if (t == LD_TOK_EOF)
|
2002-08-18 21:17:59 +08:00
|
|
|
return 0;
|
2002-11-23 02:12:41 +08:00
|
|
|
else if (t != LD_TOK_NAME)
|
2002-08-18 21:17:59 +08:00
|
|
|
return -1;
|
|
|
|
if (!strcmp(cmd, "INPUT") ||
|
|
|
|
!strcmp(cmd, "GROUP")) {
|
2010-04-20 21:49:34 +08:00
|
|
|
ret = ld_add_file_list(s1, cmd, 0);
|
2005-09-04 05:32:06 +08:00
|
|
|
if (ret)
|
|
|
|
return ret;
|
2003-04-17 05:25:59 +08:00
|
|
|
} else if (!strcmp(cmd, "OUTPUT_FORMAT") ||
|
|
|
|
!strcmp(cmd, "TARGET")) {
|
|
|
|
/* ignore some commands */
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, cmd, sizeof(cmd));
|
2019-12-14 19:31:03 +08:00
|
|
|
if (t != '(') {
|
|
|
|
tcc_error_noabort("( expected");
|
|
|
|
return -1;
|
|
|
|
}
|
2003-04-17 05:25:59 +08:00
|
|
|
for(;;) {
|
2017-05-13 14:59:06 +08:00
|
|
|
t = ld_next(s1, filename, sizeof(filename));
|
2003-04-17 05:25:59 +08:00
|
|
|
if (t == LD_TOK_EOF) {
|
2011-08-11 23:07:56 +08:00
|
|
|
tcc_error_noabort("unexpected end of file");
|
2003-04-17 05:25:59 +08:00
|
|
|
return -1;
|
|
|
|
} else if (t == ')') {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2002-08-18 21:17:59 +08:00
|
|
|
} else {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2019-12-10 03:32:13 +08:00
|
|
|
#endif /* !ELF_OBJ_ONLY */
|