mirror of
https://github.com/mirror/tinycc.git
synced 2025-01-03 04:30:08 +08:00
fixed linker symbol generation - output format support
This commit is contained in:
parent
bb07bf31aa
commit
38e8a23025
235
tccelf.c
235
tccelf.c
@ -955,8 +955,6 @@ static void add_init_array_defines(TCCState *s1, const char *section_name)
|
|||||||
static void tcc_add_runtime(TCCState *s1)
|
static void tcc_add_runtime(TCCState *s1)
|
||||||
{
|
{
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
int i;
|
|
||||||
Section *s;
|
|
||||||
|
|
||||||
if (!s1->nostdlib) {
|
if (!s1->nostdlib) {
|
||||||
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a");
|
snprintf(buf, sizeof(buf), "%s/%s", tcc_lib_path, "libtcc1.a");
|
||||||
@ -1000,7 +998,17 @@ static void tcc_add_runtime(TCCState *s1)
|
|||||||
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
|
if (s1->output_type != TCC_OUTPUT_MEMORY && !s1->nostdlib) {
|
||||||
tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o");
|
tcc_add_file(s1, CONFIG_TCC_CRT_PREFIX "/crtn.o");
|
||||||
}
|
}
|
||||||
/* add various standard linker symbols */
|
}
|
||||||
|
|
||||||
|
/* add various standard linker symbols (must be done after the
|
||||||
|
sections are filled (for example after allocating common
|
||||||
|
symbols)) */
|
||||||
|
static void tcc_add_linker_symbols(TCCState *s1)
|
||||||
|
{
|
||||||
|
char buf[1024];
|
||||||
|
int i;
|
||||||
|
Section *s;
|
||||||
|
|
||||||
add_elf_sym(symtab_section,
|
add_elf_sym(symtab_section,
|
||||||
text_section->data_offset, 0,
|
text_section->data_offset, 0,
|
||||||
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
ELF32_ST_INFO(STB_GLOBAL, STT_NOTYPE),
|
||||||
@ -1059,6 +1067,28 @@ static char elf_interp[] = "/usr/libexec/ld-elf.so.1";
|
|||||||
static char elf_interp[] = "/lib/ld-linux.so.2";
|
static char elf_interp[] = "/lib/ld-linux.so.2";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static void tcc_output_binary(TCCState *s1, FILE *f,
|
||||||
|
const int *section_order)
|
||||||
|
{
|
||||||
|
Section *s;
|
||||||
|
int i, offset, size;
|
||||||
|
|
||||||
|
offset = 0;
|
||||||
|
for(i=1;i<s1->nb_sections;i++) {
|
||||||
|
s = s1->sections[section_order[i]];
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* output an ELF file */
|
/* output an ELF file */
|
||||||
/* XXX: suppress unneeded sections */
|
/* XXX: suppress unneeded sections */
|
||||||
int tcc_output_file(TCCState *s1, const char *filename)
|
int tcc_output_file(TCCState *s1, const char *filename)
|
||||||
@ -1082,8 +1112,6 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
|||||||
s1->nb_errors = 0;
|
s1->nb_errors = 0;
|
||||||
|
|
||||||
if (file_type != TCC_OUTPUT_OBJ) {
|
if (file_type != TCC_OUTPUT_OBJ) {
|
||||||
relocate_common_syms();
|
|
||||||
|
|
||||||
tcc_add_runtime(s1);
|
tcc_add_runtime(s1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1095,6 +1123,9 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
|||||||
saved_dynamic_data_offset = 0; /* avoid warning */
|
saved_dynamic_data_offset = 0; /* avoid warning */
|
||||||
|
|
||||||
if (file_type != TCC_OUTPUT_OBJ) {
|
if (file_type != TCC_OUTPUT_OBJ) {
|
||||||
|
relocate_common_syms();
|
||||||
|
|
||||||
|
tcc_add_linker_symbols(s1);
|
||||||
|
|
||||||
if (!s1->static_link) {
|
if (!s1->static_link) {
|
||||||
const char *name;
|
const char *name;
|
||||||
@ -1310,7 +1341,11 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
|||||||
/* allocate program segment headers */
|
/* allocate program segment headers */
|
||||||
phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr));
|
phdr = tcc_mallocz(phnum * sizeof(Elf32_Phdr));
|
||||||
|
|
||||||
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
|
||||||
|
file_offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
||||||
|
} else {
|
||||||
|
file_offset = 0;
|
||||||
|
}
|
||||||
if (phnum > 0) {
|
if (phnum > 0) {
|
||||||
/* compute section to program header mapping */
|
/* compute section to program header mapping */
|
||||||
if (s1->has_text_addr) {
|
if (s1->has_text_addr) {
|
||||||
@ -1413,10 +1448,18 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
|||||||
ph->p_filesz = file_offset - ph->p_offset;
|
ph->p_filesz = file_offset - ph->p_offset;
|
||||||
ph->p_memsz = addr - ph->p_vaddr;
|
ph->p_memsz = addr - ph->p_vaddr;
|
||||||
ph++;
|
ph++;
|
||||||
/* if in the middle of a page, we duplicate the page in
|
if (j == 0) {
|
||||||
memory so that one copy is RX and the other is RW */
|
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
|
||||||
if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
|
/* if in the middle of a page, we duplicate the page in
|
||||||
addr += ELF_PAGE_SIZE;
|
memory so that one copy is RX and the other is RW */
|
||||||
|
if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
|
||||||
|
addr += ELF_PAGE_SIZE;
|
||||||
|
} else {
|
||||||
|
addr = (addr + ELF_PAGE_SIZE - 1) & ~(ELF_PAGE_SIZE - 1);
|
||||||
|
file_offset = (file_offset + ELF_PAGE_SIZE - 1) &
|
||||||
|
~(ELF_PAGE_SIZE - 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* if interpreter, then add corresponing program header */
|
/* if interpreter, then add corresponing program header */
|
||||||
@ -1566,103 +1609,111 @@ int tcc_output_file(TCCState *s1, const char *filename)
|
|||||||
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
|
ehdr.e_entry = text_section->sh_addr; /* XXX: is it correct ? */
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef TCC_TARGET_COFF
|
|
||||||
ret = tcc_output_coff(s1, filename);
|
|
||||||
#else
|
|
||||||
sort_syms(s1, symtab_section);
|
|
||||||
|
|
||||||
/* 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] = ELFCLASS32;
|
|
||||||
ehdr.e_ident[5] = ELFDATA2LSB;
|
|
||||||
ehdr.e_ident[6] = EV_CURRENT;
|
|
||||||
#ifdef __FreeBSD__
|
|
||||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
|
||||||
#endif
|
|
||||||
#ifdef TCC_TARGET_ARM
|
|
||||||
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
|
|
||||||
#endif
|
|
||||||
switch(file_type) {
|
|
||||||
default:
|
|
||||||
case TCC_OUTPUT_EXE:
|
|
||||||
ehdr.e_type = ET_EXEC;
|
|
||||||
break;
|
|
||||||
case TCC_OUTPUT_DLL:
|
|
||||||
ehdr.e_type = ET_DYN;
|
|
||||||
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(Elf32_Ehdr);
|
|
||||||
ehdr.e_shentsize = sizeof(Elf32_Shdr);
|
|
||||||
ehdr.e_shnum = shnum;
|
|
||||||
ehdr.e_shstrndx = shnum - 1;
|
|
||||||
|
|
||||||
/* write elf file */
|
/* write elf file */
|
||||||
if (file_type == TCC_OUTPUT_OBJ)
|
if (file_type == TCC_OUTPUT_OBJ)
|
||||||
mode = 0666;
|
mode = 0666;
|
||||||
else
|
else
|
||||||
mode = 0777;
|
mode = 0777;
|
||||||
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, mode);
|
fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
|
||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
error_noabort("could not write '%s'", filename);
|
error_noabort("could not write '%s'", filename);
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
}
|
||||||
f = fdopen(fd, "w");
|
f = fdopen(fd, "wb");
|
||||||
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
|
|
||||||
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
|
|
||||||
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
|
||||||
for(i=1;i<s1->nb_sections;i++) {
|
|
||||||
s = s1->sections[section_order[i]];
|
|
||||||
if (s->sh_type != SHT_NOBITS) {
|
|
||||||
while (offset < s->sh_offset) {
|
|
||||||
fputc(0, f);
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
size = s->sh_size;
|
|
||||||
fwrite(s->data, 1, size, f);
|
|
||||||
offset += size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
while (offset < ehdr.e_shoff) {
|
|
||||||
fputc(0, f);
|
|
||||||
offset++;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* output section headers */
|
#ifdef TCC_TARGET_COFF
|
||||||
for(i=0;i<s1->nb_sections;i++) {
|
if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) {
|
||||||
sh = &shdr;
|
tcc_output_coff(s1, f);
|
||||||
memset(sh, 0, sizeof(Elf32_Shdr));
|
} else
|
||||||
s = s1->sections[i];
|
#endif
|
||||||
if (s) {
|
if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
|
||||||
sh->sh_name = s->sh_name;
|
sort_syms(s1, symtab_section);
|
||||||
sh->sh_type = s->sh_type;
|
|
||||||
sh->sh_flags = s->sh_flags;
|
/* align to 4 */
|
||||||
sh->sh_entsize = s->sh_entsize;
|
file_offset = (file_offset + 3) & -4;
|
||||||
sh->sh_info = s->sh_info;
|
|
||||||
if (s->link)
|
/* fill header */
|
||||||
sh->sh_link = s->link->sh_num;
|
ehdr.e_ident[0] = ELFMAG0;
|
||||||
sh->sh_addralign = s->sh_addralign;
|
ehdr.e_ident[1] = ELFMAG1;
|
||||||
sh->sh_addr = s->sh_addr;
|
ehdr.e_ident[2] = ELFMAG2;
|
||||||
sh->sh_offset = s->sh_offset;
|
ehdr.e_ident[3] = ELFMAG3;
|
||||||
sh->sh_size = s->sh_size;
|
ehdr.e_ident[4] = ELFCLASS32;
|
||||||
|
ehdr.e_ident[5] = ELFDATA2LSB;
|
||||||
|
ehdr.e_ident[6] = EV_CURRENT;
|
||||||
|
#ifdef __FreeBSD__
|
||||||
|
ehdr.e_ident[EI_OSABI] = ELFOSABI_FREEBSD;
|
||||||
|
#endif
|
||||||
|
#ifdef TCC_TARGET_ARM
|
||||||
|
ehdr.e_ident[EI_OSABI] = ELFOSABI_ARM;
|
||||||
|
#endif
|
||||||
|
switch(file_type) {
|
||||||
|
default:
|
||||||
|
case TCC_OUTPUT_EXE:
|
||||||
|
ehdr.e_type = ET_EXEC;
|
||||||
|
break;
|
||||||
|
case TCC_OUTPUT_DLL:
|
||||||
|
ehdr.e_type = ET_DYN;
|
||||||
|
break;
|
||||||
|
case TCC_OUTPUT_OBJ:
|
||||||
|
ehdr.e_type = ET_REL;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
fwrite(sh, 1, sizeof(Elf32_Shdr), f);
|
ehdr.e_machine = EM_TCC_TARGET;
|
||||||
|
ehdr.e_version = EV_CURRENT;
|
||||||
|
ehdr.e_shoff = file_offset;
|
||||||
|
ehdr.e_ehsize = sizeof(Elf32_Ehdr);
|
||||||
|
ehdr.e_shentsize = sizeof(Elf32_Shdr);
|
||||||
|
ehdr.e_shnum = shnum;
|
||||||
|
ehdr.e_shstrndx = shnum - 1;
|
||||||
|
|
||||||
|
fwrite(&ehdr, 1, sizeof(Elf32_Ehdr), f);
|
||||||
|
fwrite(phdr, 1, phnum * sizeof(Elf32_Phdr), f);
|
||||||
|
offset = sizeof(Elf32_Ehdr) + phnum * sizeof(Elf32_Phdr);
|
||||||
|
|
||||||
|
for(i=1;i<s1->nb_sections;i++) {
|
||||||
|
s = s1->sections[section_order[i]];
|
||||||
|
if (s->sh_type != SHT_NOBITS) {
|
||||||
|
while (offset < s->sh_offset) {
|
||||||
|
fputc(0, f);
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
size = s->sh_size;
|
||||||
|
fwrite(s->data, 1, size, f);
|
||||||
|
offset += size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* output section headers */
|
||||||
|
while (offset < ehdr.e_shoff) {
|
||||||
|
fputc(0, f);
|
||||||
|
offset++;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0;i<s1->nb_sections;i++) {
|
||||||
|
sh = &shdr;
|
||||||
|
memset(sh, 0, sizeof(Elf32_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(Elf32_Shdr), f);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
tcc_output_binary(s1, f, section_order);
|
||||||
}
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
ret = 0;
|
ret = 0;
|
||||||
#endif
|
|
||||||
the_end:
|
the_end:
|
||||||
tcc_free(s1->symtab_to_dynsym);
|
tcc_free(s1->symtab_to_dynsym);
|
||||||
tcc_free(section_order);
|
tcc_free(section_order);
|
||||||
|
Loading…
Reference in New Issue
Block a user