alternative int tcc_relocate(TCCState *s1, void *ptr);

This commit is contained in:
grischka 2009-04-16 22:03:03 +02:00
parent 9a8b2912ed
commit 795f67428e
3 changed files with 80 additions and 74 deletions

View File

@ -84,9 +84,10 @@ int tcc_output_file(TCCState *s, const char *filename);
tcc_relocate() before. */ tcc_relocate() before. */
int tcc_run(TCCState *s, int argc, char **argv); int tcc_run(TCCState *s, int argc, char **argv);
/* do all relocations (needed before using tcc_get_symbol()). Return /* copy code into memory passed in by the caller and do all relocations
non zero if link error. */ (needed before using tcc_get_symbol()).
int tcc_relocate(TCCState *s); returns -1 on error and required size if ptr is NULL */
int tcc_relocate(TCCState *s1, void *ptr);
/* return symbol value. return 0 if OK, -1 if symbol not found */ /* return symbol value. return 0 if OK, -1 if symbol not found */
int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name); int tcc_get_symbol(TCCState *s, unsigned long *pval, const char *name);

View File

@ -36,6 +36,8 @@ int main(int argc, char **argv)
TCCState *s; TCCState *s;
int (*func)(int); int (*func)(int);
unsigned long val; unsigned long val;
void *mem;
int size;
s = tcc_new(); s = tcc_new();
if (!s) { if (!s) {
@ -53,13 +55,25 @@ int main(int argc, char **argv)
with tcc_add_dll(() and using its symbols directly. */ with tcc_add_dll(() and using its symbols directly. */
tcc_add_symbol(s, "add", (unsigned long)&add); tcc_add_symbol(s, "add", (unsigned long)&add);
tcc_relocate(s); /* get needed size of the code */
size = tcc_relocate(s, NULL);
if (size == -1)
return 1;
/* allocate memory and copy the code into it */
mem = malloc(size);
tcc_relocate(s, mem);
/* get entry symbol */
tcc_get_symbol(s, &val, "foo"); tcc_get_symbol(s, &val, "foo");
func = (void *)val; func = (void *)val;
/* delete the state */
tcc_delete(s);
/* run the code */
func(32); func(32);
tcc_delete(s); free(mem);
return 0; return 0;
} }

129
tcc.c
View File

@ -542,6 +542,9 @@ struct TCCState {
/* output file for preprocessing */ /* output file for preprocessing */
FILE *outfile; FILE *outfile;
/* for tcc_relocate */
int runtime_added;
}; };
/* The current value can be: */ /* The current value can be: */
@ -10277,88 +10280,61 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc)
} }
#endif #endif
/* do all relocations (needed before using tcc_get_symbol()) */ /* copy code into memory passed in by the caller and do all relocations
int tcc_relocate(TCCState *s1) (needed before using tcc_get_symbol()).
returns -1 on error and required size if ptr is NULL */
int tcc_relocate(TCCState *s1, void *ptr)
{ {
Section *s; Section *s;
unsigned long offset, length, mem;
int i; int i;
s1->nb_errors = 0; s1->nb_errors = 0;
if (0 == s1->runtime_added) {
#ifdef TCC_TARGET_PE #ifdef TCC_TARGET_PE
pe_add_runtime(s1); pe_add_runtime(s1);
relocate_common_syms();
tcc_add_linker_symbols(s1);
#else #else
tcc_add_runtime(s1); tcc_add_runtime(s1);
relocate_common_syms();
tcc_add_linker_symbols(s1);
build_got_entries(s1);
#endif #endif
s1->runtime_added = 1;
relocate_common_syms();
tcc_add_linker_symbols(s1);
#ifndef TCC_TARGET_PE
build_got_entries(s1);
#endif
#ifdef TCC_TARGET_X86_64
{
/* If the distance of two sections are longer than 32bit, our
program will crash. Let's combine all sections which are
necessary to run the program into a single buffer in the
text section */
unsigned char *p;
int size;
/* calculate the size of buffers we need */
size = 0;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_flags & SHF_ALLOC) {
size += s->data_offset;
}
}
/* double the size of the buffer for got and plt entries
XXX: calculate exact size for them? */
section_realloc(text_section, size * 2);
p = text_section->data + text_section->data_offset;
/* we will put got and plt after this offset */
text_section->data_offset = size;
for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i];
if (s->sh_flags & SHF_ALLOC) {
if (s != text_section && s->data_offset) {
if (s->sh_type == SHT_NOBITS) {
/* for bss section */
memset(p, 0, s->data_offset);
} else {
memcpy(p, s->data, s->data_offset);
tcc_free(s->data);
}
s->data = p;
/* we won't free s->data for this section */
s->data_allocated = 0;
p += s->data_offset;
}
s->sh_addr = (unsigned long)s->data;
}
}
} }
#else
/* compute relocation address : section are relocated in place. We offset = 0;
also alloc the bss space */ mem = (unsigned long)ptr;
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
if (s->sh_flags & SHF_ALLOC) { if (0 == (s->sh_flags & SHF_ALLOC))
continue;
length = s->data_offset;
if (0 == mem) {
s->sh_addr = 0;
} else if (1 == mem) {
/* section are relocated in place.
We also alloc the bss space */
if (s->sh_type == SHT_NOBITS) if (s->sh_type == SHT_NOBITS)
s->data = tcc_mallocz(s->data_offset); s->data = tcc_malloc(length);
s->sh_addr = (unsigned long)s->data; s->sh_addr = (unsigned long)s->data;
} else {
/* sections are relocated to new memory */
s->sh_addr = (mem + offset + 15) & ~15;
} }
offset = (offset + length + 15) & ~15;
} }
#endif
/* relocate symbols */
relocate_syms(s1, 1); relocate_syms(s1, 1);
if (s1->nb_errors)
if (s1->nb_errors != 0)
return -1; return -1;
if (0 == mem)
return offset + 15;
/* relocate each section */ /* relocate each section */
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
@ -10366,12 +10342,20 @@ int tcc_relocate(TCCState *s1)
relocate_section(s1, s); relocate_section(s1, s);
} }
/* mark executable sections as executable in memory */
for(i = 1; i < s1->nb_sections; i++) { for(i = 1; i < s1->nb_sections; i++) {
s = s1->sections[i]; s = s1->sections[i];
if ((s->sh_flags & (SHF_ALLOC | SHF_EXECINSTR)) == if (0 == (s->sh_flags & SHF_ALLOC))
(SHF_ALLOC | SHF_EXECINSTR)) continue;
set_pages_executable(s->data, s->data_offset); length = s->data_offset;
// printf("%-12s %08x %04x\n", s->name, s->sh_addr, length);
ptr = (void*)s->sh_addr;
if (NULL == s->data || s->sh_type == SHT_NOBITS)
memset(ptr, 0, length);
else if (ptr != s->data)
memcpy(ptr, s->data, length);
/* mark executable sections as executable in memory */
if (s->sh_flags & SHF_EXECINSTR)
set_pages_executable(ptr, length);
} }
return 0; return 0;
} }
@ -10380,9 +10364,14 @@ int tcc_relocate(TCCState *s1)
int tcc_run(TCCState *s1, int argc, char **argv) int tcc_run(TCCState *s1, int argc, char **argv)
{ {
int (*prog_main)(int, char **); int (*prog_main)(int, char **);
void *ptr;
int ret;
if (tcc_relocate(s1) < 0) ret = tcc_relocate(s1, NULL);
if (ret < 0)
return -1; return -1;
ptr = tcc_malloc(ret);
tcc_relocate(s1, ptr);
prog_main = tcc_get_symbol_err(s1, "main"); prog_main = tcc_get_symbol_err(s1, "main");
@ -10417,7 +10406,9 @@ int tcc_run(TCCState *s1, int argc, char **argv)
bound_init(); bound_init();
} }
#endif #endif
return (*prog_main)(argc, argv); ret = (*prog_main)(argc, argv);
tcc_free(ptr);
return ret;
} }
void tcc_memstats(void) void tcc_memstats(void)