mirror of
https://github.com/frida/tinycc
synced 2024-11-24 00:29:38 +03:00
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.
This commit is contained in:
parent
a86f47889c
commit
56db092ab7
23
Makefile
23
Makefile
@ -16,7 +16,6 @@ endif
|
||||
|
||||
LIBTCC = libtcc.a
|
||||
LIBTCC1 = libtcc1.a
|
||||
LIBTCCB1 = libtccb1.a
|
||||
LINK_LIBTCC =
|
||||
LIBS =
|
||||
CFLAGS += -I$(TOP)
|
||||
@ -87,7 +86,7 @@ ifeq ($(INCLUDED),no)
|
||||
# running top Makefile
|
||||
|
||||
PROGS = tcc$(EXESUF)
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCCB1) $(LIBTCC) $(LIBTCCDEF)
|
||||
TCCLIBS = $(LIBTCC1) $(LIBTCC) $(LIBTCCDEF)
|
||||
TCCDOCS = tcc.1 tcc-doc.html tcc-doc.info
|
||||
|
||||
all: $(PROGS) $(TCCLIBS) $(TCCDOCS)
|
||||
@ -101,15 +100,11 @@ TCC_X += riscv64
|
||||
LIBTCC1_X = i386 x86_64 i386-win32 x86_64-win32 x86_64-osx arm arm64 arm-wince
|
||||
LIBTCC1_X += riscv64
|
||||
|
||||
# cross libtccb1.a targets to build
|
||||
LIBTCCB1_X = i386 x86_64 i386-win32 x86_64-win32
|
||||
|
||||
PROGS_CROSS = $(foreach X,$(TCC_X),$X-tcc$(EXESUF))
|
||||
LIBTCC1_CROSS = $(foreach X,$(LIBTCC1_X),$X-libtcc1.a)
|
||||
LIBTCCB1_CROSS = $(foreach X,$(LIBTCCB1_X),$X-libtcc1.a)
|
||||
|
||||
# build cross compilers & libs
|
||||
cross: $(LIBTCC1_CROSS) $(LIBTCCB1_CROSS) $(PROGS_CROSS)
|
||||
cross: $(LIBTCC1_CROSS) $(PROGS_CROSS)
|
||||
|
||||
# build specific cross compiler & lib
|
||||
cross-%: %-tcc$(EXESUF) %-libtcc1.a ;
|
||||
@ -153,10 +148,10 @@ DEFINES += $(DEF-$(or $(findstring win,$T),unx))
|
||||
|
||||
ifneq ($(X),)
|
||||
ifeq ($(CONFIG_WIN32),yes)
|
||||
DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"$(X)libtccb1.a\""
|
||||
DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"lib/$(X)libtccb1.a\""
|
||||
DEF-win += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
|
||||
DEF-unx += -DTCC_LIBTCC1="\"lib/$(X)libtcc1.a\""
|
||||
else
|
||||
DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\"" -DTCC_LIBTCCB1="\"$(X)libtccb1.a\""
|
||||
DEF-all += -DTCC_LIBTCC1="\"$(X)libtcc1.a\""
|
||||
DEF-win += -DCONFIG_TCCDIR="\"$(tccdir)/win32\""
|
||||
endif
|
||||
endif
|
||||
@ -281,8 +276,6 @@ STRIP_yes = -s
|
||||
|
||||
LIBTCC1_W = $(filter %-win32-libtcc1.a %-wince-libtcc1.a,$(LIBTCC1_CROSS))
|
||||
LIBTCC1_U = $(filter-out $(LIBTCC1_W),$(LIBTCC1_CROSS))
|
||||
LIBTCCB1_W = $(filter %-win32-libtccb1.a %-wince-libtccb1.a,$(LIBTCCB1_CROSS))
|
||||
LIBTCCB1_U = $(filter-out $(LIBTCCB1_W),$(LIBTCCB1_CROSS))
|
||||
IB = $(if $1,mkdir -p $2 && $(INSTALLBIN) $1 $2)
|
||||
IBw = $(call IB,$(wildcard $1),$2)
|
||||
IF = $(if $1,mkdir -p $2 && $(INSTALL) $1 $2)
|
||||
@ -292,8 +285,7 @@ IR = mkdir -p $2 && cp -r $1/. $2
|
||||
# install progs & libs
|
||||
install-unx:
|
||||
$(call IBw,$(PROGS) $(PROGS_CROSS),"$(bindir)")
|
||||
$(call IFw,$(LIBTCC1) $(LIBTCC1_U),"$(tccdir)")
|
||||
$(call IFw,$(LIBTCCB1) $(LIBTCCB1_U),"$(tccdir)")
|
||||
$(call IFw,$(LIBTCC1) bcheck.o $(LIBTCC1_U),"$(tccdir)")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||
$(call $(if $(findstring .so,$(LIBTCC)),IBw,IFw),$(LIBTCC),"$(libdir)")
|
||||
$(call IF,$(TOPSRC)/libtcc.h,"$(includedir)")
|
||||
@ -318,8 +310,7 @@ uninstall-unx:
|
||||
install-win:
|
||||
$(call IBw,$(PROGS) $(PROGS_CROSS) $(subst libtcc.a,,$(LIBTCC)),"$(bindir)")
|
||||
$(call IF,$(TOPSRC)/win32/lib/*.def,"$(tccdir)/lib")
|
||||
$(call IFw,libtcc1.a $(LIBTCC1_W),"$(tccdir)/lib")
|
||||
$(call IFw,libtccb1.a $(LIBTCCB1_W),"$(tccdir)/lib")
|
||||
$(call IFw,libtcc1.a bcheck.o $(LIBTCC1_W),"$(tccdir)/lib")
|
||||
$(call IF,$(TOPSRC)/include/*.h $(TOPSRC)/tcclib.h,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/include,"$(tccdir)/include")
|
||||
$(call IR,$(TOPSRC)/win32/examples,"$(tccdir)/examples")
|
||||
|
138
i386-gen.c
138
i386-gen.c
@ -425,6 +425,11 @@ ST_FUNC void gfunc_call(int nb_args)
|
||||
int size, align, r, args_size, i, func_call;
|
||||
Sym *func_sym;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
args_size = 0;
|
||||
for(i = 0;i < nb_args; i++) {
|
||||
if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
|
||||
@ -1051,119 +1056,18 @@ ST_FUNC void ggoto(void)
|
||||
|
||||
/* bound check support functions */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec)
|
||||
{
|
||||
addr_t *ptr;
|
||||
int loc_glob;
|
||||
int sym_index;
|
||||
int bsym_index;
|
||||
|
||||
if (0 == s1->do_bounds_check)
|
||||
return;
|
||||
/* XXX: add an object file to do that */
|
||||
ptr = section_ptr_add(bound_sec, sizeof(*ptr));
|
||||
*ptr = 0;
|
||||
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
|
||||
bsym_index = set_elf_sym(sym_sec, 0, 0,
|
||||
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
|
||||
bound_sec->sh_num, "__bounds_start");
|
||||
/* pull bcheck.o from libtcc1.a */
|
||||
sym_index = set_elf_sym(sym_sec, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bound_init");
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
Section *init_section = find_section(s1, ".init");
|
||||
unsigned char *pinit;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pinit = section_ptr_add(init_section, 3);
|
||||
pinit[0] = 0x55; /* push %rbp */
|
||||
pinit[1] = 0x89; /* mov %esp,%ebp */
|
||||
pinit[2] = 0xe5;
|
||||
#endif
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(sym_sec, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
pinit = section_ptr_add(init_section, 6);
|
||||
pinit[0] = 0xb8; /* mov xx,%eax */
|
||||
write32le(pinit + 1, 0);
|
||||
pinit[5] = 0x50; /* push %eax */
|
||||
put_elf_reloc(sym_sec, init_section,
|
||||
init_section->data_offset - 5, R_386_32, bsym_index);
|
||||
sym_index = set_elf_sym(sym_sec, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bounds_add_static_var");
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(sym_sec, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
pinit = section_ptr_add(init_section, 3);
|
||||
pinit[0] = 0x83; /* add $0x4,%esp */
|
||||
pinit[1] = 0xc4;
|
||||
pinit[2] = 0x04;
|
||||
#ifdef TCC_TARGET_PE
|
||||
{
|
||||
int init_index = set_elf_sym(sym_sec,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
init_section->sh_num, "__init_start");
|
||||
Sym sym;
|
||||
init_section->sh_flags |= SHF_EXECINSTR;
|
||||
pinit = section_ptr_add(init_section, 2);
|
||||
pinit[0] = 0xc9; /* leave */
|
||||
pinit[1] = 0xc3; /* ret */
|
||||
sym.c = init_index;
|
||||
add_init_array (s1, &sym);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
/* save all temporary registers */
|
||||
save_regs(0);
|
||||
/* prepare fast i386 function call (args in eax and edx) */
|
||||
gv2(RC_EAX, RC_EDX);
|
||||
vtop -= 2;
|
||||
/* add line, filename */
|
||||
{
|
||||
static addr_t offset;
|
||||
static char last_filename[1024];
|
||||
Sym *sym_data;
|
||||
|
||||
if (strcmp (last_filename, file->filename) != 0) {
|
||||
void *ptr;
|
||||
int len = strlen (file->filename) + 1;
|
||||
|
||||
offset = data_section->data_offset;
|
||||
ptr = section_ptr_add(data_section, len);
|
||||
memcpy (ptr, file->filename, len);
|
||||
memcpy (last_filename, file->filename, len);
|
||||
}
|
||||
o(0xb9); /* mov $xx,%ecx */
|
||||
gen_le32 (0);
|
||||
sym_data = get_sym_ref(&char_pointer_type, data_section,
|
||||
offset, data_section->data_offset);
|
||||
greloca(cur_text_section, sym_data, ind - 4, R_386_32, 0);
|
||||
o(0x51); /* push %ecx */
|
||||
}
|
||||
o(0xb9); /* mov $xx,%ecx */
|
||||
gen_le32 (file->line_num);
|
||||
/* do a fast function call */
|
||||
gen_static_call(TOK___bound_ptr_add);
|
||||
o(0x04c483); /* add $4,%esp */
|
||||
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
/* returned pointer is in eax */
|
||||
vtop++;
|
||||
vtop->r = TREG_EAX | VT_BOUNDED;
|
||||
/* address of bounding function call point */
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(Elf32_Rel));
|
||||
}
|
||||
|
||||
@ -1176,6 +1080,9 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
Elf32_Rel *rel;
|
||||
Sym *sym;
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
|
||||
size = 0;
|
||||
/* XXX: put that code in generic part of tcc */
|
||||
if (!is_float(vtop->type.t)) {
|
||||
@ -1194,17 +1101,18 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
case 12: func = TOK___bound_ptr_indir12; break;
|
||||
case 16: func = TOK___bound_ptr_indir16; break;
|
||||
default:
|
||||
tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
func = 0;
|
||||
break;
|
||||
/* may happen with struct member access */
|
||||
return;
|
||||
//tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
//func = 0;
|
||||
//break;
|
||||
}
|
||||
|
||||
/* patch relocation */
|
||||
/* XXX: find a better solution ? */
|
||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
|
||||
sym = external_global_sym(func, &func_old_type);
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
/* patch relocation */
|
||||
/* XXX: find a better solution ? */
|
||||
rel = (Elf32_Rel *)(cur_text_section->reloc->data + vtop->c.i);
|
||||
rel->r_info = ELF32_R_INFO(sym->c, ELF32_R_TYPE(rel->r_info));
|
||||
}
|
||||
#endif
|
||||
|
75
i386-link.c
75
i386-link.c
@ -235,4 +235,79 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||
{
|
||||
addr_t *ptr;
|
||||
int loc_glob;
|
||||
int sym_index;
|
||||
int bsym_index;
|
||||
|
||||
if (0 == s1->do_bounds_check)
|
||||
return;
|
||||
/* XXX: add an object file to do that */
|
||||
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
|
||||
*ptr = 0;
|
||||
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
|
||||
bsym_index = set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
|
||||
bounds_section->sh_num, "__bounds_start");
|
||||
/* pull bcheck.o from libtcc1.a */
|
||||
sym_index = set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bound_init");
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
Section *init_section = find_section(s1, ".init");
|
||||
unsigned char *pinit;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pinit = section_ptr_add(init_section, 3);
|
||||
pinit[0] = 0x55; /* push %rbp */
|
||||
pinit[1] = 0x89; /* mov %esp,%ebp */
|
||||
pinit[2] = 0xe5;
|
||||
#endif
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
pinit = section_ptr_add(init_section, 6);
|
||||
pinit[0] = 0xb8; /* mov xx,%eax */
|
||||
write32le(pinit + 1, 0);
|
||||
pinit[5] = 0x50; /* push %eax */
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 5, R_386_32, bsym_index);
|
||||
sym_index = set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bounds_add_static_var");
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
pinit = section_ptr_add(init_section, 3);
|
||||
pinit[0] = 0x83; /* add $0x4,%esp */
|
||||
pinit[1] = 0xc4;
|
||||
pinit[2] = 0x04;
|
||||
#ifdef TCC_TARGET_PE
|
||||
{
|
||||
int init_index = set_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
init_section->sh_num, "__init_start");
|
||||
Sym sym;
|
||||
init_section->sh_flags |= SHF_EXECINSTR;
|
||||
pinit = section_ptr_add(init_section, 2);
|
||||
pinit[0] = 0xc9; /* leave */
|
||||
pinit[1] = 0xc3; /* ret */
|
||||
sym.c = init_index;
|
||||
add_init_array (s1, &sym);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !TARGET_DEFS_ONLY */
|
||||
|
45
lib/Makefile
45
lib/Makefile
@ -7,8 +7,6 @@ include $(TOP)/Makefile
|
||||
VPATH = $(TOPSRC)/lib $(TOPSRC)/win32/lib
|
||||
T = $(or $(CROSS_TARGET),$(NATIVE_TARGET),unknown)
|
||||
X = $(if $(CROSS_TARGET),$(CROSS_TARGET)-)
|
||||
BIN = $(TOP)/$(X)libtcc1.a
|
||||
BINB = $(TOP)/$(X)libtccb1.a
|
||||
|
||||
XTCC ?= $(TOP)/$(X)tcc$(EXESUF)
|
||||
XCC = $(XTCC)
|
||||
@ -20,8 +18,6 @@ XCFG = $(or $(findstring -win,$T),-unx)
|
||||
|
||||
# in order to use gcc, tyoe: make <target>-libtcc1-usegcc=yes
|
||||
arm-libtcc1-usegcc ?= no
|
||||
x86_64-libtcc1-usegcc ?= no
|
||||
i386-libtcc1-usegcc ?= no
|
||||
|
||||
ifeq "$($(T)-libtcc1-usegcc)" "yes"
|
||||
XCC = $(CC)
|
||||
@ -42,8 +38,6 @@ ifdef CONFIG_OSX
|
||||
XFLAGS += -D_ANSI_SOURCE
|
||||
endif
|
||||
|
||||
XFLAGS += -g
|
||||
|
||||
I386_O = libtcc1.o alloca86.o alloca86-bt.o
|
||||
X86_64_O = libtcc1.o alloca86_64.o alloca86_64-bt.o
|
||||
ARM_O = libtcc1.o armeabi.o alloca-arm.o armflush.o
|
||||
@ -51,11 +45,11 @@ ARM64_O = lib-arm64.o
|
||||
RISCV64_O = lib-arm64.o
|
||||
WIN_O = crt1.o crt1w.o wincrt1.o wincrt1w.o dllcrt1.o dllmain.o
|
||||
|
||||
OBJ-i386 = $(I386_O) $(DSO_O)
|
||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(DSO_O)
|
||||
OBJ-i386 = $(I386_O) $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64 = $(X86_64_O) va_list.o $(BCHECK_O) $(DSO_O)
|
||||
OBJ-x86_64-osx = $(X86_64_O) va_list.o
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o (WIN_O)
|
||||
OBJ-i386-win32 = $(I386_O) chkstk.o bcheck.o $(WIN_O)
|
||||
OBJ-x86_64-win32 = $(X86_64_O) chkstk.o bcheck.o $(WIN_O)
|
||||
OBJ-arm64 = $(ARM64_O) $(DSO_O)
|
||||
OBJ-arm = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-fpa = $(ARM_O) $(DSO_O)
|
||||
@ -66,27 +60,14 @@ OBJ-arm-eabihf = $(ARM_O) $(DSO_O)
|
||||
OBJ-arm-wince = $(ARM_O) $(WIN_O)
|
||||
OBJ-riscv64 = $(RISCV64_O) $(DSO_O)
|
||||
|
||||
OBJB-i386 = $(BCHECK_O)
|
||||
OBJB-x86_64 = $(BCHECK_O)
|
||||
OBJB-x86_64-osx = dummy.o
|
||||
OBJB-i386-win32 = bcheck.o
|
||||
OBJB-x86_64-win32 = bcheck.o
|
||||
OBJB-arm64 = dummy.o
|
||||
OBJB-arm = dummy.o
|
||||
OBJB-arm-fpa = dummy.o
|
||||
OBJB-arm-fpa-ld = dummy.o
|
||||
OBJB-arm-vfp = dummy.o
|
||||
OBJB-arm-eabi = dummy.o
|
||||
OBJB-arm-eabihf = dummy.o
|
||||
OBJB-arm-wince = dummy.o
|
||||
OBJB-riscv64 = dummy.o
|
||||
OBJ-extra = $(filter bcheck.o,$(OBJ-$T))
|
||||
OBJ-libtcc1 = $(addprefix $(X),$(filter-out $(OBJ-extra),$(OBJ-$T)))
|
||||
|
||||
all: $(BIN) $(BINB)
|
||||
ALL = $(addprefix $(TOP)/,$(X)libtcc1.a $(OBJ-extra))
|
||||
|
||||
$(BIN) : $(patsubst %.o,$(X)%.o,$(OBJ-$T))
|
||||
$(XAR) rcs $@ $^
|
||||
all: $(ALL)
|
||||
|
||||
$(BINB) : $(patsubst %.o,$(X)%.o,$(OBJB-$T))
|
||||
$(TOP)/$(X)libtcc1.a : $(OBJ-libtcc1)
|
||||
$(XAR) rcs $@ $^
|
||||
|
||||
$(X)%.o : %.c
|
||||
@ -95,8 +76,12 @@ $(X)%.o : %.c
|
||||
$(X)%.o : %.S
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(TOP)/%.o : %.c
|
||||
$(XCC) -c $< -o $@ $(XFLAGS)
|
||||
|
||||
$(TOP)/bcheck.o : XFLAGS += -g
|
||||
|
||||
$(X)crt1w.o : crt1.c
|
||||
$(X)wincrt1w.o : wincrt1.c
|
||||
|
||||
clean :
|
||||
rm -f *.a *.o $(BIN) $(BINB)
|
||||
rm -f *.a *.o $(ALL)
|
||||
|
@ -5,44 +5,25 @@
|
||||
__bound_alloca:
|
||||
|
||||
#ifdef _WIN32
|
||||
pop %rdx
|
||||
mov %rcx,%rax
|
||||
add $15,%rax
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
p1:
|
||||
cmp $4096,%rax
|
||||
jbe p2
|
||||
test %rax,-4096(%rsp)
|
||||
sub $4096,%rsp
|
||||
sub $4096,%rax
|
||||
jmp p1
|
||||
p2:
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rax
|
||||
|
||||
push %rdx
|
||||
inc %rcx # add one extra to separate regions
|
||||
jmp alloca
|
||||
.globl __bound_alloca_nr
|
||||
__bound_alloca_nr:
|
||||
dec %rcx
|
||||
push %rax
|
||||
mov %rcx,%rdx
|
||||
mov %rax,%rcx
|
||||
sub $20,%rsp
|
||||
call __bound_new_region
|
||||
add $20,%rsp
|
||||
sub $32,%rsp
|
||||
call __bound_new_region
|
||||
add $32,%rsp
|
||||
pop %rax
|
||||
pop %rdx
|
||||
|
||||
add $32,%rax
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
#else
|
||||
pop %rdx
|
||||
mov %rdi,%rax
|
||||
mov %rax,%rsi # size, a second parm to the __bound_new_region
|
||||
|
||||
add $15,%rax
|
||||
add $15 + 1,%rax # add one extra to separate regions
|
||||
and $-16,%rax
|
||||
jz p3
|
||||
|
||||
|
@ -24,12 +24,8 @@ p1:
|
||||
jmp p1
|
||||
p2:
|
||||
#endif
|
||||
|
||||
sub %rax,%rsp
|
||||
mov %rsp,%rax
|
||||
#ifdef _WIN32
|
||||
add $32,%rax
|
||||
#endif
|
||||
p3:
|
||||
push %rdx
|
||||
ret
|
||||
|
31
lib/bcheck.c
31
lib/bcheck.c
@ -205,6 +205,9 @@ void __bound_checking (int no_check)
|
||||
no_checking = no_check;
|
||||
}
|
||||
|
||||
#define no_FASTCALL
|
||||
//#define no_checking 1
|
||||
|
||||
/* print a bound error message */
|
||||
static void bound_error(const char *fmt, ...)
|
||||
{
|
||||
@ -221,8 +224,7 @@ static void bound_alloc_error(void)
|
||||
|
||||
/* return '(p + offset)' for pointer arithmetic (a pointer can reach
|
||||
the end of a region in this case */
|
||||
void * FASTCALL __bound_ptr_add(void *p, size_t offset,
|
||||
size_t line, const char *filename)
|
||||
void * no_FASTCALL __bound_ptr_add(void *p, size_t offset)
|
||||
{
|
||||
size_t addr = (size_t)p;
|
||||
|
||||
@ -230,8 +232,8 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset,
|
||||
return p + offset;
|
||||
}
|
||||
|
||||
dprintf(stderr, "%s %s (%s:%u): %p 0x%x\n",
|
||||
__FILE__, __FUNCTION__, filename, line, p, (unsigned)offset);
|
||||
dprintf(stderr, "%s %s : %p 0x%x\n",
|
||||
__FILE__, __FUNCTION__, p, (unsigned)offset);
|
||||
|
||||
WAIT_SEM ();
|
||||
INCR_COUNT(bound_ptr_add_count);
|
||||
@ -250,8 +252,10 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset,
|
||||
if (addr <= tree->size) {
|
||||
addr += offset;
|
||||
if (tree->is_invalid || addr > tree->size) {
|
||||
fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n",
|
||||
__FILE__, __FUNCTION__, filename, line, p + offset);
|
||||
#if 0
|
||||
fprintf(stderr,"%s %s : %p is outside of the region\n",
|
||||
__FILE__, __FUNCTION__, p + offset);
|
||||
#endif
|
||||
if (never_fatal == 0) {
|
||||
POST_SEM ();
|
||||
return INVALID_POINTER; /* return an invalid pointer */
|
||||
@ -266,16 +270,15 @@ void * FASTCALL __bound_ptr_add(void *p, size_t offset,
|
||||
/* return '(p + offset)' for pointer indirection (the resulting must
|
||||
be strictly inside the region */
|
||||
#define BOUND_PTR_INDIR(dsize) \
|
||||
void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \
|
||||
size_t line, const char *filename) \
|
||||
void * no_FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset) \
|
||||
{ \
|
||||
size_t addr = (size_t)p; \
|
||||
\
|
||||
if (no_checking) { \
|
||||
return p + offset; \
|
||||
} \
|
||||
dprintf(stderr, "%s %s (%s:%u): %p 0x%x start\n", \
|
||||
__FILE__, __FUNCTION__, filename, line, p, (unsigned)offset); \
|
||||
dprintf(stderr, "%s %s : %p 0x%x start\n", \
|
||||
__FILE__, __FUNCTION__, p, (unsigned)offset); \
|
||||
WAIT_SEM (); \
|
||||
INCR_COUNT(bound_ptr_indir ## dsize ## _count); \
|
||||
if (tree) { \
|
||||
@ -293,8 +296,8 @@ void * FASTCALL __bound_ptr_indir ## dsize (void *p, size_t offset, \
|
||||
if (addr <= tree->size) { \
|
||||
addr += offset + dsize; \
|
||||
if (tree->is_invalid || addr > tree->size) { \
|
||||
fprintf(stderr,"%s %s (%s:%u): %p is outside of the region\n", \
|
||||
__FILE__, __FUNCTION__, filename, line, p + offset); \
|
||||
fprintf(stderr,"%s %s : %p is outside of the region\n", \
|
||||
__FILE__, __FUNCTION__, p + offset); \
|
||||
if (never_fatal == 0) { \
|
||||
POST_SEM (); \
|
||||
return INVALID_POINTER; /* return an invalid pointer */ \
|
||||
@ -907,7 +910,7 @@ static void __bound_check(const void *p, size_t size, const char *function)
|
||||
return;
|
||||
if (size == 0)
|
||||
return;
|
||||
p = __bound_ptr_add((void *)p, size, 0, function);
|
||||
p = __bound_ptr_add((void *)p, size);
|
||||
if (p == INVALID_POINTER)
|
||||
bound_error("invalid pointer");
|
||||
}
|
||||
@ -959,7 +962,7 @@ int __bound_strlen(const char *s)
|
||||
INCR_COUNT(bound_strlen_count);
|
||||
while (*p++);
|
||||
len = (p - s) - 1;
|
||||
p = __bound_ptr_indir1((char *)s, len, 0, "strlen");
|
||||
p = __bound_ptr_indir1((char *)s, len);
|
||||
if (p == INVALID_POINTER)
|
||||
bound_error("bad pointer in strlen()");
|
||||
return len;
|
||||
|
@ -1 +0,0 @@
|
||||
static char dummy;
|
4
libtcc.c
4
libtcc.c
@ -1545,7 +1545,6 @@ static const TCCOption tcc_options[] = {
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
{ "b", TCC_OPTION_b, 0 },
|
||||
{ "ba", TCC_OPTION_ba, 0 },
|
||||
#endif
|
||||
{ "g", TCC_OPTION_g, TCC_OPTION_HAS_ARG | TCC_OPTION_NOSEP },
|
||||
{ "c", TCC_OPTION_c, 0 },
|
||||
@ -1802,9 +1801,6 @@ reparse:
|
||||
s->do_bounds_check = 1;
|
||||
s->do_debug = 1;
|
||||
break;
|
||||
case TCC_OPTION_ba:
|
||||
s->do_bounds_check_address = 1;
|
||||
break;
|
||||
#endif
|
||||
case TCC_OPTION_g:
|
||||
s->do_debug = 1;
|
||||
|
1
tcc.c
1
tcc.c
@ -59,7 +59,6 @@ static const char help[] =
|
||||
" -g generate runtime debug info\n"
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
" -b compile with built-in memory and bounds checker (implies -g)\n"
|
||||
" -ba Enable better address checking with bounds checker\n"
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BACKTRACE
|
||||
" -bt N show N callers in stack traces\n"
|
||||
|
9
tcc.h
9
tcc.h
@ -292,9 +292,6 @@ extern long double strtold (const char *__nptr, char **__endptr);
|
||||
#ifndef TCC_LIBTCC1
|
||||
# define TCC_LIBTCC1 "libtcc1.a"
|
||||
#endif
|
||||
#ifndef TCC_LIBTCCB1
|
||||
# define TCC_LIBTCCB1 "libtccb1.a"
|
||||
#endif
|
||||
|
||||
/* library to use with CONFIG_USE_LIBGCC instead of libtcc1.a */
|
||||
#if defined CONFIG_USE_LIBGCC && !defined TCC_LIBGCC
|
||||
@ -720,7 +717,6 @@ struct TCCState {
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* compile with built-in memory and bounds checker */
|
||||
unsigned char do_bounds_check;
|
||||
unsigned char do_bounds_check_address;
|
||||
#endif
|
||||
#ifdef TCC_TARGET_ARM
|
||||
enum float_abi float_abi; /* float ABI of the generated code*/
|
||||
@ -1250,7 +1246,7 @@ ST_FUNC int tcc_add_crt(TCCState *s, const char *filename);
|
||||
#endif
|
||||
ST_FUNC int tcc_add_dll(TCCState *s, const char *filename, int flags);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec);
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1);
|
||||
#endif
|
||||
ST_FUNC void tcc_add_pragma_libs(TCCState *s1);
|
||||
PUB_FUNC int tcc_add_library_err(TCCState *s, const char *f);
|
||||
@ -1437,6 +1433,9 @@ ST_FUNC Sym *get_sym_ref(CType *type, Section *sec, unsigned long offset, unsign
|
||||
#if defined TCC_TARGET_X86_64 && !defined TCC_TARGET_PE
|
||||
ST_FUNC int classify_x86_64_va_arg(CType *ty);
|
||||
#endif
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void gbound_args(int nb_args);
|
||||
#endif
|
||||
|
||||
/* ------------ tccelf.c ------------ */
|
||||
|
||||
|
4
tccelf.c
4
tccelf.c
@ -1321,7 +1321,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
||||
{
|
||||
s1->filetype = 0;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
tcc_add_bcheck(s1, bounds_section, symtab_section);
|
||||
tcc_add_bcheck(s1);
|
||||
#endif
|
||||
tcc_add_pragma_libs(s1);
|
||||
#ifndef TCC_TARGET_PE
|
||||
@ -1340,7 +1340,7 @@ ST_FUNC void tcc_add_runtime(TCCState *s1)
|
||||
if (s1->do_bounds_check && s1->output_type != TCC_OUTPUT_DLL) {
|
||||
tcc_add_library_err(s1, "pthread");
|
||||
tcc_add_library_err(s1, "dl");
|
||||
tcc_add_support(s1, TCC_LIBTCCB1);
|
||||
tcc_add_support(s1, "bcheck.o");
|
||||
}
|
||||
#endif
|
||||
tcc_add_support(s1, TCC_LIBTCC1);
|
||||
|
41
tccgen.c
41
tccgen.c
@ -1230,6 +1230,11 @@ ST_FUNC void save_reg_upstack(int r, int n)
|
||||
type = &int_type;
|
||||
#endif
|
||||
size = type_size(type, &align);
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
l = loc = (loc - size) & -align;
|
||||
else
|
||||
#endif
|
||||
l=get_temp_local_var(size,align);
|
||||
sv.type.t = type->t;
|
||||
sv.r = VT_LOCAL | VT_LVAL;
|
||||
@ -1417,7 +1422,7 @@ static void gbound(void)
|
||||
|
||||
vtop->r &= ~VT_MUSTBOUND;
|
||||
/* if lvalue, then use checking code before dereferencing */
|
||||
if ((vtop->r & VT_LVAL) && !nocode_wanted) {
|
||||
if (vtop->r & VT_LVAL) {
|
||||
/* if not VT_BOUNDED value, then make one */
|
||||
if (!(vtop->r & VT_BOUNDED)) {
|
||||
lval_type = vtop->r & (VT_LVAL_TYPE | VT_LVAL);
|
||||
@ -1434,6 +1439,19 @@ static void gbound(void)
|
||||
gen_bounded_ptr_deref();
|
||||
}
|
||||
}
|
||||
|
||||
/* we need to call __bound_ptr_add before we start to load function
|
||||
args into registers */
|
||||
ST_FUNC void gbound_args(int nb_args)
|
||||
{
|
||||
int i;
|
||||
for (i = 1; i <= nb_args; ++i)
|
||||
if (vtop[1 - i].r & VT_MUSTBOUND) {
|
||||
vrotb(i);
|
||||
gbound();
|
||||
vrott(i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
static void incr_bf_adr(int o)
|
||||
@ -2499,25 +2517,7 @@ redo:
|
||||
}
|
||||
gen_op('*');
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
/* The main reason to removing this code:
|
||||
#include <stdio.h>
|
||||
int main ()
|
||||
{
|
||||
int v[10];
|
||||
int i = 10;
|
||||
int j = 9;
|
||||
fprintf(stderr, "v+i-j = %p\n", v+i-j);
|
||||
fprintf(stderr, "v+(i-j) = %p\n", v+(i-j));
|
||||
}
|
||||
When this code is on. then the output looks like
|
||||
v+i-j = 0xfffffffe
|
||||
v+(i-j) = 0xbff84000
|
||||
This should now work in updated bcheck.c version.
|
||||
*/
|
||||
/* if evaluating constant expression, no code should be
|
||||
generated, so no bound check */
|
||||
if (tcc_state->do_bounds_check && tcc_state->do_bounds_check_address
|
||||
&& !const_wanted && !nocode_wanted) {
|
||||
if (tcc_state->do_bounds_check && !const_wanted) {
|
||||
/* if bounded pointers, we generate a special code to
|
||||
test bounds */
|
||||
if (op == '-') {
|
||||
@ -2525,6 +2525,7 @@ redo:
|
||||
vswap();
|
||||
gen_op('-');
|
||||
}
|
||||
vtop[-1].r &= ~VT_MUSTBOUND;
|
||||
gen_bounded_ptr_add();
|
||||
} else
|
||||
#endif
|
||||
|
36
tccpe.c
36
tccpe.c
@ -1836,6 +1836,12 @@ ST_FUNC void pe_add_unwind_data(unsigned start, unsigned end, unsigned stack)
|
||||
#define PE_STDSYM(n,s) "_" n s
|
||||
#endif
|
||||
|
||||
static void tcc_add_support(TCCState *s1, const char *filename)
|
||||
{
|
||||
if (tcc_add_dll(s1, filename, 0) < 0)
|
||||
tcc_error_noabort("%s not found", filename);
|
||||
}
|
||||
|
||||
static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||
{
|
||||
const char *start_symbol;
|
||||
@ -1884,35 +1890,21 @@ static void pe_add_runtime(TCCState *s1, struct pe_info *pe)
|
||||
|
||||
if (0 == s1->nostdlib) {
|
||||
static const char *libs[] = {
|
||||
TCC_LIBTCC1,
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
TCC_LIBTCCB1,
|
||||
#endif
|
||||
"msvcrt", "kernel32", "", "user32", "gdi32", NULL
|
||||
};
|
||||
const char **pp, *p;
|
||||
#ifdef TCC_IS_NATIVE
|
||||
if (s1->do_bounds_check)
|
||||
tcc_add_support(s1, "bcheck.o");
|
||||
#endif
|
||||
tcc_add_support(s1, TCC_LIBTCC1);
|
||||
for (pp = libs; 0 != (p = *pp); ++pp) {
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (pp == libs + 1 &&
|
||||
(s1->do_bounds_check == 0 || s1->output_type == TCC_OUTPUT_DLL)) {
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (0 == *p) {
|
||||
if (PE_DLL != pe_type && PE_GUI != pe_type)
|
||||
break;
|
||||
} else if (pp == libs && tcc_add_dll(s1, p, 0) >= 0) {
|
||||
continue;
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
} else if (pp == libs + 1 && tcc_add_dll(s1, p, 0) >= 0) {
|
||||
continue;
|
||||
#endif
|
||||
} else {
|
||||
if (*p)
|
||||
tcc_add_library_err(s1, p);
|
||||
}
|
||||
else if (PE_DLL != pe_type && PE_GUI != pe_type)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (TCC_OUTPUT_MEMORY == s1->output_type)
|
||||
pe_type = PE_RUN;
|
||||
pe->type = pe_type;
|
||||
|
7
tccpp.c
7
tccpp.c
@ -392,16 +392,15 @@ ST_FUNC void cstr_reset(CString *cstr)
|
||||
ST_FUNC int cstr_printf(CString *cstr, const char *fmt, ...)
|
||||
{
|
||||
va_list v;
|
||||
va_list vc;
|
||||
int len, size;
|
||||
|
||||
va_start(v, fmt);
|
||||
va_copy (vc, v);
|
||||
len = vsnprintf(NULL, 0, fmt, vc);
|
||||
va_end(vc);
|
||||
len = vsnprintf(NULL, 0, fmt, v);
|
||||
va_end(v);
|
||||
size = cstr->size + len + 1;
|
||||
if (size > cstr->size_allocated)
|
||||
cstr_realloc(cstr, size);
|
||||
va_start(v, fmt);
|
||||
vsnprintf((char*)cstr->data + cstr->size, size, fmt, v);
|
||||
va_end(v);
|
||||
cstr->size += len;
|
||||
|
3
tcctok.h
3
tcctok.h
@ -306,6 +306,9 @@
|
||||
DEF(TOK___bound_local_new, "__bound_local_new")
|
||||
DEF(TOK___bound_local_delete, "__bound_local_delete")
|
||||
# ifdef TCC_TARGET_PE
|
||||
# ifdef TCC_TARGET_X86_64
|
||||
DEF(TOK___bound_alloca_nr, "__bound_alloca_nr")
|
||||
# endif
|
||||
DEF(TOK_malloc, "malloc")
|
||||
DEF(TOK_free, "free")
|
||||
DEF(TOK_realloc, "realloc")
|
||||
|
@ -23,7 +23,7 @@ TESTS = \
|
||||
tests2-dir \
|
||||
pp-dir
|
||||
|
||||
BTESTS = test1b test3b btest test4
|
||||
BTESTS = btest test2b
|
||||
|
||||
# test4_static -- Not all relocation types are implemented yet.
|
||||
# asmtest / asmtest2 -- minor differences with gcc
|
||||
@ -115,7 +115,7 @@ test3 test3b: tcctest.c test.ref
|
||||
$(TCC) $(RUN_TCC) $(RUN_TCC) $(RUN_TCC) -run $< > test.out3
|
||||
@diff -u test.ref test.out3 && echo "Auto Test3 OK"
|
||||
|
||||
test%b : TCCFLAGS += -b -ba
|
||||
test%b : TCCFLAGS += -b
|
||||
|
||||
# binary output test
|
||||
test4: tcctest.c test.ref
|
||||
@ -130,7 +130,7 @@ test4: tcctest.c test.ref
|
||||
./tcctest1 > test1.out
|
||||
@if diff -u test.ref test1.out ; then echo "Dynamic Auto Test OK"; fi
|
||||
# dynamic output + bound check
|
||||
$(TCC) -b -ba -o tcctest4 $<
|
||||
$(TCC) -b -o tcctest4 $<
|
||||
./tcctest4 > test4.out
|
||||
@if diff -u test.ref test4.out ; then echo "BCheck Auto Test OK"; fi
|
||||
|
||||
@ -163,15 +163,14 @@ memtest:
|
||||
|
||||
|
||||
# memory and bound check auto test
|
||||
BOUNDS_OK = 1 3 4 8 10 14 16
|
||||
BOUNDS_OK = 1 4 8 10 14 16
|
||||
BOUNDS_FAIL= 2 5 6 7 9 11 12 13 15 17
|
||||
|
||||
btest: boundtest.c
|
||||
@echo ------------ $@ ------------
|
||||
@ulimit -c 0; \
|
||||
for i in $(BOUNDS_OK); do \
|
||||
@for i in $(BOUNDS_OK); do \
|
||||
echo ; echo --- boundtest $$i ---; \
|
||||
if $(TCC) -b -ba -run $< $$i ; then \
|
||||
if $(TCC) -b -run $< $$i ; then \
|
||||
echo succeeded as expected; \
|
||||
else\
|
||||
echo Failed positive test $$i ; exit 1 ; \
|
||||
@ -179,7 +178,7 @@ btest: boundtest.c
|
||||
done ;\
|
||||
for i in $(BOUNDS_FAIL); do \
|
||||
echo ; echo --- boundtest $$i ---; \
|
||||
if $(TCC) -b -ba -run $< $$i ; then \
|
||||
if $(TCC) -b -run $< $$i ; then \
|
||||
echo Failed negative test $$i ; exit 1 ;\
|
||||
else\
|
||||
echo failed as expected; \
|
||||
|
267
x86_64-gen.c
267
x86_64-gen.c
@ -142,9 +142,6 @@ ST_DATA const int reg_classes[NB_REGS] = {
|
||||
|
||||
static unsigned long func_sub_sp_offset;
|
||||
static int func_ret_sub;
|
||||
static int nested_call;
|
||||
static int call_used_nr_reg;
|
||||
static int call_used_regs[20];
|
||||
|
||||
/* XXX: make it faster ? */
|
||||
ST_FUNC void g(int c)
|
||||
@ -654,218 +651,19 @@ static void gen_bounds_call(int v)
|
||||
#endif
|
||||
}
|
||||
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1, Section *bound_sec, Section *sym_sec)
|
||||
{
|
||||
addr_t *ptr;
|
||||
int loc_glob;
|
||||
int sym_index;
|
||||
int bsym_index;
|
||||
|
||||
if (0 == s1->do_bounds_check)
|
||||
return;
|
||||
/* XXX: add an object file to do that */
|
||||
ptr = section_ptr_add(bound_sec, sizeof(*ptr));
|
||||
*ptr = 0;
|
||||
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
|
||||
bsym_index = set_elf_sym(sym_sec, 0, 0,
|
||||
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
|
||||
bound_sec->sh_num, "__bounds_start");
|
||||
/* pull bcheck.o from libtcc1.a */
|
||||
sym_index = set_elf_sym(sym_sec, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bound_init");
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
Section *init_section = find_section(s1, ".init");
|
||||
unsigned char *pinit;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pinit = section_ptr_add(init_section, 8);
|
||||
pinit[0] = 0x55; /* push %rbp */
|
||||
pinit[1] = 0x48; /* mov %rsp,%rpb */
|
||||
pinit[2] = 0x89;
|
||||
pinit[3] = 0xe5;
|
||||
pinit[4] = 0x48; /* sub $0x10,%rsp */
|
||||
pinit[5] = 0x83;
|
||||
pinit[6] = 0xec;
|
||||
pinit[7] = 0x10;
|
||||
#endif
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(sym_sec, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
pinit = section_ptr_add(init_section, 13);
|
||||
pinit[0] = 0x48; /* mov xx,%rax */
|
||||
pinit[1] = 0xb8;
|
||||
write64le(pinit + 2, 0);
|
||||
#ifdef TCC_TARGET_PE
|
||||
pinit[10] = 0x48; /* mov %rax,%rcx */
|
||||
pinit[11] = 0x89;
|
||||
pinit[12] = 0xc1;
|
||||
#else
|
||||
pinit[10] = 0x48; /* mov %rax,%rdi */
|
||||
pinit[11] = 0x89;
|
||||
pinit[12] = 0xc7;
|
||||
#endif
|
||||
put_elf_reloc(sym_sec, init_section,
|
||||
init_section->data_offset - 11, R_X86_64_64, bsym_index);
|
||||
sym_index = set_elf_sym(sym_sec, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bounds_add_static_var");
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(sym_sec, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
#ifdef TCC_TARGET_PE
|
||||
{
|
||||
int init_index = set_elf_sym(sym_sec,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
init_section->sh_num, "__init_start");
|
||||
Sym sym;
|
||||
init_section->sh_flags |= SHF_EXECINSTR;
|
||||
pinit = section_ptr_add(init_section, 2);
|
||||
pinit[0] = 0xc9; /* leave */
|
||||
pinit[1] = 0xc3; /* ret */
|
||||
sym.c = init_index;
|
||||
add_init_array (s1, &sym);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* generate a bounded pointer addition */
|
||||
ST_FUNC void gen_bounded_ptr_add(void)
|
||||
{
|
||||
int i;
|
||||
|
||||
nested_call++;
|
||||
|
||||
/* save all temporary registers */
|
||||
save_regs(0);
|
||||
|
||||
for (i = 0; i < call_used_nr_reg; i++) {
|
||||
switch (call_used_regs[i]) {
|
||||
case TREG_RAX: case TREG_RCX: case TREG_RDX: case TREG_RSP:
|
||||
case TREG_RSI: case TREG_RDI:
|
||||
o(0x50 + call_used_regs[i]); /* push reg */
|
||||
break;
|
||||
case TREG_R8: case TREG_R9: case TREG_R10: case TREG_R11:
|
||||
o(0x5041 + (call_used_regs[i] - TREG_R8) * 0x100); /* push reg */
|
||||
break;
|
||||
case TREG_XMM0: case TREG_XMM1: case TREG_XMM2: case TREG_XMM3:
|
||||
case TREG_XMM4: case TREG_XMM5: case TREG_XMM6: case TREG_XMM7:
|
||||
o(0x10ec8348); /* sub $10,%rsp */
|
||||
/* vmovdqu %xmmx,(%rsp) */
|
||||
o(0x047ffac5 + (call_used_regs[i] - TREG_XMM0) * 0x8000000); o(0x24);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nested_call > 1) {
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0x5152); /* push %rdx/%rcx */
|
||||
o(0x51415041); /* push %r8/%r9 */
|
||||
#else
|
||||
o(0x51525657); /* push %rdi/%rsi/%rdx/%rcx */
|
||||
#endif
|
||||
}
|
||||
/* prepare fast x86_64 function call */
|
||||
gv(RC_RAX);
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0xc28948); // mov %rax,%rdx ## second arg in %rdx, this must be size
|
||||
#else
|
||||
o(0xc68948); // mov %rax,%rsi ## second arg in %rsi, this must be size
|
||||
#endif
|
||||
vtop--;
|
||||
|
||||
gv(RC_RAX);
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0xc18948); // mov %rax,%rcx ## first arg in %rcx, this must be ptr
|
||||
#else
|
||||
o(0xc78948); // mov %rax,%rdi ## first arg in %rdi, this must be ptr
|
||||
#endif
|
||||
vtop--;
|
||||
|
||||
/* add line, filename */
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0xc0c749); /* mov $xx,%r8 */
|
||||
#else
|
||||
o(0xba); /* mov $xx,%edx */
|
||||
#endif
|
||||
gen_le32 (file->line_num);
|
||||
{
|
||||
static addr_t offset;
|
||||
static char last_filename[1024];
|
||||
Sym *sym_data;
|
||||
|
||||
if (strcmp (last_filename, file->filename) != 0) {
|
||||
void *ptr;
|
||||
int len = strlen (file->filename) + 1;
|
||||
|
||||
offset = data_section->data_offset;
|
||||
ptr = section_ptr_add(data_section, len);
|
||||
memcpy (ptr, file->filename, len);
|
||||
memcpy (last_filename, file->filename, len);
|
||||
}
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0xb949); /* mov $xx,%r9 */
|
||||
#else
|
||||
o(0xb948); /* mov $xx,%rcx */
|
||||
#endif
|
||||
gen_le64 (0);
|
||||
sym_data = get_sym_ref(&char_pointer_type, data_section,
|
||||
offset, data_section->data_offset);
|
||||
greloca(cur_text_section, sym_data, ind - 8, R_X86_64_64, 0);
|
||||
}
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0x20ec8348); /* sub $20, %rsp */
|
||||
#endif
|
||||
|
||||
/* do a fast function call */
|
||||
gen_bounds_call(TOK___bound_ptr_add);
|
||||
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0x20c48348); /* add $20, %rsp */
|
||||
#endif
|
||||
|
||||
if (nested_call > 1) {
|
||||
#ifdef TCC_TARGET_PE
|
||||
o(0x58415941); /* pop %r9/%r8 */
|
||||
o(0x5a59); /* pop %rcx/%rdx */
|
||||
#else
|
||||
o(0x5f5e5a59); /* pop $rcx/%rdx/%rsi/%rdi */
|
||||
#endif
|
||||
}
|
||||
vpush_global_sym(&func_old_type, TOK___bound_ptr_add);
|
||||
vrott(3);
|
||||
gfunc_call(2);
|
||||
vpushi(0);
|
||||
/* returned pointer is in rax */
|
||||
vtop++;
|
||||
vtop->r = TREG_RAX | VT_BOUNDED;
|
||||
|
||||
for (i = call_used_nr_reg - 1; i >= 0; i--) {
|
||||
switch (call_used_regs[i]) {
|
||||
case TREG_RAX: case TREG_RCX: case TREG_RDX: case TREG_RSP:
|
||||
case TREG_RSI: case TREG_RDI:
|
||||
o(0x58 + call_used_regs[i]); /* pop reg */
|
||||
break;
|
||||
case TREG_R8: case TREG_R9: case TREG_R10: case TREG_R11:
|
||||
o(0x5841 + (call_used_regs[i] - TREG_R8) * 0x100); /* pop reg */
|
||||
break;
|
||||
case TREG_XMM0: case TREG_XMM1: case TREG_XMM2: case TREG_XMM3:
|
||||
case TREG_XMM4: case TREG_XMM5: case TREG_XMM6: case TREG_XMM7:
|
||||
/* vmovdqu (%rsp),%xmmx */
|
||||
o(0x046ffac5 + (call_used_regs[i] - TREG_XMM0) * 0x8000000); o(0x24);
|
||||
o(0x10c48348); /* add $10,%rsp */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
/* relocation offset of the bounding function call point */
|
||||
vtop->c.i = (cur_text_section->reloc->data_offset - sizeof(ElfW(Rela)));
|
||||
nested_call--;
|
||||
}
|
||||
|
||||
/* patch pointer addition in vtop so that pointer dereferencing is
|
||||
@ -877,6 +675,9 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
ElfW(Rela) *rel;
|
||||
Sym *sym;
|
||||
|
||||
if (nocode_wanted)
|
||||
return;
|
||||
|
||||
size = 0;
|
||||
/* XXX: put that code in generic part of tcc */
|
||||
if (!is_float(vtop->type.t)) {
|
||||
@ -886,7 +687,7 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
size = 2;
|
||||
}
|
||||
if (!size)
|
||||
size = type_size(&vtop->type, &align);
|
||||
size = type_size(&vtop->type, &align);
|
||||
switch(size) {
|
||||
case 1: func = TOK___bound_ptr_indir1; break;
|
||||
case 2: func = TOK___bound_ptr_indir2; break;
|
||||
@ -895,18 +696,17 @@ ST_FUNC void gen_bounded_ptr_deref(void)
|
||||
case 12: func = TOK___bound_ptr_indir12; break;
|
||||
case 16: func = TOK___bound_ptr_indir16; break;
|
||||
default:
|
||||
tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
func = 0;
|
||||
break;
|
||||
/* may happen with struct member access */
|
||||
return;
|
||||
//tcc_error("unhandled size when dereferencing bounded pointer");
|
||||
//func = 0;
|
||||
//break;
|
||||
}
|
||||
|
||||
sym = external_global_sym(func, &func_old_type);
|
||||
if (!sym->c)
|
||||
put_extern_sym(sym, NULL, 0, 0);
|
||||
|
||||
/* patch relocation */
|
||||
/* XXX: find a better solution ? */
|
||||
|
||||
rel = (ElfW(Rela) *)(cur_text_section->reloc->data + vtop->c.i);
|
||||
rel->r_info = ELF64_R_INFO(sym->c, ELF64_R_TYPE(rel->r_info));
|
||||
}
|
||||
@ -992,6 +792,11 @@ void gfunc_call(int nb_args)
|
||||
int size, r, args_size, i, d, bt, struct_size;
|
||||
int arg;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
args_size = (nb_args < REGN ? REGN : nb_args) * PTR_SIZE;
|
||||
arg = nb_args;
|
||||
|
||||
@ -1051,7 +856,6 @@ void gfunc_call(int nb_args)
|
||||
} else {
|
||||
d = arg_prepare_reg(arg);
|
||||
gen_offs_sp(0x8d, d, struct_size);
|
||||
call_used_regs[call_used_nr_reg++] = d;
|
||||
}
|
||||
struct_size += size;
|
||||
} else {
|
||||
@ -1070,7 +874,6 @@ void gfunc_call(int nb_args)
|
||||
o(0x66);
|
||||
orex(1,d,0, 0x7e0f);
|
||||
o(0xc0 + arg*8 + REG_VALUE(d));
|
||||
call_used_regs[call_used_nr_reg++] = d;
|
||||
}
|
||||
} else {
|
||||
if (bt == VT_STRUCT) {
|
||||
@ -1086,7 +889,6 @@ void gfunc_call(int nb_args)
|
||||
d = arg_prepare_reg(arg);
|
||||
orex(1,d,r,0x89); /* mov */
|
||||
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
|
||||
call_used_regs[call_used_nr_reg++] = d;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1105,7 +907,12 @@ void gfunc_call(int nb_args)
|
||||
|
||||
if ((vtop->r & VT_SYM) && vtop->sym->v == TOK_alloca) {
|
||||
/* need to add the "func_scratch" area after alloca */
|
||||
o(0x48); func_alloca = oad(0x2d, func_alloca); /* sub $NN, %rax */
|
||||
o(0x48); func_alloca = oad(0x05, func_alloca); /* add $NN, %rax */
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gen_bounds_call(TOK___bound_alloca_nr); /* new region */
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/* other compilers don't clear the upper bits when returning char/short */
|
||||
@ -1125,7 +932,6 @@ void gfunc_call(int nb_args)
|
||||
o(0xc089); /* mov %eax,%eax */
|
||||
#endif
|
||||
vtop--;
|
||||
call_used_nr_reg = 0;
|
||||
}
|
||||
|
||||
|
||||
@ -1141,7 +947,7 @@ void gfunc_prolog(Sym *func_sym)
|
||||
int n_arg = 0;
|
||||
|
||||
func_ret_sub = 0;
|
||||
func_scratch = 0;
|
||||
func_scratch = 32;
|
||||
func_alloca = 0;
|
||||
loc = 0;
|
||||
|
||||
@ -1228,6 +1034,10 @@ void gfunc_epilog(void)
|
||||
{
|
||||
int v, saved_ind;
|
||||
|
||||
/* align local size to word & save local variables */
|
||||
func_scratch = (func_scratch + 15) & -16;
|
||||
loc = (loc & -16) - func_scratch;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check
|
||||
&& func_bound_offset != lbounds_section->data_offset)
|
||||
@ -1273,9 +1083,7 @@ void gfunc_epilog(void)
|
||||
|
||||
saved_ind = ind;
|
||||
ind = func_sub_sp_offset - FUNC_PROLOG_SIZE;
|
||||
/* align local size to word & save local variables */
|
||||
func_scratch = (func_scratch + 15) & -16;
|
||||
v = (func_scratch + -loc + 15) & -16;
|
||||
v = -loc;
|
||||
|
||||
if (v >= 4096) {
|
||||
Sym *sym = external_global_sym(TOK___chkstk, &func_old_type);
|
||||
@ -1479,6 +1287,11 @@ void gfunc_call(int nb_args)
|
||||
int sse_reg, gen_reg;
|
||||
char _onstack[nb_args ? nb_args : 1], *onstack = _onstack;
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
if (tcc_state->do_bounds_check)
|
||||
gbound_args(nb_args);
|
||||
#endif
|
||||
|
||||
/* calculate the number of integer/float register arguments, remember
|
||||
arguments to be passed via stack (in onstack[]), and also remember
|
||||
if we have to align the stack pointer to 16 (onstack[i] == 2). Needs
|
||||
@ -1611,14 +1424,11 @@ void gfunc_call(int nb_args)
|
||||
o(0x280f);
|
||||
o(0xc0 + (sse_reg << 3));
|
||||
}
|
||||
call_used_regs[call_used_nr_reg++] = sse_reg + TREG_XMM0;
|
||||
call_used_regs[call_used_nr_reg++] = sse_reg + 1 + TREG_XMM0;
|
||||
} else {
|
||||
assert(reg_count == 1);
|
||||
--sse_reg;
|
||||
/* Load directly to register */
|
||||
gv(RC_XMM0 << sse_reg);
|
||||
call_used_regs[call_used_nr_reg++] = sse_reg + TREG_XMM0;
|
||||
}
|
||||
} else if (mode == x86_64_mode_integer) {
|
||||
/* simple type */
|
||||
@ -1629,12 +1439,10 @@ void gfunc_call(int nb_args)
|
||||
d = arg_prepare_reg(gen_reg);
|
||||
orex(1,d,r,0x89); /* mov */
|
||||
o(0xc0 + REG_VALUE(r) * 8 + REG_VALUE(d));
|
||||
call_used_regs[call_used_nr_reg++] = d;
|
||||
if (reg_count == 2) {
|
||||
d = arg_prepare_reg(gen_reg+1);
|
||||
orex(1,d,vtop->r2,0x89); /* mov */
|
||||
o(0xc0 + REG_VALUE(vtop->r2) * 8 + REG_VALUE(d));
|
||||
call_used_regs[call_used_nr_reg++] = d;
|
||||
}
|
||||
}
|
||||
vtop--;
|
||||
@ -1677,7 +1485,6 @@ void gfunc_call(int nb_args)
|
||||
else if (bt == (VT_SHORT | VT_UNSIGNED))
|
||||
o(0xc0b70f); /* movzwl %al, %eax */
|
||||
vtop--;
|
||||
call_used_nr_reg = 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -287,4 +287,89 @@ void relocate(TCCState *s1, ElfW_Rel *rel, int type, unsigned char *ptr, addr_t
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TCC_BCHECK
|
||||
ST_FUNC void tcc_add_bcheck(TCCState *s1)
|
||||
{
|
||||
addr_t *ptr;
|
||||
int loc_glob;
|
||||
int sym_index;
|
||||
int bsym_index;
|
||||
|
||||
if (0 == s1->do_bounds_check)
|
||||
return;
|
||||
/* XXX: add an object file to do that */
|
||||
ptr = section_ptr_add(bounds_section, sizeof(*ptr));
|
||||
*ptr = 0;
|
||||
loc_glob = s1->output_type != TCC_OUTPUT_MEMORY ? STB_LOCAL : STB_GLOBAL;
|
||||
bsym_index = set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(loc_glob, STT_NOTYPE), 0,
|
||||
bounds_section->sh_num, "__bounds_start");
|
||||
/* pull bcheck.o from libtcc1.a */
|
||||
sym_index = set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bound_init");
|
||||
if (s1->output_type != TCC_OUTPUT_MEMORY) {
|
||||
/* add 'call __bound_init()' in .init section */
|
||||
Section *init_section = find_section(s1, ".init");
|
||||
unsigned char *pinit;
|
||||
#ifdef TCC_TARGET_PE
|
||||
pinit = section_ptr_add(init_section, 8);
|
||||
pinit[0] = 0x55; /* push %rbp */
|
||||
pinit[1] = 0x48; /* mov %rsp,%rpb */
|
||||
pinit[2] = 0x89;
|
||||
pinit[3] = 0xe5;
|
||||
pinit[4] = 0x48; /* sub $0x10,%rsp */
|
||||
pinit[5] = 0x83;
|
||||
pinit[6] = 0xec;
|
||||
pinit[7] = 0x10;
|
||||
#endif
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
pinit = section_ptr_add(init_section, 13);
|
||||
pinit[0] = 0x48; /* mov xx,%rax */
|
||||
pinit[1] = 0xb8;
|
||||
write64le(pinit + 2, 0);
|
||||
#ifdef TCC_TARGET_PE
|
||||
pinit[10] = 0x48; /* mov %rax,%rcx */
|
||||
pinit[11] = 0x89;
|
||||
pinit[12] = 0xc1;
|
||||
#else
|
||||
pinit[10] = 0x48; /* mov %rax,%rdi */
|
||||
pinit[11] = 0x89;
|
||||
pinit[12] = 0xc7;
|
||||
#endif
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 11, R_X86_64_64, bsym_index);
|
||||
sym_index = set_elf_sym(symtab_section, 0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
SHN_UNDEF, "__bounds_add_static_var");
|
||||
pinit = section_ptr_add(init_section, 5);
|
||||
pinit[0] = 0xe8;
|
||||
write32le(pinit + 1, -4);
|
||||
put_elf_reloc(symtab_section, init_section,
|
||||
init_section->data_offset - 4, R_386_PC32, sym_index);
|
||||
/* R_386_PC32 = R_X86_64_PC32 = 2 */
|
||||
#ifdef TCC_TARGET_PE
|
||||
{
|
||||
int init_index = set_elf_sym(symtab_section,
|
||||
0, 0,
|
||||
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
|
||||
init_section->sh_num, "__init_start");
|
||||
Sym sym;
|
||||
init_section->sh_flags |= SHF_EXECINSTR;
|
||||
pinit = section_ptr_add(init_section, 2);
|
||||
pinit[0] = 0xc9; /* leave */
|
||||
pinit[1] = 0xc3; /* ret */
|
||||
sym.c = init_index;
|
||||
add_init_array (s1, &sym);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* !TARGET_DEFS_ONLY */
|
||||
|
Loading…
Reference in New Issue
Block a user