Create 64-bit ELF exeuctables
authorRobert Pengelly <robertapengelly@hotmail.com>
Tue, 4 Nov 2025 11:44:26 +0000 (11:44 +0000)
committerRobert Pengelly <robertapengelly@hotmail.com>
Tue, 4 Nov 2025 11:44:26 +0000 (11:44 +0000)
elf.c
elf.h
ld.c
lib.c

diff --git a/elf.c b/elf.c
index b315c2a5137addfc2e4c880ec5fa0457a14e33e3..c050e4c9381594c658ef383c7899e47f720917c3 100644 (file)
--- a/elf.c
+++ b/elf.c
@@ -84,6 +84,96 @@ static void translate_relocation (const char *filename, struct reloc_entry *relo
 
 }
 
+#define     ELF64_R_SYM(i)              ((i) >> 32)
+#define     ELF64_R_TYPE(i)             ((i) & 0xffffffff)
+
+static void translate_relocation64_addend (const char *filename, struct reloc_entry *reloc, struct elf64_rela *input_reloc, struct section_part *part, int endianess) {
+
+    uint64_t r_info = array_to_integer (input_reloc->r_info, 8, endianess);
+    uint64_t r_offset = array_to_integer (input_reloc->r_offset, 8, endianess);
+    
+    uint32_t symbol_index = ELF64_R_SYM (r_info), rel_type = ELF64_R_TYPE (r_info);
+    
+    if (symbol_index >= part->of->symbol_cnt) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: relocation has invalid symbol index", filename);
+        goto bad;
+    
+    }
+    
+    if (r_offset >= part->content_size) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: relocation has invalid r_offset", filename);
+        goto bad;
+    
+    }
+    
+    reloc->symbol = part->of->symbol_arr + symbol_index;
+    reloc->offset = r_offset;
+    reloc->addend = array_to_integer (input_reloc->r_addend, 8, endianess);
+    
+    if ((state->format & LD_TARGET_MACHINE_AMD64)) {
+    
+        switch (rel_type) {
+        
+            case R_AMD64_NONE:
+            
+                break;
+            
+            case R_AMD64_64:
+            
+                reloc->howto = &reloc_howtos[RELOC_TYPE_64];
+                break;
+            
+            case R_AMD64_PC32:
+            
+                reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+                break;
+            
+            case R_AMD64_PLT32:
+            
+                reloc->howto = &reloc_howtos[RELOC_TYPE_PC32];
+                break;
+            
+            case R_AMD64_RELATIVE:
+            
+                reloc->howto = &reloc_howtos[RELOC_TYPE_64];
+                break;
+            
+            case R_AMD64_32:
+            
+                reloc->howto = &reloc_howtos[RELOC_TYPE_32];
+                break;
+            
+            case R_AMD64_32S:
+            
+                reloc->howto = &reloc_howtos[RELOC_TYPE_32];
+                break;
+            
+            default:
+            
+                report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++relocation type 0x%02x not supported yet", rel_type);
+                exit (EXIT_FAILURE);
+        
+        }
+        
+        if (reloc->howto->pc_rel && !reloc->howto->special_function) {
+            reloc->addend += reloc->howto->size;
+        }
+    
+    } else {
+    bad:
+    
+        reloc->symbol = 0;
+        reloc->offset = 0;
+        reloc->addend = 0;
+        
+        reloc->howto = &reloc_howtos[RELOC_TYPE_IGNORED];
+    
+    }
+
+}
+
 #define     ELF32_ST_BIND(i)            ((i) >> 4)
 # define        STB_LOCAL               0
 # define        STB_GLOBAL              1
@@ -103,39 +193,519 @@ static uint64_t translate_sh_flags_to_section_flags (uint64_t sh_flags) {
         flags |= SECTION_FLAG_ALLOC;
     }
     
