1 /* ----------------------------------------------------------------------- *
3 * Copyright 2008 H. Peter Anvin - All Rights Reserved
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
8 * Boston MA 02110-1301, USA; either version 2 of the License, or
9 * (at your option) any later version; incorporated herein by reference.
11 * ----------------------------------------------------------------------- */
16 * Take a linked list of segments and output it as an ELF32 image
27 int output_elf(struct segment *segs, addr_t entry, FILE *out)
33 int namebytes = 11; /* Null entry plus .shstrtab */
35 uint32_t data_start, data_offset;
36 uint32_t data_size = 0;
40 for (s = segs; s; s = s->next) {
43 namebytes += strlen(s->name)+1;
44 if (s->sh_type != SHT_NOBITS)
45 data_size += s->length;
48 memset(&ehdr, 0, sizeof ehdr);
49 ehdr.e_ident[EI_MAG0] = ELFMAG0;
50 ehdr.e_ident[EI_MAG1] = ELFMAG1;
51 ehdr.e_ident[EI_MAG2] = ELFMAG2;
52 ehdr.e_ident[EI_MAG3] = ELFMAG3;
53 ehdr.e_ident[EI_CLASS] = ELFCLASS32;
54 ehdr.e_ident[EI_DATA] = ELFDATA2LSB;
55 ehdr.e_ident[EI_VERSION] = EV_CURRENT;
56 ehdr.e_ident[EI_OSABI] = ELFOSABI_STANDALONE;
58 wrle16(ET_EXEC, &ehdr.e_type);
59 wrle16(EM_386, &ehdr.e_machine);
60 wrle32(EV_CURRENT, &ehdr.e_version);
61 wrle32(entry, &ehdr.e_entry);
62 wrle32(sizeof ehdr, &ehdr.e_phoff);
63 shoff = sizeof ehdr + nsections*(sizeof phdr) + data_size + namebytes;
64 shoff = (shoff+3) & ~3;
65 wrle32(shoff, &ehdr.e_shoff);
66 wrle16(sizeof ehdr, &ehdr.e_ehsize);
67 wrle16(sizeof phdr, &ehdr.e_phentsize);
68 wrle16(nsections, &ehdr.e_phnum);
69 wrle16(sizeof shdr, &ehdr.e_shentsize);
70 wrle16(nsections+2, &ehdr.e_shnum);
71 wrle16(nsections+1, &ehdr.e_shstrndx);
72 fwrite(&ehdr, 1, sizeof ehdr, out);
74 /* First actual data byte */
75 data_start = (sizeof ehdr) + nsections*(sizeof phdr);
77 /* Program header table */
78 data_offset = data_start;
79 for (s = segs; s; s = s->next) {
80 uint32_t filesize, memsize;
81 uint32_t p_type, p_flags;
83 filesize = (s->sh_type == SHT_NOBITS) ? 0 : s->length;
84 memsize = (s->sh_flags & SHF_ALLOC) ? s->length : 0;
95 p_type = PT_NULL; /* No other types supported */
100 if (s->sh_flags & SHF_ALLOC) /* Somewhat cheesy... */
102 if (s->sh_flags & SHF_EXECINSTR)
104 if (s->sh_flags & SHF_WRITE)
107 memset(&phdr, 0, sizeof phdr);
108 wrle32(p_type, &phdr.p_type);
109 wrle32(data_offset, &phdr.p_offset);
110 wrle32(s->address, &phdr.p_vaddr);
111 wrle32(s->address, &phdr.p_paddr);
112 wrle32(filesize, &phdr.p_filesz);
113 wrle32(memsize, &phdr.p_memsz);
114 wrle32(p_flags, &phdr.p_flags);
115 wrle32(1, &phdr.p_align);
117 fwrite(&phdr, 1, sizeof phdr, out);
119 data_offset += filesize;
122 /* Actual file data */
123 for (s = segs; s; s = s->next) {
124 if (s->sh_type != SHT_NOBITS)
125 fwrite(s->data, 1, s->length, out);
129 putc(0, out); /* Null string table entry */
131 for (s = segs; s; s = s->next) {
132 uint32_t len = strlen(s->name)+1;
133 fwrite(s->name, 1, len, out);
136 fwrite(".shstrtab", 1, 10, out);
139 while (data_offset & 3) {
140 putc(0, out); /* Align the section header table */
144 /* Section header table */
145 memset(&shdr, 0, sizeof shdr);
146 fwrite(&shdr, 1, sizeof shdr, out); /* Null section header */
148 data_offset = data_start;
150 for (s = segs; s; s = s->next) {
151 memset(&shdr, 0, sizeof shdr);
152 wrle32(name_offset, &shdr.sh_name);
153 wrle32(s->sh_type, &shdr.sh_type);
154 wrle32(s->sh_flags, &shdr.sh_flags);
155 wrle32(s->address, &shdr.sh_addr);
156 wrle32(data_offset, &shdr.sh_offset); /* Even for SHT_NOBITS */
157 wrle32(s->length, &shdr.sh_size);
158 wrle32(1, &shdr.sh_addralign);
160 fwrite(&shdr, 1, sizeof shdr, out);
162 name_offset += strlen(s->name)+1;
164 if (s->sh_type != SHT_NOBITS)
165 data_offset += s->length;
168 /* String table section header */
169 memset(&shdr, 0, sizeof shdr);
170 wrle32(name_offset, &shdr.sh_name);
171 wrle32(SHT_STRTAB, &shdr.sh_type);
172 wrle32(data_offset, &shdr.sh_offset);
173 wrle32(namebytes, &shdr.sh_size);
175 fwrite(&shdr, 1, sizeof shdr, out);