Update appimagetool.c
[appimagekit/gsi.git] / elf.c
blob77fab66c7facc11d8eefe7463bf020b853e5eb53
1 #include <stdio.h>
2 #include <stdint.h>
3 #include <errno.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <fcntl.h>
8 #include "light_elf.h"
9 #include "light_byteswap.h"
12 typedef Elf32_Nhdr Elf_Nhdr;
14 static char *fname;
15 static Elf64_Ehdr ehdr;
17 #if __BYTE_ORDER == __LITTLE_ENDIAN
18 #define ELFDATANATIVE ELFDATA2LSB
19 #elif __BYTE_ORDER == __BIG_ENDIAN
20 #define ELFDATANATIVE ELFDATA2MSB
21 #else
22 #error "Unknown machine endian"
23 #endif
25 static uint16_t file16_to_cpu(uint16_t val)
27 if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE)
28 val = bswap_16(val);
29 return val;
32 static uint32_t file32_to_cpu(uint32_t val)
34 if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE)
35 val = bswap_32(val);
36 return val;
39 static uint64_t file64_to_cpu(uint64_t val)
41 if (ehdr.e_ident[EI_DATA] != ELFDATANATIVE)
42 val = bswap_64(val);
43 return val;
46 static unsigned long read_elf32(int fd)
48 Elf32_Ehdr ehdr32;
49 Elf32_Shdr shdr32;
50 off_t last_shdr_offset;
51 ssize_t ret;
52 unsigned long sht_end, last_section_end;
54 ret = pread(fd, &ehdr32, sizeof(ehdr32), 0);
55 if (ret < 0 || (size_t)ret != sizeof(ehdr32)) {
56 fprintf(stderr, "Read of ELF header from %s failed: %s\n",
57 fname, strerror(errno));
58 exit(10);
61 ehdr.e_shoff = file32_to_cpu(ehdr32.e_shoff);
62 ehdr.e_shentsize = file16_to_cpu(ehdr32.e_shentsize);
63 ehdr.e_shnum = file16_to_cpu(ehdr32.e_shnum);
65 last_shdr_offset = ehdr.e_shoff + (ehdr.e_shentsize * (ehdr.e_shnum - 1));
66 ret = pread(fd, &shdr32, sizeof(shdr32), last_shdr_offset);
67 if (ret < 0 || (size_t)ret != sizeof(shdr32)) {
68 fprintf(stderr, "Read of ELF section header from %s failed: %s\n",
69 fname, strerror(errno));
70 exit(10);
73 /* ELF ends either with the table of section headers (SHT) or with a section. */
74 sht_end = ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum);
75 last_section_end = file64_to_cpu(shdr32.sh_offset) + file64_to_cpu(shdr32.sh_size);
76 return sht_end > last_section_end ? sht_end : last_section_end;
79 static unsigned long read_elf64(int fd)
81 Elf64_Ehdr ehdr64;
82 Elf64_Shdr shdr64;
83 off_t last_shdr_offset;
84 ssize_t ret;
85 unsigned long sht_end, last_section_end;
87 ret = pread(fd, &ehdr64, sizeof(ehdr64), 0);
88 if (ret < 0 || (size_t)ret != sizeof(ehdr64)) {
89 fprintf(stderr, "Read of ELF header from %s failed: %s\n",
90 fname, strerror(errno));
91 exit(10);
94 ehdr.e_shoff = file64_to_cpu(ehdr64.e_shoff);
95 ehdr.e_shentsize = file16_to_cpu(ehdr64.e_shentsize);
96 ehdr.e_shnum = file16_to_cpu(ehdr64.e_shnum);
98 last_shdr_offset = ehdr.e_shoff + (ehdr.e_shentsize * (ehdr.e_shnum - 1));
99 ret = pread(fd, &shdr64, sizeof(shdr64), last_shdr_offset);
100 if (ret < 0 || (size_t)ret != sizeof(shdr64)) {
101 fprintf(stderr, "Read of ELF section header from %s failed: %s\n",
102 fname, strerror(errno));
103 exit(10);
106 /* ELF ends either with the table of section headers (SHT) or with a section. */
107 sht_end = ehdr.e_shoff + (ehdr.e_shentsize * ehdr.e_shnum);
108 last_section_end = file64_to_cpu(shdr64.sh_offset) + file64_to_cpu(shdr64.sh_size);
109 return sht_end > last_section_end ? sht_end : last_section_end;
112 unsigned long get_elf_size(const char *fname)
114 ssize_t ret;
115 int fd;
116 static unsigned long size = 0;
118 fd = open(fname, O_RDONLY);
119 if (fd < 0) {
120 fprintf(stderr, "Cannot open %s: %s\n",
121 fname, strerror(errno));
122 return(1);
124 ret = pread(fd, ehdr.e_ident, EI_NIDENT, 0);
125 if (ret != EI_NIDENT) {
126 fprintf(stderr, "Read of e_ident from %s failed: %s\n",
127 fname, strerror(errno));
128 return(1);
130 if ((ehdr.e_ident[EI_DATA] != ELFDATA2LSB) &&
131 (ehdr.e_ident[EI_DATA] != ELFDATA2MSB))
133 fprintf(stderr, "Unkown ELF data order %u\n",
134 ehdr.e_ident[EI_DATA]);
135 return(1);
137 if(ehdr.e_ident[EI_CLASS] == ELFCLASS32) {
138 size = read_elf32(fd);
139 } else if(ehdr.e_ident[EI_CLASS] == ELFCLASS64) {
140 size = read_elf64(fd);
141 } else {
142 fprintf(stderr, "Unknown ELF class %u\n", ehdr.e_ident[EI_CLASS]);
143 return(1);
146 close(fd);
147 return size;