mirror of
git://repo.or.cz/tinycc.git
synced 2026-11-04 21:26:36 +08:00
tccelf: provide complete ELF boundary symbols
The traditional boundary symbols were recorded against the canonical .text, .data and .bss sections before dynamic binding and final layout. Separately named allocatable sections and copy-relocated data could therefore fall outside the advertised ranges. Track definitions synthesized by the linker and finalize them from the ordered loadable sections. Refresh both regular and dynamic symbol tables, and give the plain etext, edata and end names PROVIDE semantics on every ELF target while preserving user definitions. Cover archive references, overrides, copy relocations and independently named text/data/bss sections. Reported-by: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com>
This commit is contained in:
parent
31020bf963
commit
384614a945
1
tcc.h
1
tcc.h
@ -722,6 +722,7 @@ struct sym_attr {
|
||||
unsigned plt_offset;
|
||||
int plt_sym;
|
||||
int dyn_index;
|
||||
unsigned char linker_sym:1;
|
||||
#ifdef TCC_TARGET_ARM
|
||||
unsigned char plt_thumb_stub:1;
|
||||
#endif
|
||||
|
||||
95
tccelf.c
95
tccelf.c
@ -1560,6 +1560,90 @@ ST_FUNC int set_global_sym(TCCState *s1, const char *name, Section *sec, addr_t
|
||||
ELFW(ST_INFO)(name ? STB_GLOBAL : STB_LOCAL, STT_NOTYPE), 0, shn, name);
|
||||
}
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
static int set_linker_sym(TCCState *s1, const char *name,
|
||||
Section *sec, addr_t offs)
|
||||
{
|
||||
int sym_index = find_elf_sym(symtab_section, name);
|
||||
ElfW(Sym) *sym = sym_index
|
||||
? &((ElfW(Sym) *)symtab_section->data)[sym_index] : NULL;
|
||||
/* Mirror the set_elf_sym cases where the new definition wins. */
|
||||
int is_linker_sym = !sym || sym->st_shndx == SHN_UNDEF
|
||||
|| ELFW(ST_BIND)(sym->st_info) == STB_WEAK
|
||||
|| (sec && sec != bss_section
|
||||
&& ((sym->st_other & ST_ASM_SET)
|
||||
|| sym->st_shndx == SHN_COMMON
|
||||
|| sym->st_shndx == bss_section->sh_num));
|
||||
|
||||
sym_index = set_global_sym(s1, name, sec, offs);
|
||||
if (is_linker_sym)
|
||||
get_sym_attr(s1, sym_index, 1)->linker_sym = 1;
|
||||
return sym_index;
|
||||
}
|
||||
|
||||
static void provide_linker_sym(TCCState *s1, const char *name,
|
||||
Section *sec, addr_t offs)
|
||||
{
|
||||
int sym_index = find_elf_sym(symtab_section, name);
|
||||
|
||||
if (!sym_index
|
||||
|| ((ElfW(Sym) *)symtab_section->data)[sym_index].st_shndx != SHN_UNDEF)
|
||||
return;
|
||||
set_linker_sym(s1, name, sec, offs);
|
||||
}
|
||||
|
||||
static void update_linker_sym(TCCState *s1, const char *name,
|
||||
Section *sec, addr_t offs)
|
||||
{
|
||||
int sym_index = find_elf_sym(symtab_section, name);
|
||||
|
||||
if (sym_index && sym_index < s1->nb_sym_attrs
|
||||
&& s1->sym_attrs[sym_index].linker_sym) {
|
||||
ElfW(Sym) *sym = &((ElfW(Sym) *)symtab_section->data)[sym_index];
|
||||
|
||||
sym->st_value = offs;
|
||||
sym->st_shndx = sec->sh_num;
|
||||
if (s1->dynsym) {
|
||||
sym_index = find_elf_sym(s1->dynsym, name);
|
||||
if (sym_index) {
|
||||
sym = &((ElfW(Sym) *)s1->dynsym->data)[sym_index];
|
||||
sym->st_value = offs;
|
||||
sym->st_shndx = sec->sh_num;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void finalize_linker_symbols(TCCState *s1, int *sec_order)
|
||||
{
|
||||
Section *etext = text_section;
|
||||
Section *edata = data_section;
|
||||
Section *end = bss_section;
|
||||
Section *s;
|
||||
int i;
|
||||
|
||||
/* Follow the final loadable-section order rather than assuming that
|
||||
.text, .data and .bss are the last sections of their regions. */
|
||||
for (i = 1; i < s1->nb_sections; ++i) {
|
||||
s = s1->sections[sec_order[i]];
|
||||
if (!(s->sh_flags & SHF_ALLOC))
|
||||
continue;
|
||||
end = s;
|
||||
if (!(s->sh_flags & SHF_WRITE))
|
||||
etext = s;
|
||||
if (s->sh_type != SHT_NOBITS)
|
||||
edata = s;
|
||||
}
|
||||
|
||||
update_linker_sym(s1, "_etext", etext, etext->sh_size);
|
||||
update_linker_sym(s1, "etext", etext, etext->sh_size);
|
||||
update_linker_sym(s1, "_edata", edata, edata->sh_size);
|
||||
update_linker_sym(s1, "edata", edata, edata->sh_size);
|
||||
update_linker_sym(s1, "_end", end, end->sh_size);
|
||||
update_linker_sym(s1, "end", end, end->sh_size);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void add_init_array_defines(TCCState *s1, const char *section_name)
|
||||
{
|
||||
Section *s;
|
||||
@ -1884,9 +1968,19 @@ static void tcc_add_linker_symbols(TCCState *s1)
|
||||
int i;
|
||||
Section *s;
|
||||
|
||||
#ifndef ELF_OBJ_ONLY
|
||||
set_linker_sym(s1, "_etext", text_section, -1);
|
||||
set_linker_sym(s1, "_edata", data_section, -1);
|
||||
set_linker_sym(s1, "_end", bss_section, -1);
|
||||
/* These conventional ELF symbols have PROVIDE semantics. */
|
||||
provide_linker_sym(s1, "etext", text_section, -1);
|
||||
provide_linker_sym(s1, "edata", data_section, -1);
|
||||
provide_linker_sym(s1, "end", bss_section, -1);
|
||||
#else
|
||||
set_global_sym(s1, "_etext", text_section, -1);
|
||||
set_global_sym(s1, "_edata", data_section, -1);
|
||||
set_global_sym(s1, "_end", bss_section, -1);
|
||||
#endif
|
||||
#if TARGETOS_OpenBSD
|
||||
set_global_sym(s1, "__executable_start", NULL, ELF_START_ADDR);
|
||||
#endif
|
||||
@ -3081,6 +3175,7 @@ static int elf_output_file(TCCState *s1, const char *filename)
|
||||
sec_order = tcc_malloc(sizeof(int) * 2 * s1->nb_sections);
|
||||
/* compute section to program header mapping */
|
||||
layout_sections(s1, sec_order, &dyninf);
|
||||
finalize_linker_symbols(s1, sec_order);
|
||||
|
||||
if (dynamic) {
|
||||
/* put in GOT the dynamic section address and relocate PLT */
|
||||
|
||||
13
tests/tests2/148+_linker_symbols.c
Normal file
13
tests/tests2/148+_linker_symbols.c
Normal file
@ -0,0 +1,13 @@
|
||||
extern char etext[], _etext[];
|
||||
extern char edata[], _edata[];
|
||||
extern char end[], _end[];
|
||||
|
||||
int check_linker_symbols(void)
|
||||
{
|
||||
int errors = 0;
|
||||
|
||||
errors += etext != _etext;
|
||||
errors += edata != _edata;
|
||||
errors += end != _end;
|
||||
return errors;
|
||||
}
|
||||
13
tests/tests2/148+override_linker_symbols.c
Normal file
13
tests/tests2/148+override_linker_symbols.c
Normal file
@ -0,0 +1,13 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int etext(void) { return 1; }
|
||||
int edata(void) { return 2; }
|
||||
int end(void) { return 3; }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int errors = etext() + edata() + end() != 6;
|
||||
|
||||
printf("user definitions errors: %d\n", errors);
|
||||
return errors;
|
||||
}
|
||||
11
tests/tests2/148_linker_symbols.c
Normal file
11
tests/tests2/148_linker_symbols.c
Normal file
@ -0,0 +1,11 @@
|
||||
#include <stdio.h>
|
||||
|
||||
int check_linker_symbols(void);
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int errors = check_linker_symbols();
|
||||
|
||||
printf("linker symbols errors: %d\n", errors);
|
||||
return errors;
|
||||
}
|
||||
2
tests/tests2/148_linker_symbols.expect
Normal file
2
tests/tests2/148_linker_symbols.expect
Normal file
@ -0,0 +1,2 @@
|
||||
linker symbols errors: 0
|
||||
user definitions errors: 0
|
||||
1
tests/tests2/149+_end_copy_reloc.c
Normal file
1
tests/tests2/149+_end_copy_reloc.c
Normal file
@ -0,0 +1 @@
|
||||
unsigned char copy_reloc_data[257];
|
||||
18
tests/tests2/149+override_end_copy_reloc.c
Normal file
18
tests/tests2/149+override_end_copy_reloc.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern unsigned char copy_reloc_data[257];
|
||||
|
||||
int end(void) { return 42; }
|
||||
int _end(void) { return 24; }
|
||||
|
||||
int main(void)
|
||||
{
|
||||
int errors;
|
||||
|
||||
copy_reloc_data[256] = 42;
|
||||
errors = end() != 42;
|
||||
errors += _end() != 24;
|
||||
errors += copy_reloc_data[256] != 42;
|
||||
printf("user end copy relocation errors: %d\n", errors);
|
||||
return errors;
|
||||
}
|
||||
18
tests/tests2/149_end_copy_reloc.c
Normal file
18
tests/tests2/149_end_copy_reloc.c
Normal file
@ -0,0 +1,18 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern unsigned char copy_reloc_data[257];
|
||||
extern char end[], _end[];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned long data_end;
|
||||
int errors = 0;
|
||||
|
||||
copy_reloc_data[256] = 42;
|
||||
data_end = (unsigned long)(copy_reloc_data + sizeof copy_reloc_data);
|
||||
errors += end != _end;
|
||||
errors += (unsigned long)end < data_end;
|
||||
errors += copy_reloc_data[256] != 42;
|
||||
printf("end copy relocation errors: %d\n", errors);
|
||||
return errors;
|
||||
}
|
||||
2
tests/tests2/149_end_copy_reloc.expect
Normal file
2
tests/tests2/149_end_copy_reloc.expect
Normal file
@ -0,0 +1,2 @@
|
||||
end copy relocation errors: 0
|
||||
user end copy relocation errors: 0
|
||||
14
tests/tests2/150+_linker_boundaries.c
Normal file
14
tests/tests2/150+_linker_boundaries.c
Normal file
@ -0,0 +1,14 @@
|
||||
void __attribute__((section(".text.linker_test"), noinline, used))
|
||||
linker_test_text(void)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned char linker_test_data[23]
|
||||
__attribute__((section(".data.linker_test"), used)) = { 1 };
|
||||
|
||||
unsigned char linker_test_bss[257]
|
||||
__attribute__((section(".bss.linker_test"), used));
|
||||
|
||||
/* set_global_sym replaces BSS/common definitions of these symbols. */
|
||||
unsigned char _etext;
|
||||
unsigned char _edata;
|
||||
31
tests/tests2/150_linker_boundaries.c
Normal file
31
tests/tests2/150_linker_boundaries.c
Normal file
@ -0,0 +1,31 @@
|
||||
#include <stdio.h>
|
||||
|
||||
extern void linker_test_text(void);
|
||||
extern unsigned char linker_test_data[23];
|
||||
extern unsigned char linker_test_bss[257];
|
||||
extern char etext[], _etext[];
|
||||
extern char edata[], _edata[];
|
||||
extern char end[], _end[];
|
||||
|
||||
int main(void)
|
||||
{
|
||||
unsigned long text_addr = (unsigned long)linker_test_text;
|
||||
unsigned long data_end = (unsigned long)(linker_test_data
|
||||
+ sizeof linker_test_data);
|
||||
unsigned long bss_end = (unsigned long)(linker_test_bss
|
||||
+ sizeof linker_test_bss);
|
||||
int errors = 0;
|
||||
|
||||
linker_test_data[22] = 42;
|
||||
linker_test_bss[256] = 42;
|
||||
errors += etext != _etext;
|
||||
errors += edata != _edata;
|
||||
errors += end != _end;
|
||||
errors += (unsigned long)etext <= text_addr;
|
||||
errors += (unsigned long)edata < data_end;
|
||||
errors += (unsigned long)end < bss_end;
|
||||
errors += linker_test_data[22] != 42;
|
||||
errors += linker_test_bss[256] != 42;
|
||||
printf("linker boundary errors: %d\n", errors);
|
||||
return errors;
|
||||
}
|
||||
1
tests/tests2/150_linker_boundaries.expect
Normal file
1
tests/tests2/150_linker_boundaries.expect
Normal file
@ -0,0 +1 @@
|
||||
linker boundary errors: 0
|
||||
@ -38,12 +38,13 @@ ifeq ($(CONFIG_bcheck),no)
|
||||
endif
|
||||
ifeq ($(CONFIG_dll),no)
|
||||
SKIP += 113_btdll.test 147_def_library.test # no shared lib support yet
|
||||
SKIP += 149_end_copy_reloc.test
|
||||
endif
|
||||
ifeq (-$(findstring gcc,$(CC))-,--)
|
||||
SKIP += $(patsubst %.expect,%.test,$(GEN-ALWAYS))
|
||||
endif
|
||||
ifeq ($(CC_NAME),tcc)
|
||||
SKIP += 146_tls_extern.test # needs an external system linker
|
||||
SKIP += 146_tls_extern.test 150_linker_boundaries.test # needs external tools
|
||||
endif
|
||||
ifeq (-$(CONFIG_WIN32)-$(CONFIG_i386)$(CONFIG_arm)-,--yes-)
|
||||
SKIP += 95_bitfields%.test # type_align is different on 32bit-non-windows
|
||||
@ -54,6 +55,8 @@ ifeq (-$(CONFIG_WIN32)-,-yes-)
|
||||
SKIP += 117_builtins.test # win32 port doesn't define __builtins
|
||||
SKIP += 124_atomic_counter.test # No pthread support
|
||||
SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported
|
||||
SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests
|
||||
SKIP += 150_linker_boundaries.test
|
||||
endif
|
||||
ifneq (,$(filter OpenBSD FreeBSD NetBSD,$(TARGETOS)))
|
||||
SKIP += 106_versym.test # no pthread_condattr_setpshared
|
||||
@ -66,6 +69,11 @@ ifeq ($(TARGETOS),DragonFly)
|
||||
endif
|
||||
ifeq ($(CONFIG_OSX),yes)
|
||||
SKIP += 144_tls.test 146_tls_extern.test # TLS runtime not supported on Mach-O
|
||||
SKIP += 148_linker_symbols.test 149_end_copy_reloc.test # ELF linker tests
|
||||
SKIP += 150_linker_boundaries.test
|
||||
endif
|
||||
ifeq ($(CONFIG_pie),yes)
|
||||
SKIP += 149_end_copy_reloc.test # PIE executables do not use copy relocations
|
||||
endif
|
||||
ifeq (-$(ARCH)-,-arm-)
|
||||
SKIP += 144_tls.test 146_tls_extern.test # doesn't work currently
|
||||
@ -143,6 +151,38 @@ GEN-ALWAYS =
|
||||
146_tls_extern-def.o -o $(basename $@).exe && \
|
||||
./$(basename $@).exe
|
||||
|
||||
# Check optional ELF linker symbols, including references from an archive.
|
||||
148_linker_symbols.test: NORUN = true
|
||||
148_linker_symbols.test: T1 = ( \
|
||||
$(TCC) -c $(subst 148,148+,$1) -o 148_linker_symbols.o && \
|
||||
$(AR) rcs 148_linker_symbols.a 148_linker_symbols.o && \
|
||||
$(TCC) $1 148_linker_symbols.a -o $(basename $@).exe && \
|
||||
./$(basename $@).exe && \
|
||||
$(TCC) $(subst 148,148+override,$1) -o 148_linker_symbols-override.exe && \
|
||||
./148_linker_symbols-override.exe \
|
||||
)
|
||||
|
||||
# Copy relocations must be included in the final end symbols.
|
||||
149_end_copy_reloc.test: NORUN = true
|
||||
149_end_copy_reloc.test: T1 = ( \
|
||||
$(TCC) -shared $(subst 149,149+,$1) -o 149_end_copy_reloc$(DLLSUF) && \
|
||||
$(TCC) $1 ./149_end_copy_reloc$(DLLSUF) -Wl,-rpath=. \
|
||||
-o $(basename $@).exe && \
|
||||
./$(basename $@).exe && \
|
||||
$(TCC) $(subst 149,149+override,$1) ./149_end_copy_reloc$(DLLSUF) \
|
||||
-Wl,-rpath=. -o 149_end_copy_reloc-override.exe && \
|
||||
./149_end_copy_reloc-override.exe \
|
||||
)
|
||||
|
||||
# Boundary symbols must cover separately named sections from external objects.
|
||||
150_linker_boundaries.test: NORUN = true
|
||||
150_linker_boundaries.test: T1 = ( \
|
||||
$(CC) -fno-pic -fno-pie -c $(subst 150,150+,$1) \
|
||||
-o 150_linker_boundaries.o && \
|
||||
$(TCC) $1 150_linker_boundaries.o -o $(basename $@).exe && \
|
||||
./$(basename $@).exe \
|
||||
)
|
||||
|
||||
112_backtrace.test: FLAGS += -dt -b
|
||||
112_backtrace.test 113_btdll.test 126_bound_global.test: FILTER += \
|
||||
-e 's;[0-9A-Fa-fx]\{5,\};........;g' \
|
||||
@ -233,4 +273,4 @@ $(sort $(GEN-ALWAYS) $(UPDATE)) : force
|
||||
force:
|
||||
|
||||
clean :
|
||||
rm -f fred.txt *.output *.o *.exe *.dll *.so *.def $(GEN-ALWAYS)
|
||||
rm -f fred.txt *.output *.o *.a *.exe *.dll *.so *.def $(GEN-ALWAYS)
|
||||
|
||||
Loading…
Reference in New Issue
Block a user