-    if (sh_flags & SHF_EXEC_INSTR) {
-        flags |= SECTION_FLAG_CODE;
+    if (sh_flags & SHF_EXEC_INSTR) {
+        flags |= SECTION_FLAG_CODE;
+    }
+    
+    return flags;
+
+}
+
+#define     CHECK_READ(memory_position, size_to_read)                           \
+    do                                                                          \
+        if (((memory_position) - data + (size_to_read) > data_size) ||          \
+             (memory_position) < data) {                                        \
+            report_at (program_name, 0, REPORT_FATAL_ERROR,                     \
+                "%s: corrupt input file", filename);                            \
+            exit (EXIT_FAILURE);                                                \
+        }                                                                       \
+    while (0)
+
+void read_elf32_object (const char *filename, unsigned char *data, unsigned long data_size, int endianess) {
+
+    unsigned char *pos = (unsigned char *) data;
+    
+    uint32_t e_shoff, sh_type, sh_link, sh_offset, sh_size, sh_entsize, sh_info;
+    uint16_t e_shentsize, e_shstrndx, e_shnum;
+    
+    struct elf32_exec *header;
+    struct elf32_shdr *shdr, *strtab_hdr;
+    
+    struct elf32_sym *elf_symbol;
+    struct symbol *symbol, *old_symbol;
+    
+    char *section_name_string_table = 0, *sym_strtab, *section_name, *p;
+    uint32_t section_name_string_table_size = 0, sym_strtab_size, st_name, i, j;
+    
+    struct section_part **part_p_array, *bss_part;
+    struct object_file *of = 0;
+    
+    struct section_part *part;
+    struct section *section;
+    struct subsection *subsection;
+    
+    struct section *bss_section = 0;
+    uint64_t bss_section_number = 0;
+    
+    struct elf32_rela *rela;
+    struct elf32_rel rel;
+    
+    CHECK_READ (pos, sizeof (*header));
+    
+    header = (struct elf32_exec *) pos;
+    pos += sizeof (*header);
+    
+    if (header->e_ident[EI_VERSION] != EV_CURRENT) {
+        
+        report_at (program_name, 0, REPORT_ERROR, "%s: unsupported ELF version", filename);
+        return;
+    
+    }
+    
+    if (array_to_integer (header->e_type, 2, endianess) != ET_REL) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: e_type is no ET_REL", filename);
+        return;
+    
+    }
+    
+    if (array_to_integer (header->e_version, 4, endianess) != EV_CURRENT) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: unsupported ELF version", filename);
+        return;
+    
+    }
+    
+    if (array_to_integer (header->e_ehsize, 2, endianess) < sizeof (*header)) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: e_ehsize is too small", filename);
+        return;
+    
+    }
+    
+    e_shnum = array_to_integer (header->e_shnum, 2, endianess);
+    e_shoff = array_to_integer (header->e_shoff, 4, endianess);
+    
+    e_shentsize = array_to_integer (header->e_shentsize, 2, endianess);
+    
+    if (e_shoff == 0 || e_shentsize == 0 || e_shnum == 0) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: missing section header table", filename);
+        return;
+    
+    }
+    
+    if (e_shentsize < sizeof (*shdr)) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: e_shentsize is too small", filename);
+        return;
+    
+    }
+    
+    e_shstrndx = array_to_integer (header->e_shstrndx, 2, endianess);
+    
+    if (e_shstrndx == 0 || e_shstrndx >= e_shnum) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: missing section header table", filename);
+        return;
+    
+    }
+    
+    pos = data + e_shoff;
+    
+    CHECK_READ (pos, (unsigned long) (e_shentsize * e_shnum));
+    pos += e_shentsize * e_shstrndx;
+    
+    shdr = (struct elf32_shdr *) pos;
+    
+    if (array_to_integer (shdr->sh_type, 4, endianess) != SHT_STRTAB) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "%s: section name string table does no have SHT_STRTAB type", filename);
+        return;
+    
+    }
+    
+    section_name_string_table_size = array_to_integer (shdr->sh_size, 4, endianess);
+    
+    pos = data + array_to_integer (shdr->sh_offset, 4, endianess);
+    CHECK_READ (pos, (unsigned long) section_name_string_table_size);
+    
+    section_name_string_table = (char *) pos;
+    part_p_array = xmalloc (sizeof (*part_p_array) * (e_shnum + 1));
+    
+    for (i = 1; i < e_shnum; i++) {
+    
+        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        
+        if (array_to_integer (shdr->sh_type, 4, endianess) != SHT_SYMTAB) {
+            continue;
+        }
+        
+        if (of) {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: more than 1 symbol table per object file", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        of = object_file_make (filename, array_to_integer (shdr->sh_size, 4, endianess) / array_to_integer (shdr->sh_entsize, 4, endianess));
+    
+    }
+    
+    for (i = 1; i < e_shnum; i++) {
+    
+        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        
+        if (array_to_integer (shdr->sh_name, 4, endianess) < section_name_string_table_size) {
+            section_name = xstrdup (section_name_string_table + array_to_integer (shdr->sh_name, 4, endianess));
+        } else {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid offset into string table", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        sh_type = array_to_integer (shdr->sh_type, 4, endianess);
+        
+        if (sh_type != SHT_PROGBITS && sh_type != SHT_NOBITS) {
+        
+            part_p_array[i] = 0;
+            
+            free (section_name);
+            continue;
+        
+        }
+        
+        if ((p = strrchr (section_name, '.'))) {
+        
+            if (p != section_name) {
+                *p++ = '\0';
+            }
+        
+        }
+        
+        section = section_find_or_make (section_name);
+        
+        if (array_to_integer (shdr->sh_addralign, 4, endianess) > section->section_alignment) {
+            section->section_alignment = array_to_integer (shdr->sh_addralign, 4, endianess);
+        }
+        
+        section->flags = translate_sh_flags_to_section_flags (array_to_integer (shdr->sh_flags, 4, endianess));
+        
+        if (sh_type == SHT_NOBITS) {
+            section->is_bss = 1;
+        } else {
+            section->flags |= SECTION_FLAG_LOAD;
+        }
+        
+        if (p) {
+            subsection = subsection_find_or_make (section, p);
+        } else {
+            subsection = 0;
+        }
+        
+        free (section_name);
+        
+        part = section_part_new (section, of);
+        part->alignment = array_to_integer (shdr->sh_addralign, 4, endianess);
+        
+        part->content_size = array_to_integer (shdr->sh_size, 4, endianess);
+        
+        if (sh_type != SHT_NOBITS) {
+        
+            pos = data + array_to_integer (shdr->sh_offset, 4, endianess);
+            
+            part->content = xmalloc (part->content_size);
+            CHECK_READ (pos, part->content_size);
+            
+            memcpy (part->content, pos, part->content_size);
+        
+        }
+        
+        if (section->is_bss) {
+        
+            bss_section_number = i;
+            bss_section = section;
+        
+        }
+        
+        if (subsection) {
+            subsection_append_section_part (subsection, part);
+        } else {
+            section_append_section_part (section, part);
+        }
+        
+        part_p_array[i] = part;
+    
+    }
+    
+    for (i = 1; i < e_shnum; i++) {
+    
+        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        
+        if (array_to_integer (shdr->sh_type, 4, endianess) != SHT_SYMTAB) {
+            continue;
+        }
+        
+        sh_link = array_to_integer (shdr->sh_link, 4, endianess);
+        
+        if (sh_link == 0 || sh_link >=  e_shnum) {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: symtab has invalid sh_link", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        strtab_hdr = (struct elf32_shdr *) (pos = data + e_shoff + sh_link * e_shentsize);
+        
+        sym_strtab_size = array_to_integer (strtab_hdr->sh_size, 4, endianess);
+        
+        pos = data + array_to_integer (strtab_hdr->sh_offset, 4, endianess);
+        CHECK_READ (pos, (unsigned long) sym_strtab_size);
+        
+        sym_strtab = (char *) pos;
+        
+        sh_entsize = array_to_integer (shdr->sh_entsize, 4, endianess);
+        sh_offset = array_to_integer (shdr->sh_offset, 4, endianess);
+        sh_size = array_to_integer (shdr->sh_size, 4, endianess);
+        
+        pos = data + sh_offset;
+        CHECK_READ (pos, (unsigned long) sh_size);
+        
+        if (sh_entsize < sizeof (*elf_symbol)) {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: symbol table sh_entsize is too small", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        for (j = 1; j < sh_size / sh_entsize; j++) {
+        
+            elf_symbol = (struct elf32_sym *) (data + sh_offset + j * sh_entsize);
+            symbol = of->symbol_arr + j;
+            
+            if ((st_name = array_to_integer (elf_symbol->st_name, 4, endianess)) < sym_strtab_size) {
+            
+                if (sym_strtab[st_name] == '\0') {
+                    symbol->name = xstrdup (UNNAMED_SYMBOL_NAME);
+                } else {
+                    symbol->name = xstrdup (sym_strtab + st_name);
+                }
+            
+            } else {
+            
+                report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: invalid offset into string table", filename);
+                exit (EXIT_FAILURE);
+            
+            }
+            
+            symbol->value = array_to_integer (elf_symbol->st_value, 4, endianess);
+            symbol->size = array_to_integer (elf_symbol->st_size, 4, endianess);
+            
+            symbol->section_number = array_to_integer (elf_symbol->st_shndx, 2, endianess);
+            
+            if (symbol->section_number == SHN_UNDEF) {
+            
+                symbol->section_number = UNDEFINED_SECTION_NUMBER;
+                symbol->part = 0;
+            
+            } else if (symbol->section_number == SHN_ABS) {
+            
+                symbol->section_number = ABSOLUTE_SECTION_NUMBER;
+                symbol->part = 0;
+            
+            } else if (symbol->section_number == SHN_COMMON) {
+            
+                if (symbol->size) {
+                
+                    old_symbol = symbol_find (symbol->name);
+                    
+                    if (ELF32_ST_BIND (elf_symbol->st_info[0]) != STB_GLOBAL) {
+                    
+                        report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: non-global common symbol", filename);
+                        exit (EXIT_FAILURE);
+                    
+                    }
+                    
+                    if (!old_symbol || symbol_is_undefined (old_symbol)) {
+                    
+                        if (!bss_section) {
+                        
+                            bss_section = section_find_or_make (".bss");
+                            
+                            if (bss_section->section_alignment < 4) {
+                                bss_section->section_alignment = 4;
+                            }
+                            
+                            bss_section->flags = translate_sh_flags_to_section_flags (SHF_WRITE | SHF_ALLOC);
+                            bss_section->is_bss = 1;
+                            
+                            bss_section_number = e_shnum ? e_shnum : 1;
+                        
+                        }
+                        
+                        bss_part = section_part_new (bss_section, of);
+                        section_append_section_part (bss_section, bss_part);
+                        
+                        
+                        bss_part->content_size = symbol->size;
+                        bss_part->alignment = symbol->value;
+                        
+                        symbol->part = bss_part;
+                        symbol->value = 0;
+                        
+                        symbol->section_number = bss_section_number;
+                    
+                    } else {
+                    
+                        if (symbol->size > old_symbol->size) {
+                            old_symbol->part->content_size = old_symbol->size = symbol->size;
+                        }
+                        
+                        if (symbol->value > old_symbol->part->alignment) {
+                            old_symbol->part->alignment = symbol->value;
+                        }
+                        
+                        symbol->part = 0;
+                        symbol->value = 0;
+                        
+                        symbol->section_number = UNDEFINED_SECTION_NUMBER;
+                    
+                    }
+                
+                } else {
+                
+                    symbol->section_number = UNDEFINED_SECTION_NUMBER;
+                    symbol->part = 0;
+                
+                }
+            
+            } else if (symbol->section_number >= SHN_LORESERVE && symbol->section_number <= SHN_HIRESERVE) {
+            
+                report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++not yet supported symbol st_shndx: %hu", symbol->section_number);
+                exit (EXIT_FAILURE);
+            
+            } else if (symbol->section_number >= e_shnum) {
+            
+                report_at (program_name, 0, REPORT_ERROR, "%s: invalid symbol st_shndx: %hu", filename, symbol->section_number);
+                symbol->part = 0;
+            
+            } else {
+                symbol->part = part_p_array[symbol->section_number];
+            }
+            
+            switch (ELF32_ST_BIND (elf_symbol->st_info[0])) {
+            
+                case STB_LOCAL:
+                
+                    break;
+                
+                case STB_GLOBAL:
+                
+                    symbol_record_external_symbol (symbol);
+                    break;
+                
+                default:
+                
+                    report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++not yet supported symbol ELF32_ST_BIND: %u", ELF32_ST_BIND (elf_symbol->st_info[0]));
+                    exit (EXIT_FAILURE);
+            
+            }
+            
+            if (ELF32_ST_TYPE (elf_symbol->st_info[0]) == STT_SECTION) {
+                symbol->flags |= SYMBOL_FLAG_SECTION_SYMBOL;
+            }
+        
+        }
+    
+    }
+    
+    for (i = 0; i < e_shnum; i++) {
+    
+        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        
+        sh_type = array_to_integer (shdr->sh_type, 4, endianess);
+        sh_size = array_to_integer (shdr->sh_size, 4, endianess);
+        
+        if ((sh_type != SHT_RELA && sh_type != SHT_REL) || sh_size == 0) {
+            continue;
+        }
+        
+        if ((sh_info = array_to_integer (shdr->sh_info, 4, endianess)) >= e_shnum) {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: relocation section has invalid sh_info", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        if (!(part = part_p_array[sh_info])) {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: relocation section has invalid sh_info", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        if (part->section->is_bss) {
+        
+            report_at (program_name, 0, REPORT_FATAL_ERROR, "%s: relocation section sh_info points to BSS section", filename);
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        sh_entsize = array_to_integer (shdr->sh_entsize, 4, endianess);
+        sh_offset = array_to_integer (shdr->sh_offset, 4, endianess);
+        
+        if ((sh_type == SHT_RELA && sh_entsize != sizeof (*rela)) || (sh_type == SHT_REL && sh_entsize != sizeof (rel))) {
+        
+            report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++relocation shdr.sh_entsize not yet supported");
+            exit (EXIT_FAILURE);
+        
+        }
+        
+        sh_size = array_to_integer (shdr->sh_size, 4, endianess);
+        
+        pos = data + sh_offset;
+        CHECK_READ (pos, (unsigned long) sh_size);
+        
+        part->reloc_cnt = sh_size / sh_entsize;
+        part->reloc_arr = xmalloc (part->reloc_cnt * sizeof (*part->reloc_arr));
+        
+        if (sh_type == SHT_RELA) {
+        
+            for (j = 0; j < part->reloc_cnt; j++) {
+            
+                rela = (struct elf32_rela *) (pos + sh_entsize * j);
+                
+                integer_to_array (array_to_integer (rela->r_offset, 4, endianess), rel.r_offset, 4, endianess);
+                integer_to_array (array_to_integer (rela->r_info, 4, endianess), rel.r_info, 4, endianess);
+                
+                part->reloc_arr[j].addend = array_to_integer (rela->r_addend, 4, endianess);
+                translate_relocation (filename, part->reloc_arr + j, &rel, part, endianess);
+            
+            }
+        
+        } else {
+        
+            for (j = 0; j < part->reloc_cnt; j++) {
+            
+                memcpy (&rel, pos + sh_entsize * j, sizeof (rel));
+                translate_relocation (filename, part->reloc_arr + j, &rel, part, endianess);
+            
+            }
+        
+        }
+    
     }
     
-    return flags;
+    free (part_p_array);
 
 }
 
-#define     CHECK_READ(memory_position, size_to_read)                           \
-    do                                                                          \
-        if (((memory_position) - data + (size_to_read) > data_size) ||          \
-             (memory_position) < data) {                                        \
-            report_at (program_name, 0, REPORT_FATAL_ERROR,                     \
-                "%s: corrupt input file", filename);                            \
-            exit (EXIT_FAILURE);                                                \
-        }                                                                       \
-    while (0)
-
-void read_elf32_object (const char *filename, unsigned char *data, unsigned long data_size, int endianess) {
+void read_elf64_object (const char *filename, unsigned char *data, unsigned long data_size, int endianess) {
 
     unsigned char *pos = (unsigned char *) data;
     
+    uint64_t e_shoff, sh_type, sh_link, sh_offset, sh_size, sh_entsize, sh_info;
     uint16_t e_shentsize, e_shstrndx, e_shnum;
-    uint32_t e_shoff, sh_type, sh_link, sh_offset, sh_size, sh_entsize, sh_info;
     
-    struct elf32_exec *header;
-    struct elf32_shdr *shdr, *strtab_hdr;
+    struct elf64_exec *header;
+    struct elf64_shdr *shdr, *strtab_hdr;
     
-    struct elf32_sym *elf_symbol;
+    struct elf64_sym *elf_symbol;
     struct symbol *symbol, *old_symbol;
     
     char *section_name_string_table = 0, *sym_strtab, *section_name, *p;
-    uint32_t section_name_string_table_size = 0, sym_strtab_size, st_name, i, j;
+    uint64_t section_name_string_table_size = 0, sym_strtab_size, st_name, i, j;
     
     struct section_part **part_p_array, *bss_part;
     struct object_file *of = 0;
@@ -147,12 +717,10 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     struct section *bss_section = 0;
     uint64_t bss_section_number = 0;
     
-    struct elf32_rela *rela;
-    struct elf32_rel rel;
-    
+    struct elf64_rela *rela;
     CHECK_READ (pos, sizeof (*header));
     
-    header = (struct elf32_exec *) pos;
+    header = (struct elf64_exec *) pos;
     pos += sizeof (*header);
     
     if (header->e_ident[EI_VERSION] != EV_CURRENT) {
@@ -184,7 +752,7 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     }
     
     e_shnum = array_to_integer (header->e_shnum, 2, endianess);
-    e_shoff = array_to_integer (header->e_shoff, 4, endianess);
+    e_shoff = array_to_integer (header->e_shoff, 8, endianess);
     
     e_shentsize = array_to_integer (header->e_shentsize, 2, endianess);
     
@@ -216,7 +784,7 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     CHECK_READ (pos, (unsigned long) (e_shentsize * e_shnum));
     pos += e_shentsize * e_shstrndx;
     
-    shdr = (struct elf32_shdr *) pos;
+    shdr = (struct elf64_shdr *) pos;
     
     if (array_to_integer (shdr->sh_type, 4, endianess) != SHT_STRTAB) {
     
@@ -225,9 +793,9 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     
     }
     
-    section_name_string_table_size = array_to_integer (shdr->sh_size, 4, endianess);
+    section_name_string_table_size = array_to_integer (shdr->sh_size, 8, endianess);
     
-    pos = data + array_to_integer (shdr->sh_offset, 4, endianess);
+    pos = data + array_to_integer (shdr->sh_offset, 8, endianess);
     CHECK_READ (pos, (unsigned long) section_name_string_table_size);
     
     section_name_string_table = (char *) pos;
@@ -235,7 +803,7 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     
     for (i = 1; i < e_shnum; i++) {
     
-        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        shdr = (struct elf64_shdr *) (pos = data + e_shoff + i * e_shentsize);
         
         if (array_to_integer (shdr->sh_type, 4, endianess) != SHT_SYMTAB) {
             continue;
@@ -254,7 +822,7 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     
     for (i = 1; i < e_shnum; i++) {
     
-        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        shdr = (struct elf64_shdr *) (pos = data + e_shoff + i * e_shentsize);
         
         if (array_to_integer (shdr->sh_name, 4, endianess) < section_name_string_table_size) {
             section_name = xstrdup (section_name_string_table + array_to_integer (shdr->sh_name, 4, endianess));
@@ -286,11 +854,11 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
         
         section = section_find_or_make (section_name);
         
-        if (array_to_integer (shdr->sh_addralign, 4, endianess) > section->section_alignment) {
-            section->section_alignment = array_to_integer (shdr->sh_addralign, 4, endianess);
+        if (array_to_integer (shdr->sh_addralign, 8, endianess) > section->section_alignment) {
+            section->section_alignment = array_to_integer (shdr->sh_addralign, 8, endianess);
         }
         
-        section->flags = translate_sh_flags_to_section_flags (array_to_integer (shdr->sh_flags, 4, endianess));
+        section->flags = translate_sh_flags_to_section_flags (array_to_integer (shdr->sh_flags, 8, endianess));
         
         if (sh_type == SHT_NOBITS) {
             section->is_bss = 1;
@@ -307,13 +875,13 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
         free (section_name);
         
         part = section_part_new (section, of);
-        part->alignment = array_to_integer (shdr->sh_addralign, 4, endianess);
+        part->alignment = array_to_integer (shdr->sh_addralign, 8, endianess);
         
-        part->content_size = array_to_integer (shdr->sh_size, 4, endianess);
+        part->content_size = array_to_integer (shdr->sh_size, 8, endianess);
         
         if (sh_type != SHT_NOBITS) {
         
-            pos = data + array_to_integer (shdr->sh_offset, 4, endianess);
+            pos = data + array_to_integer (shdr->sh_offset, 8, endianess);
             
             part->content = xmalloc (part->content_size);
             CHECK_READ (pos, part->content_size);
@@ -341,7 +909,7 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     
     for (i = 1; i < e_shnum; i++) {
     
-        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        shdr = (struct elf64_shdr *) (pos = data + e_shoff + i * e_shentsize);
         
         if (array_to_integer (shdr->sh_type, 4, endianess) != SHT_SYMTAB) {
             continue;
@@ -356,18 +924,18 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
         
         }
         
-        strtab_hdr = (struct elf32_shdr *) (pos = data + e_shoff + sh_link * e_shentsize);
+        strtab_hdr = (struct elf64_shdr *) (pos = data + e_shoff + sh_link * e_shentsize);
         
-        sym_strtab_size = array_to_integer (strtab_hdr->sh_size, 4, endianess);
+        sym_strtab_size = array_to_integer (strtab_hdr->sh_size, 8, endianess);
         
-        pos = data + array_to_integer (strtab_hdr->sh_offset, 4, endianess);
+        pos = data + array_to_integer (strtab_hdr->sh_offset, 8, endianess);
         CHECK_READ (pos, (unsigned long) sym_strtab_size);
         
         sym_strtab = (char *) pos;
         
-        sh_entsize = array_to_integer (shdr->sh_entsize, 4, endianess);
-        sh_offset = array_to_integer (shdr->sh_offset, 4, endianess);
-        sh_size = array_to_integer (shdr->sh_size, 4, endianess);
+        sh_entsize = array_to_integer (shdr->sh_entsize, 8, endianess);
+        sh_offset = array_to_integer (shdr->sh_offset, 8, endianess);
+        sh_size = array_to_integer (shdr->sh_size, 8, endianess);
         
         pos = data + sh_offset;
         CHECK_READ (pos, (unsigned long) sh_size);
@@ -381,7 +949,7 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
         
         for (j = 1; j < sh_size / sh_entsize; j++) {
         
-            elf_symbol = (struct elf32_sym *) (data + sh_offset + j * sh_entsize);
+            elf_symbol = (struct elf64_sym *) (data + sh_offset + j * sh_entsize);
             symbol = of->symbol_arr + j;
             
             if ((st_name = array_to_integer (elf_symbol->st_name, 4, endianess)) < sym_strtab_size) {
@@ -399,8 +967,8 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
             
             }
             
-            symbol->value = array_to_integer (elf_symbol->st_value, 4, endianess);
-            symbol->size = array_to_integer (elf_symbol->st_size, 4, endianess);
+            symbol->value = array_to_integer (elf_symbol->st_value, 8, endianess);
+            symbol->size = array_to_integer (elf_symbol->st_size, 8, endianess);
             
             symbol->section_number = array_to_integer (elf_symbol->st_shndx, 2, endianess);
             
@@ -522,10 +1090,10 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
     
     for (i = 0; i < e_shnum; i++) {
     
-        shdr = (struct elf32_shdr *) (pos = data + e_shoff + i * e_shentsize);
+        shdr = (struct elf64_shdr *) (pos = data + e_shoff + i * e_shentsize);
         
         sh_type = array_to_integer (shdr->sh_type, 4, endianess);
-        sh_size = array_to_integer (shdr->sh_size, 4, endianess);
+        sh_size = array_to_integer (shdr->sh_size, 8, endianess);
         
         if ((sh_type != SHT_RELA && sh_type != SHT_REL) || sh_size == 0) {
             continue;
@@ -552,17 +1120,17 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
         
         }
         
-        sh_entsize = array_to_integer (shdr->sh_entsize, 4, endianess);
-        sh_offset = array_to_integer (shdr->sh_offset, 4, endianess);
+        sh_entsize = array_to_integer (shdr->sh_entsize, 8, endianess);
+        sh_offset = array_to_integer (shdr->sh_offset, 8, endianess);
         
-        if ((sh_type == SHT_RELA && sh_entsize != sizeof (*rela)) || (sh_type == SHT_REL && sh_entsize != sizeof (rel))) {
+        if ((sh_type == SHT_RELA && sh_entsize != sizeof (*rela)) || (sh_type == SHT_REL && sh_entsize != sizeof (struct elf64_rel))) {
         
             report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++relocation shdr.sh_entsize not yet supported");
             exit (EXIT_FAILURE);
         
         }
         
-        sh_size = array_to_integer (shdr->sh_size, 4, endianess);
+        sh_size = array_to_integer (shdr->sh_size, 8, endianess);
         
         pos = data + sh_offset;
         CHECK_READ (pos, (unsigned long) sh_size);
@@ -574,24 +1142,15 @@ void read_elf32_object (const char *filename, unsigned char *data, unsigned long
         
             for (j = 0; j < part->reloc_cnt; j++) {
             
-                rela = (struct elf32_rela *) (pos + sh_entsize * j);
-                
-                integer_to_array (array_to_integer (rela->r_offset, 4, endianess), rel.r_offset, 4, endianess);
-                integer_to_array (array_to_integer (rela->r_info, 4, endianess), rel.r_info, 4, endianess);
-                
-                part->reloc_arr[j].addend = array_to_integer (rela->r_addend, 4, endianess);
-                translate_relocation (filename, part->reloc_arr + j, &rel, part, endianess);
+                rela = (struct elf64_rela *) (pos + sh_entsize * j);
+                translate_relocation64_addend (filename, part->reloc_arr + j, rela, part, endianess);
             
             }
         
         } else {
         
-            for (j = 0; j < part->reloc_cnt; j++) {
-            
-                memcpy (&rel, pos + sh_entsize * j, sizeof (rel));
-                translate_relocation (filename, part->reloc_arr + j, &rel, part, endianess);
-            
-            }
+            report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "+++ELF64 relocations without addend not yet supported");
+            exit (EXIT_FAILURE);
         
         }
     
@@ -622,7 +1181,7 @@ uint64_t elf_get_first_section_rva (void) {
     uint64_t size_of_headers = 0;
     
     if (state->format == LD_FORMAT_AMD64_ELF) {
-        /*size_of_headers = sizeof (struct elf64_exec);*/
+        size_of_headers = sizeof (struct elf64_exec);
     } else if (state->format == LD_FORMAT_I386_ELF) {
         size_of_headers = sizeof (struct elf32_exec);
     }
@@ -637,6 +1196,7 @@ uint64_t elf_get_first_section_rva (void) {
 
 #define     PT_LOAD                     1
 #define     EM_I386                     3
+#define     EM_AMD64                    62
 
 static uint32_t translate_section_flags_to_sh_flags (uint32_t flags) {
 
@@ -767,6 +1327,91 @@ static unsigned char *write_sections (unsigned char *data, struct elf32_exec *he
 
 }
 
+static unsigned char *write_sections64 (unsigned char *data, struct elf64_exec *header, uint64_t shstrtab_i) {
+
+    struct elf64_phdr phdr = { 0 };
+    struct elf64_shdr shdr = { 0 };
+    
+    struct section *section;
+    
+    unsigned char *pos, *phdr_pos, *shdr_pos;
+    uint32_t flags;
+    
+    phdr_pos = data + array_to_integer (header->e_phoff, 8, 0);
+    pos = data + sizeof (header);
+    
+    /*if (generate_section_headers) */{
+    
+        shdr_pos = data + array_to_integer (header->e_shoff, 8, 0);
+        
+        integer_to_array (SHT_NULL, shdr.sh_type, 4, 0);
+        integer_to_array (SHN_UNDEF, shdr.sh_link, 4, 0);
+        
+        memcpy (shdr_pos, &shdr, sizeof (shdr));
+        shdr_pos += sizeof (shdr);
+    
+    }
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        integer_to_array (PT_LOAD, phdr.p_type, 4, 0);
+        
+        integer_to_array (state->base_address + section->rva, phdr.p_paddr, 8, 0);
+        integer_to_array (state->base_address + section->rva, phdr.p_vaddr, 8, 0);
+        
+        integer_to_array (section->total_size, phdr.p_memsz, 8, 0);
+        
+        if (!section->is_bss) {
+        
+            integer_to_array (section->total_size, phdr.p_filesz, 8, 0);
+            
+            pos = data + ALIGN (pos - data, section->section_alignment);
+            integer_to_array (pos - data, phdr.p_offset, 8, 0);
+            
+            section_write (section, pos);
+            pos += section->total_size;
+        
+        } else {
+        
+            integer_to_array (0, phdr.p_filesz, 8, 0);
+            integer_to_array (0, phdr.p_offset, 8, 0);
+        
+        }
+        
+        flags = translate_section_flags_to_p_flags (section->flags);
+        integer_to_array (flags, phdr.p_flags, 4, 0);
+        
+        integer_to_array (section->section_alignment, phdr.p_align, 8, 0);
+        
+        /*if (generate_section_headers) */{
+        
+            integer_to_array (section->is_bss ? SHT_NOBITS : SHT_PROGBITS, shdr.sh_type, 4, 0);
+            
+            flags = translate_section_flags_to_sh_flags (section->flags);
+            integer_to_array (flags, shdr.sh_flags, 8, 0);
+            
+            integer_to_array (array_to_integer (phdr.p_vaddr,  8, 0), shdr.sh_addr, 8, 0);
+            integer_to_array (array_to_integer (phdr.p_offset, 8, 0), shdr.sh_offset, 8, 0);
+            integer_to_array (array_to_integer (phdr.p_memsz,  8, 0), shdr.sh_size, 8, 0);
+            integer_to_array (array_to_integer (phdr.p_align,  8, 0), shdr.sh_addralign, 8, 0);
+            
+            integer_to_array (shstrtab_i, shdr.sh_name, 4, 0);
+            shstrtab_i += strlen (section->name) + 1;
+            
+            memcpy (shdr_pos, &shdr, sizeof (shdr));
+            shdr_pos += sizeof (shdr);
+        
+        }
+        
+        memcpy (phdr_pos, &phdr, sizeof (phdr));
+        phdr_pos += sizeof (phdr);
+    
+    }
+    
+    return pos;
+
+}
+
 void elf32_write (const char *filename) {
 
     struct elf32_exec header = { 0 };
@@ -776,7 +1421,7 @@ void elf32_write (const char *filename) {
     unsigned char *data, *pos;
     
     struct section *section;
-    uint16_t e_phnum = 0, e_shnum = 0;
+    uint16_t e_phnum = 0, e_shnum = 1;
     
     uint64_t shstrtab_size, shstrtab_start_i = 0;
     
@@ -850,8 +1495,8 @@ void elf32_write (const char *filename) {
             section->target_index = e_shnum++;
         }
         
-        integer_to_array (e_shnum, header.e_shnum, 2, 0);
         integer_to_array (e_shnum++, header.e_shstrndx, 2, 0);
+        integer_to_array (e_shnum, header.e_shnum, 2, 0);
         
         data_size += (e_shnum * sizeof (struct elf32_shdr));
     
@@ -869,6 +1514,11 @@ void elf32_write (const char *filename) {
         unsigned char *shdr_pos = data + array_to_integer (header.e_shoff, 4, 0) + array_to_integer (header.e_shstrndx, 2, 0) * sizeof (struct elf32_shdr);
         unsigned char *saved_pos = pos;
         
+        integer_to_array (1, shstrshdr.sh_name, 4, 0);
+        integer_to_array (SHT_STRTAB, shstrshdr.sh_type, 4, 0);
+        integer_to_array (saved_pos - data, shstrshdr.sh_offset, 4, 0);
+        integer_to_array (1, shstrshdr.sh_addralign, 4, 0);
+        
         *pos++ = '\0';
         
         memcpy (pos, ".shstrtab", sizeof (".shstrtab"));
@@ -898,3 +1548,140 @@ void elf32_write (const char *filename) {
     fclose (fp);
 
 }
+
+void elf64_write (const char *filename) {
+
+    struct elf64_exec header = { 0 };
+    FILE *fp;
+    
+    unsigned long data_size = 0;
+    unsigned char *data, *pos;
+    
+    struct section *section;
+    uint16_t e_phnum = 0, e_shnum = 1;
+    
+    uint64_t shstrtab_size, shstrtab_start_i = 0;
+    
+    if (!(fp = fopen (filename, "wb"))) {
+    
+        report_at (program_name, 0, REPORT_ERROR, "failed to open '%s' for writing", filename);
+        return;
+    
+    }
+    
+    header.e_ident[0] = 0x7F;
+    header.e_ident[1] = 'E';
+    header.e_ident[2] = 'L';
+    header.e_ident[3] = 'F';
+    
+    header.e_ident[EI_CLASS] = ELF_CLASS64;
+    header.e_ident[EI_DATA] = ELF_DATA2LSB;
+    
+    header.e_ident[EI_VERSION] = EV_CURRENT;
+    
+    integer_to_array (ET_EXEC, header.e_type, 2, 0);
+    integer_to_array (EM_AMD64, header.e_machine, 2, 0);
+    integer_to_array (EV_CURRENT, header.e_version, 4, 0);
+    
+    integer_to_array (state->entry_point + state->base_address, header.e_entry, 8, 0);
+    integer_to_array (sizeof (header), header.e_ehsize, 2, 0);
+    
+    data_size += sizeof (header);
+    
+    for (section = all_sections; section; section = section->next) {
+    
+        if (!section->is_bss) {
+        
+            data_size = ALIGN (data_size, section->section_alignment);
+            data_size += section->total_size;
+        
+        }
+        
+        e_phnum++;
+    
+    }
+    
+    /*if (generate_section_headers) */{
+    
+        shstrtab_start_i = shstrtab_size = 1 + sizeof (".shstrtab");
+        
+        for (section = all_sections; section; section = section->next) {
+            shstrtab_size += strlen (section->name) + 1;
+        }
+        
+        data_size += shstrtab_size;
+    
+    }
+    
+    data_size = ALIGN (data_size, 8);
+    
+    integer_to_array (data_size, header.e_phoff, 8, 0);
+    integer_to_array (sizeof (struct elf64_phdr), header.e_phentsize, 2, 0);
+    integer_to_array (e_phnum, header.e_phnum, 2, 0);
+    
+    data_size += e_phnum * sizeof (struct elf64_phdr);
+    
+    /*if (generate_section_headers) */{
+    
+        data_size = ALIGN (data_size, 8);
+        
+        integer_to_array (data_size, header.e_shoff, 8, 0);
+        integer_to_array (sizeof (struct elf64_shdr), header.e_shentsize, 2, 0);
+        
+        for (section = all_sections; section; section = section->next) {
+            section->target_index = e_shnum++;
+        }
+        
+        integer_to_array (e_shnum++, header.e_shstrndx, 2, 0);
+        integer_to_array (e_shnum, header.e_shnum, 2, 0);
+        
+        data_size += (e_shnum * sizeof (struct elf64_shdr));
+    
+    }
+    
+    data = xmalloc (data_size);
+    memcpy (data, &header, sizeof (header));
+    
+    pos = write_sections64 (data, &header, shstrtab_start_i);
+    
+    /*if (generate_section_headers) */{
+    
+        struct elf64_shdr shstrshdr = { 0 };
+        
+        unsigned char *shdr_pos = data + array_to_integer (header.e_shoff, 8, 0) + array_to_integer (header.e_shstrndx, 2, 0) * sizeof (struct elf64_shdr);
+        unsigned char *saved_pos = pos;
+        
+        integer_to_array (1, shstrshdr.sh_name, 4, 0);
+        integer_to_array (SHT_STRTAB, shstrshdr.sh_type, 4, 0);
+        integer_to_array (saved_pos - data, shstrshdr.sh_offset, 8, 0);
+        integer_to_array (1, shstrshdr.sh_addralign, 8, 0);
+        
+        *pos++ = '\0';
+        
+        memcpy (pos, ".shstrtab", sizeof (".shstrtab"));
+        pos += sizeof (".shstrtab");
+        
+        for (section = all_sections; section; section = section->next) {
+        
+            uint64_t name_len = strlen (section->name);
+            
+            memcpy (pos, section->name, name_len);
+            pos[name_len] = '\0';
+            
+            pos += name_len + 1;
+        
+        }
+        
+        integer_to_array (pos - saved_pos, shstrshdr.sh_size, 8, 0);
+        memcpy (shdr_pos, &shstrshdr, sizeof (shstrshdr));
+    
+    }
+    
+    if (fwrite (data, data_size, 1, fp) != 1) {
+        report_at (program_name, 0, REPORT_ERROR, "failed to write data to '%s'", filename);
+    }
+    
+    free (data);
+    fclose (fp);
+
+}
diff --git a/elf.h b/elf.h
index 033e2a01890af3c2bfc0fe90b4111720e507f20b..536ae0c4b7b62323b76a21ff839c72572e747064 100644 (file)
--- a/elf.h
+++ b/elf.h
@@ -37,6 +37,25 @@ struct elf32_exec {
 
 };
 
+struct elf64_exec {
+
+    unsigned char e_ident[16];
+    unsigned char e_type[2];
+    unsigned char e_machine[2];
+    unsigned char e_version[4];
+    unsigned char e_entry[8];
+    unsigned char e_phoff[8];
+    unsigned char e_shoff[8];
+    unsigned char e_flags[4];
+    unsigned char e_ehsize[2];
+    unsigned char e_phentsize[2];
+    unsigned char e_phnum[2];
+    unsigned char e_shentsize[2];
+    unsigned char e_shnum[2];
+    unsigned char e_shstrndx[2];
+
+};
+
 #define     SHT_NULL                    0
 #define     SHT_PROGBITS                1
 #define     SHT_SYMTAB                  2
@@ -58,6 +77,21 @@ struct elf32_shdr {
 
 };
 
+struct elf64_shdr {
+    
+    unsigned char sh_name[4];
+    unsigned char sh_type[4];
+    unsigned char sh_flags[8];
+    unsigned char sh_addr[8];
+    unsigned char sh_offset[8];
+    unsigned char sh_size[8];
+    unsigned char sh_link[4];
+    unsigned char sh_info[4];
+    unsigned char sh_addralign[8];
+    unsigned char sh_entsize[8];
+
+};
+
 #define     SHF_WRITE                   0x01
 #define     SHF_ALLOC                   0x02
 #define     SHF_EXEC_INSTR              0x04
@@ -73,6 +107,17 @@ struct elf32_sym {
 
 };
 
+struct elf64_sym {
+
+    unsigned char st_name[4];
+    unsigned char st_info[1];
+    unsigned char st_other[1];
+    unsigned char st_shndx[2];
+    unsigned char st_value[8];
+    unsigned char st_size[8];
+
+};
+
 #define     SHN_UNDEF                   0x0000
 #define     SHN_LORESERVE               0xFF00
 #define     SHN_ABS                     0xFFF1
@@ -87,6 +132,14 @@ struct elf32_rela {
 
 };
 
+struct elf64_rela {
+
+    unsigned char r_offset[8];
+    unsigned char r_info[8];
+    unsigned char r_addend[8];
+
+};
+
 struct elf32_rel {
 
     unsigned char r_offset[4];
@@ -98,6 +151,21 @@ struct elf32_rel {
 #define     R_386_32                    1
 #define     R_386_PC32                  2
 
+struct elf64_rel {
+
+    unsigned char r_offset[8];
+    unsigned char r_info[8];
+
+};
+
+#define     R_AMD64_NONE                0
+#define     R_AMD64_64                  1
+#define     R_AMD64_PC32                2
+#define     R_AMD64_PLT32               4
+#define     R_AMD64_RELATIVE            8
+#define     R_AMD64_32                  10
+#define     R_AMD64_32S                 11
+
 struct elf32_phdr {
 
     unsigned char p_type[4];
@@ -111,10 +179,26 @@ struct elf32_phdr {
 
 };
 
-void read_elf32_object (const char *filename, unsigned char *data, unsigned long data_size, int endianess);
+struct elf64_phdr {
+
+    unsigned char p_type[4];
+    unsigned char p_flags[4];
+    unsigned char p_offset[8];
+    unsigned char p_vaddr[8];
+    unsigned char p_paddr[8];
+    unsigned char p_filesz[8];
+    unsigned char p_memsz[8];
+    unsigned char p_align[8];
+
+};
 
 void elf_before_link (void);
+
+void read_elf32_object (const char *filename, unsigned char *data, unsigned long data_size, int endianess);
+void read_elf64_object (const char *filename, unsigned char *data, unsigned long data_size, int endianess);
+
 void elf32_write (const char *filename);
+void elf64_write (const char *filename);
 
 #include    "stdint.h"
 uint64_t elf_get_first_section_rva (void);
diff --git a/ld.c b/ld.c
index a467ff0c904fdf2ee50cbce411dcd997282c567d..f032dde72062e9a08fb4359717ba43f584f2e765 100644 (file)
--- a/ld.c
+++ b/ld.c
@@ -118,8 +118,7 @@ static int read_object_file (const char *filename, unsigned char *data, unsigned
         int endianess = (data[EI_DATA] == ELF_DATA2MSB);
         
         if (data[EI_CLASS] == ELF_CLASS64) {
-            /*elf64_get_symbols (object, offset + 8, endianess);*/
-            report_at (__FILE__, __LINE__, REPORT_INTERNAL_ERROR, "currently 64-bit elf support isn't implemented");
+            read_elf64_object (filename, data, data_size, endianess);
         } else {
             read_elf32_object (filename, data, data_size, endianess);
         }
@@ -612,6 +611,8 @@ int main (int argc, char **argv) {
         elks_write (state->output_filename);
     } else if (state->format == LD_FORMAT_I386_ELF) {
         elf32_write (state->output_filename);
+    } else if (state->format == LD_FORMAT_AMD64_ELF) {
+        elf64_write (state->output_filename);
     } else if (state->format == LD_FORMAT_I386_PE) {
     
         pe_after_link ();
diff --git a/lib.c b/lib.c
index 928954989067d391155842fde71efa6ccce58458..17105bb903fba79b380af3ab4104e8e04d7fb57b 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -109,7 +109,7 @@ static void print_usage (void) {
         fprintf (stderr, "    --help                            Print option help.\n");
         fprintf (stderr, "    --oformat FORMAT                  Specify the format of output file (default msdos).\n");
         fprintf (stderr, "                                          Supported formats are:\n");
-        fprintf (stderr, "                                              a.out-i386, elf-i386\n");
+        fprintf (stderr, "                                              a.out-i386, elf-amd64, elf-i386\n");
         fprintf (stderr, "                                              elks-ia16, elks-i386\n");
         fprintf (stderr, "                                              macho-aarch64, macho-amd64\n");
         fprintf (stderr, "                                              pe-i386, binary, msdos\n");
@@ -340,6 +340,18 @@ static void use_option (const char *cmd_arg, int idx, const char *optarg) {
             
             }
             
+            if (xstrcasecmp (optarg, "elf-amd64") == 0) {
+            
+                state->format = LD_FORMAT_AMD64_ELF;
+                
+                /*if (state->emulation == LD_EMULATION_NONE) {
+                    state->emulation = LD_EMULATION_I386_COFF;
+                }*/
+                
+                break;
+            
+            }
+            
             report_at (program_name, 0, REPORT_ERROR, "unrecognised output format '%s'", optarg);
             exit (EXIT_FAILURE);