| @@ -542,6 +542,9 @@ struct TCCState { · 541 unmodified lines |
| 542 | 542 | |
| 543 | 543 | /* output file for preprocessing */ |
| 544 | 544 | FILE *outfile; |
| 545 | + |
| 546 | + /* for tcc_relocate */ |
| 547 | + int runtime_added; |
| 545 | 548 | }; |
| 546 | 549 | |
| 547 | 550 | /* The current value can be: */ |
| @@ -10277,88 +10280,61 @@ static void sig_error(int signum, siginfo_t *siginf, void *puc) · 9729 unmodified lines |
| 10277 | 10280 | } |
| 10278 | 10281 | #endif |
| 10279 | 10282 | |
| 10280 | | −/* do all relocations (needed before using tcc_get_symbol()) */ |
| 10281 | | −int tcc_relocate(TCCState *s1) |
| 10283 | +/* copy code into memory passed in by the caller and do all relocations |
| 10284 | + (needed before using tcc_get_symbol()). |
| 10285 | + returns -1 on error and required size if ptr is NULL */ |
| 10286 | +int tcc_relocate(TCCState *s1, void *ptr) |
| 10282 | 10287 | { |
| 10283 | 10288 | Section *s; |
| 10289 | + unsigned long offset, length, mem; |
| 10284 | 10290 | int i; |
| 10285 | 10291 | |
| 10286 | 10292 | s1->nb_errors = 0; |
| 10287 | | − |
| 10293 | + |
| 10294 | + if (0 == s1->runtime_added) { |
| 10288 | 10295 | #ifdef TCC_TARGET_PE |
| 10289 | | − pe_add_runtime(s1); |
| 10296 | + pe_add_runtime(s1); |
| 10297 | + relocate_common_syms(); |
| 10298 | + tcc_add_linker_symbols(s1); |
| 10290 | 10299 | #else |
| 10291 | | − tcc_add_runtime(s1); |
| 10292 | | −#endif |
| 10293 | | − |
| 10294 | | − relocate_common_syms(); |
| 10295 | | − |
| 10296 | | − tcc_add_linker_symbols(s1); |
| 10297 | | −#ifndef TCC_TARGET_PE |
| 10298 | | − build_got_entries(s1); |
| 10300 | + tcc_add_runtime(s1); |
| 10301 | + relocate_common_syms(); |
| 10302 | + tcc_add_linker_symbols(s1); |
| 10303 | + build_got_entries(s1); |
| 10299 | 10304 | #endif |
| 10300 | | − |
| 10301 | | −#ifdef TCC_TARGET_X86_64 |
| 10302 | | − { |
| 10303 | | − /* If the distance of two sections are longer than 32bit, our |
| 10304 | | − program will crash. Let's combine all sections which are |
| 10305 | | − necessary to run the program into a single buffer in the |
| 10306 | | − text section */ |
| 10307 | | − unsigned char *p; |
| 10308 | | − int size; |
| 10309 | | − /* calculate the size of buffers we need */ |
| 10310 | | − size = 0; |
| 10311 | | − for(i = 1; i < s1->nb_sections; i++) { |
| 10312 | | − s = s1->sections[i]; |
| 10313 | | − if (s->sh_flags & SHF_ALLOC) { |
| 10314 | | − size += s->data_offset; |
| 10315 | | − } |
| 10316 | | − } |
| 10317 | | − /* double the size of the buffer for got and plt entries |
| 10318 | | − XXX: calculate exact size for them? */ |
| 10319 | | − section_realloc(text_section, size * 2); |
| 10320 | | − p = text_section->data + text_section->data_offset; |
| 10321 | | − /* we will put got and plt after this offset */ |
| 10322 | | − text_section->data_offset = size; |
| 10323 | | − |
| 10324 | | − for(i = 1; i < s1->nb_sections; i++) { |
| 10325 | | − s = s1->sections[i]; |
| 10326 | | − if (s->sh_flags & SHF_ALLOC) { |
| 10327 | | − if (s != text_section && s->data_offset) { |
| 10328 | | − if (s->sh_type == SHT_NOBITS) { |
| 10329 | | − /* for bss section */ |
| 10330 | | − memset(p, 0, s->data_offset); |
| 10331 | | − } else { |
| 10332 | | − memcpy(p, s->data, s->data_offset); |
| 10333 | | − tcc_free(s->data); |
| 10334 | | − } |
| 10335 | | − s->data = p; |
| 10336 | | − /* we won't free s->data for this section */ |
| 10337 | | − s->data_allocated = 0; |
| 10338 | | − p += s->data_offset; |
| 10339 | | − } |
| 10340 | | − s->sh_addr = (unsigned long)s->data; |
| 10341 | | − } |
| 10342 | | − } |
| 10305 | + s1->runtime_added = 1; |
| 10343 | 10306 | } |
| 10344 | | −#else |
| 10345 | | − /* compute relocation address : section are relocated in place. We |
| 10346 | | − also alloc the bss space */ |
| 10307 | + |
| 10308 | + offset = 0; |
| 10309 | + mem = (unsigned long)ptr; |
| 10347 | 10310 | for(i = 1; i < s1->nb_sections; i++) { |
| 10348 | 10311 | s = s1->sections[i]; |
| 10349 | | − if (s->sh_flags & SHF_ALLOC) { |
| 10312 | + if (0 == (s->sh_flags & SHF_ALLOC)) |
| 10313 | + continue; |
| 10314 | + length = s->data_offset; |
| 10315 | + if (0 == mem) { |
| 10316 | + s->sh_addr = 0; |
| 10317 | + } else if (1 == mem) { |
| 10318 | + /* section are relocated in place. |
| 10319 | + We also alloc the bss space */ |
| 10350 | 10320 | if (s->sh_type == SHT_NOBITS) |
| 10351 | | − s->data = tcc_mallocz(s->data_offset); |
| 10321 | + s->data = tcc_malloc(length); |
| 10352 | 10322 | s->sh_addr = (unsigned long)s->data; |
| 10323 | + } else { |
| 10324 | + /* sections are relocated to new memory */ |
| 10325 | + s->sh_addr = (mem + offset + 15) & ~15; |
| 10353 | 10326 | } |
| 10327 | + offset = (offset + length + 15) & ~15; |
| 10354 | 10328 | } |
| 10355 | | −#endif |
| 10356 | 10329 | |
| 10330 | + /* relocate symbols */ |
| 10357 | 10331 | relocate_syms(s1, 1); |
| 10358 | | − |
| 10359 | | − if (s1->nb_errors != 0) |
| 10332 | + if (s1->nb_errors) |
| 10360 | 10333 | return -1; |
| 10361 | 10334 | |
| 10335 | + if (0 == mem) |
| 10336 | + return offset + 15; |
| 10337 | + |
| 10362 | 10338 | /* relocate each section */ |
| 10363 | 10339 | for(i = 1; i < s1->nb_sections; i++) { |
| 10364 | 10340 | s = s1->sections[i]; |
| @@ -10366,12 +10342,20 @@ int tcc_relocate(TCCState *s1) · 1 unmodified line |
| 10366 | 10342 | relocate_section(s1, s); |
| 10367 | 10343 | } |
| 10368 | 10344 | |
| 10369 | | − /* mark executable sections as executable in memory */ |
| 10370 | 10345 | for(i = 1; i < s1->nb_sections; i++) { |
| 10371 | 10346 | s = s1->sections[i]; |
| 10372 | | − if ((s->sh_flags & (SHF_ALLOC | SHF_EXECINSTR)) == |
| 10373 | | − (SHF_ALLOC | SHF_EXECINSTR)) |
| 10374 | | − set_pages_executable(s->data, s->data_offset); |
| 10347 | + if (0 == (s->sh_flags & SHF_ALLOC)) |
| 10348 | + continue; |
| 10349 | + length = s->data_offset; |
| 10350 | + // printf("%-12s %08x %04x\n", s->name, s->sh_addr, length); |
| 10351 | + ptr = (void*)s->sh_addr; |
| 10352 | + if (NULL == s->data || s->sh_type == SHT_NOBITS) |
| 10353 | + memset(ptr, 0, length); |
| 10354 | + else if (ptr != s->data) |
| 10355 | + memcpy(ptr, s->data, length); |
| 10356 | + /* mark executable sections as executable in memory */ |
| 10357 | + if (s->sh_flags & SHF_EXECINSTR) |
| 10358 | + set_pages_executable(ptr, length); |
| 10375 | 10359 | } |
| 10376 | 10360 | return 0; |
| 10377 | 10361 | } |
| @@ -10380,9 +10364,14 @@ int tcc_relocate(TCCState *s1) · 2 unmodified lines |
| 10380 | 10364 | int tcc_run(TCCState *s1, int argc, char **argv) |
| 10381 | 10365 | { |
| 10382 | 10366 | int (*prog_main)(int, char **); |
| 10367 | + void *ptr; |
| 10368 | + int ret; |
| 10383 | 10369 | |
| 10384 | | − if (tcc_relocate(s1) < 0) |
| 10370 | + ret = tcc_relocate(s1, NULL); |
| 10371 | + if (ret < 0) |
| 10385 | 10372 | return -1; |
| 10373 | + ptr = tcc_malloc(ret); |
| 10374 | + tcc_relocate(s1, ptr); |
| 10386 | 10375 | |
| 10387 | 10376 | prog_main = tcc_get_symbol_err(s1, "main"); |
| 10388 | 10377 | |
| @@ -10417,7 +10406,9 @@ int tcc_run(TCCState *s1, int argc, char **argv) · 28 unmodified lines |
| 10417 | 10406 | bound_init(); |
| 10418 | 10407 | } |
| 10419 | 10408 | #endif |
| 10420 | | − return (*prog_main)(argc, argv); |
| 10409 | + ret = (*prog_main)(argc, argv); |
| 10410 | + tcc_free(ptr); |
| 10411 | + return ret; |
| 10421 | 10412 | } |
| 10422 | 10413 | |
| 10423 | 10414 | void tcc_memstats(void) |