aboutsummaryrefslogtreecommitdiff
path: root/tccelf.c
diff options
context:
space:
mode:
authorbellard <bellard>2004-10-23 22:53:42 +0000
committerbellard <bellard>2004-10-23 22:53:42 +0000
commit38e8a23025ea24bcff08edb02f1a468eafcf80a4 (patch)
tree47ce928764c2d34c6f00587a7443da14a389c213 /tccelf.c
parentbb07bf31aae1bcb4c3590f61210c46c0d3a37433 (diff)
downloadtinycc-38e8a23025ea24bcff08edb02f1a468eafcf80a4.tar.gz
tinycc-38e8a23025ea24bcff08edb02f1a468eafcf80a4.tar.bz2
fixed linker symbol generation - output format support
Diffstat (limited to 'tccelf.c')
-rw-r--r--tccelf.c231
1 files changed, 141 insertions, 90 deletions
diff --git a/tccelf.c b/tccelf.c
index 8a34442..c5dc023 100644
--- a/tccelf.c
+++ b/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)
{
char buf[1024];
- int i;
- Section *s;
if (!s1->nostdlib) {
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) {
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,
text_section->data_offset, 0,
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";
#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 */
/* XXX: suppress unneeded sections */
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;
if (file_type != TCC_OUTPUT_OBJ) {
- relocate_common_syms();
-
tcc_add_runtime(s1);
}
@@ -1095,6 +1123,9 @@ int tcc_output_file(TCCState *s1, const char *filename)
saved_dynamic_data_offset = 0; /* avoid warning */
if (file_type != TCC_OUTPUT_OBJ) {
+ relocate_common_syms();
+
+ tcc_add_linker_symbols(s1);
if (!s1->static_link) {
const char *name;
@@ -1310,7 +1341,11 @@ int tcc_output_file(TCCState *s1, const char *filename)
/* allocate program segment headers */
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) {
/* compute section to program header mapping */
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_memsz = addr - ph->p_vaddr;
ph++;
- /* if in the middle of a page, we duplicate the page in
- memory so that one copy is RX and the other is RW */
- if ((addr & (ELF_PAGE_SIZE - 1)) != 0)
- addr += ELF_PAGE_SIZE;
+ if (j == 0) {
+ if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
+ /* if in the middle of a page, we duplicate the page in
+ 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 */
@@ -1566,103 +1609,111 @@ int tcc_output_file(TCCState *s1, const char *filename)
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 */
if (file_type == TCC_OUTPUT_OBJ)
mode = 0666;
else
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) {
error_noabort("could not write '%s'", filename);
goto fail;
}
- f = fdopen(fd, "w");
- 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++;
+ f = fdopen(fd, "wb");
+
+#ifdef TCC_TARGET_COFF
+ if (s1->output_format == TCC_OUTPUT_FORMAT_COFF) {
+ tcc_output_coff(s1, f);
+ } else
+#endif
+ if (s1->output_format == TCC_OUTPUT_FORMAT_ELF) {
+ 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;
+
+ 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;
}
- size = s->sh_size;
- fwrite(s->data, 1, size, f);
- offset += size;
}
- }
- while (offset < ehdr.e_shoff) {
- fputc(0, f);
- offset++;
- }
+
+ /* output section headers */
+ while (offset < ehdr.e_shoff) {
+ fputc(0, f);
+ offset++;
+ }
- /* output section headers */
- 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;
+ 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);
}
- fwrite(sh, 1, sizeof(Elf32_Shdr), f);
+ } else {
+ tcc_output_binary(s1, f, section_order);
}
fclose(f);
ret = 0;
-#endif
the_end:
tcc_free(s1->symtab_to_dynsym);
tcc_free(section_order);