Merge remote-tracking branch 'origin/master' into isa/arm64
[lunaix-os.git] / lunaix-os / scripts / elftool.c
1 #include <sys/mman.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <sys/fcntl.h>
5 #include <unistd.h>
6 #include <errno.h>
7 #include <string.h>
8
9 typedef unsigned long   elf64_ptr_t;
10 typedef unsigned short  elf64_hlf_t;
11 typedef unsigned long   elf64_off_t;
12 typedef          int    elf64_swd_t;
13 typedef unsigned int    elf64_wrd_t;
14 typedef unsigned long   elf64_xwrd_t;
15 typedef          long   elf64_sxwrd_t;
16
17 typedef unsigned int    elf32_ptr_t;
18 typedef unsigned short  elf32_hlf_t;
19 typedef unsigned int    elf32_off_t;
20 typedef unsigned int    elf32_swd_t;
21 typedef unsigned int    elf32_wrd_t;
22
23 #define ELFCLASS32 1
24 #define ELFCLASS64 2
25
26 #define PT_LOAD 1
27
28 typedef unsigned long ptr_t;
29
30 struct elf_generic_ehdr
31 {
32     union {
33         struct {
34             unsigned int signature;
35             unsigned char class;
36         } __attribute__((packed));
37         unsigned char e_ident[16];
38     };
39     unsigned short e_type;
40     unsigned short e_machine;
41     unsigned int e_version;
42 };
43
44 struct elf32_ehdr
45 {
46     struct elf_generic_ehdr head;
47     elf32_ptr_t e_entry;
48     elf32_off_t e_phoff;
49     elf32_off_t e_shoff;
50     elf32_wrd_t e_flags;
51     elf32_hlf_t e_ehsize;
52     elf32_hlf_t e_phentsize;
53     elf32_hlf_t e_phnum;
54     elf32_hlf_t e_shentsize;
55     elf32_hlf_t e_shnum;
56     elf32_hlf_t e_shstrndx;
57 };
58
59 struct elf64_ehdr
60 {
61     struct elf_generic_ehdr head;
62     elf64_ptr_t e_entry;
63     elf64_off_t e_phoff;
64     elf64_off_t e_shoff;
65     elf64_wrd_t e_flags;
66     elf64_hlf_t e_ehsize;
67     elf64_hlf_t e_phentsize;
68     elf64_hlf_t e_phnum;
69     elf64_hlf_t e_shentsize;
70     elf64_hlf_t e_shnum;
71     elf64_hlf_t e_shstrndx;
72 };
73
74 struct elf64_phdr
75 {
76     elf64_wrd_t p_type;
77     elf64_wrd_t p_flags;
78     elf64_off_t p_offset;
79     elf64_ptr_t p_va;
80     elf64_ptr_t p_pa;
81     elf64_xwrd_t p_filesz;
82     elf64_xwrd_t p_memsz;
83     elf64_xwrd_t p_align;
84 };
85
86 struct elf32_phdr
87 {
88     elf32_wrd_t p_type;
89     elf32_off_t p_offset;
90     elf32_ptr_t p_va;
91     elf32_ptr_t p_pa;
92     elf32_wrd_t p_filesz;
93     elf32_wrd_t p_memsz;
94     elf32_wrd_t p_flags;
95     elf32_wrd_t p_align;
96 };
97
98 struct elf_section
99 {
100     ptr_t va;
101     ptr_t pa;
102     unsigned int flags;
103     unsigned int memsz;
104 };
105
106 struct ksec_genctx
107 {
108     struct elf_section* secs;
109     int size;
110     const char* prefix;
111 };
112
113 #define MAPPED_SIZE     (256 << 10)
114
115 static struct elf_generic_ehdr*
116 __load_elf(const char* path)
117 {
118     int fd;
119     struct elf_generic_ehdr* ehdr;
120     
121     fd = open(path, O_RDONLY);
122     if (fd == -1) {
123         printf("fail to open elf: %s\n", strerror(errno));
124         return NULL;
125     }
126
127     ehdr = mmap(NULL, MAPPED_SIZE, PROT_READ, MAP_SHARED, fd, 0);
128     if ((void*)ehdr == (void*)-1) {
129         printf("fail to mmap elf (%d): %s\n", errno, strerror(errno));
130         return NULL;
131     }
132
133     return ehdr;
134 }
135
136 static void
137 __wr_mapentry(struct ksec_genctx* ctx, struct elf_section* sec)
138 {
139     printf("/* --- entry --- */\n");
140     printf("%s 0x%lx\n", ctx->prefix, sec->va);
141     printf("%s 0x%lx\n", ctx->prefix, sec->pa);
142     printf(".4byte 0x%x\n", sec->memsz);
143     printf(".4byte 0x%x\n", sec->flags);
144 }
145
146 static void
147 __wr_maplast(struct ksec_genctx* ctx, struct elf_section* sec)
148 {
149     printf("/* --- entry --- */\n");
150     printf("%s 0x%lx\n", ctx->prefix, sec->va);
151     printf("%s 0x%lx\n", ctx->prefix, sec->pa);
152     printf(".4byte (__kexec_end - 0x%lx)\n", sec->va);
153     printf(".4byte 0x%x\n", sec->flags);
154 }
155
156 #define SIZEPF32    ".4byte"
157 #define SIZEPF64    ".8byte"
158 #define gen_ksec_map(bits, ctx, ehdr)                                           \
159     ({                                                                          \
160         struct elf##bits##_ehdr *_e;                                            \
161         struct elf##bits##_phdr *phdr, *phent;                                  \
162         _e   = (struct elf##bits##_ehdr*)(ehdr);                                \
163         phdr = (struct elf##bits##_phdr*)((ptr_t)_e + _e->e_phoff);             \
164         for (int i = 0, j = 0; i < _e->e_phnum; i++) {                          \
165             phent = &phdr[i];                                                   \
166             if (phent->p_type != PT_LOAD) {                                     \
167                 continue;                                                       \
168             }                                                                   \
169             ctx.secs[j++] = (struct elf_section) {                              \
170                 .va = phent->p_va,                                              \
171                 .pa = phent->p_pa,                                              \
172                 .memsz = phent->p_memsz,                                        \
173                 .flags = phent->p_flags,                                        \
174             };                                                                  \
175         }                                                                       \
176     })
177
178 #define count_loadable(bits, ehdr)                                              \
179     ({                                                                          \
180         struct elf##bits##_ehdr *_e;                                            \
181         struct elf##bits##_phdr *phdr, *phent;                                  \
182         int all_loadable = 0;                                                   \
183         _e   = (struct elf##bits##_ehdr*)(ehdr);                                \
184         phdr = (struct elf##bits##_phdr*)((ptr_t)_e + _e->e_phoff);             \
185         for (int i = 0; i < _e->e_phnum; i++) {                                 \
186             phent = &phdr[i];                                                   \
187             if (phent->p_type == PT_LOAD) {                                     \
188                 all_loadable++;                                                 \
189             }                                                                   \
190         }                                                                       \
191         all_loadable;                                                           \
192     })
193
194 static void
195 __emit_size(struct ksec_genctx* genctx)
196 {
197     ptr_t va;
198     unsigned int size = 0;
199     int n = genctx->size - 1;
200
201     /*
202         first two LOAD are boot text and data.
203         we are calculating the kernel size, so
204         ignore it.
205     */
206     for (int i = 2; i < n; i++)
207     {
208         size += genctx->secs[i].memsz;
209     }
210
211     va = genctx->secs[n].va;
212     printf(".4byte 0x%x + (__kexec_end - 0x%lx)\n", size, va);
213 }
214
215 static void
216 __generate_kernelmap(struct elf_generic_ehdr* ehdr)
217 {
218     
219     printf(".section .autogen.ksecmap, \"a\", @progbits\n"
220            ".global __autogen_ksecmap\n"
221            "__autogen_ksecmap:\n");
222
223     struct ksec_genctx genctx;
224
225     if (ehdr->class == ELFCLASS32) {
226         genctx.size = count_loadable(32, ehdr);
227         genctx.prefix = SIZEPF32;
228     } else {
229         genctx.size = count_loadable(64, ehdr);
230         genctx.prefix = SIZEPF64;
231     }
232
233     genctx.secs = calloc(genctx.size, sizeof(struct elf_section));
234
235     if (ehdr->class == ELFCLASS32) {
236         gen_ksec_map(32, genctx, ehdr);
237     }
238     else {
239         genctx.size = count_loadable(64, ehdr);
240         gen_ksec_map(64, genctx, ehdr);
241     }
242
243     int i = 0;
244     struct elf_section* sec_ent;
245
246     printf(".4byte 0x%x\n", genctx.size);
247     __emit_size(&genctx);
248     
249     /*
250         Lunaix define the last LOAD phdr is variable
251         sized. that is the actual size will not be known 
252         until after relink, so we need to emit a special 
253         entry and let linker determine the size. 
254         (see __wr_maplast)
255      */
256
257     for (; i < genctx.size - 1; i++)
258     {
259         sec_ent = &genctx.secs[i];
260         __wr_mapentry(&genctx, sec_ent);
261     }
262     
263     __wr_maplast(&genctx, &genctx.secs[i]);
264 }
265
266 #define MODE_GETARCH 1
267 #define MODE_GENLOAD 2
268 #define MODE_ERROR   3
269
270 int 
271 main(int argc, char* const* argv)
272 {
273     int c, mode;
274     char *path, *out;
275
276     path = NULL;
277     mode = MODE_GETARCH;
278
279     while ((c = getopt(argc, argv, "i:tph")) != -1)
280     {
281         switch (c)
282         {
283             case 'i':
284                 path = optarg;
285             break;
286
287             case 't':
288                 mode = MODE_GETARCH;
289             break;
290
291             case 'p':
292                 mode = MODE_GENLOAD;
293             break;
294
295             case 'h':
296                 printf("usage: elftool -i elf_file -pt [-o out]\n");
297                 printf("       -t: get elf type.\n");
298                 printf("       -p: generate load sections.\n");
299                 exit(1);
300             break;
301
302             default:
303                 printf("unknown option: '%c'", optopt);
304                 exit(1);
305             break;
306         }
307     }
308
309     if (!path) {
310         printf("must specify an elf.\n");
311         exit(1);
312     }
313
314     struct elf_generic_ehdr* ehdr;
315     ehdr = __load_elf(path);
316
317     if (!ehdr) {
318         return 1;
319     }
320
321     if (ehdr->signature != 0x464c457fU) {
322         printf("not an elf file\n");
323         return 1;
324     }
325
326     if (mode == MODE_GETARCH) {
327         if (ehdr->class == ELFCLASS32) {
328             printf("ELF32\n");
329         }
330         else {
331             printf("ELF64\n");
332         }
333         return 0;
334     }
335
336     if (mode == MODE_GENLOAD) {
337         __generate_kernelmap(ehdr);
338         return 0;
339     }
340
341     return 0;
342 }