From eed86c760f71f7e740c26c2521e5a5d0c0d21d0d Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 29 Jan 2018 02:44:30 +0800 Subject: [PATCH] Add support to PXA devices Close #340 --- native/jni/magiskboot/bootimg.c | 192 +++++++++++++++++------------ native/jni/magiskboot/bootimg.h | 141 +++++++++++++-------- native/jni/magiskboot/magiskboot.h | 2 +- native/jni/magiskboot/main.c | 7 +- native/jni/magiskboot/types.c | 2 +- 5 files changed, 208 insertions(+), 136 deletions(-) diff --git a/native/jni/magiskboot/bootimg.c b/native/jni/magiskboot/bootimg.c index 4a86a5707..eb970e0e1 100644 --- a/native/jni/magiskboot/bootimg.c +++ b/native/jni/magiskboot/bootimg.c @@ -13,6 +13,14 @@ #define ELF32_RET 4 #define ELF64_RET 5 +// Macros to determine header on-the-go +#define lheader(b, e, o) \ + ((b)->flags & PXA_FLAG) ? \ + (((struct pxa_boot_img_hdr*) (b)->hdr)->e o) : \ + (((struct boot_img_hdr*) (b)->hdr)->e o) + +#define header(b, e) (lheader(b, e,)) + static void dump(void *buf, size_t size, const char *filename) { int fd = creat(filename, 0644); xwrite(fd, buf, size); @@ -32,29 +40,42 @@ static void restore_buf(int fd, const void *buf, size_t size) { xwrite(fd, buf, size); } -static void print_hdr(const boot_img_hdr *hdr) { - fprintf(stderr, "KERNEL [%d] @ 0x%08x\n", hdr->kernel_size, hdr->kernel_addr); - fprintf(stderr, "RAMDISK [%d] @ 0x%08x\n", hdr->ramdisk_size, hdr->ramdisk_addr); - fprintf(stderr, "SECOND [%d] @ 0x%08x\n", hdr->second_size, hdr->second_addr); - fprintf(stderr, "EXTRA [%d] @ 0x%08x\n", hdr->extra_size, hdr->tags_addr); - fprintf(stderr, "PAGESIZE [%d]\n", hdr->page_size); - if (hdr->os_version != 0) { - int a,b,c,y,m = 0; - int os_version, os_patch_level; - os_version = hdr->os_version >> 11; - os_patch_level = hdr->os_version & 0x7ff; +static void print_hdr(const boot_img *boot) { + fprintf(stderr, "KERNEL [%u]\n", header(boot, kernel_size)); + fprintf(stderr, "RAMDISK [%u]\n", header(boot, ramdisk_size)); + fprintf(stderr, "SECOND [%u]\n", header(boot, second_size)); + fprintf(stderr, "EXTRA [%u]\n", header(boot, extra_size)); + fprintf(stderr, "PAGESIZE [%u]\n", header(boot, page_size)); - a = (os_version >> 14) & 0x7f; - b = (os_version >> 7) & 0x7f; - c = os_version & 0x7f; - fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c); + if (!(boot->flags & PXA_FLAG)) { + uint32_t os_version = ((boot_img_hdr*) boot->hdr)->os_version; + if (os_version) { + int a,b,c,y,m = 0; + int version, patch_level; + version = os_version >> 11; + patch_level = os_version & 0x7ff; - y = (os_patch_level >> 4) + 2000; - m = os_patch_level & 0xf; - fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m); + a = (version >> 14) & 0x7f; + b = (version >> 7) & 0x7f; + c = version & 0x7f; + fprintf(stderr, "OS_VERSION [%d.%d.%d]\n", a, b, c); + + y = (patch_level >> 4) + 2000; + m = patch_level & 0xf; + fprintf(stderr, "PATCH_LEVEL [%d-%02d]\n", y, m); + } } - fprintf(stderr, "NAME [%s]\n", hdr->name); - fprintf(stderr, "CMDLINE [%s]\n", hdr->cmdline); + + fprintf(stderr, "NAME [%s]\n", header(boot, name)); + fprintf(stderr, "CMDLINE [%s]\n", header(boot, cmdline)); +} + +static void clean_boot(boot_img *boot) { + munmap(boot->map_addr, boot->map_size); + free(boot->hdr); + free(boot->k_hdr); + free(boot->r_hdr); + memset(boot, 0, sizeof(*boot)); } int parse_img(const char *image, boot_img *boot) { @@ -77,29 +98,37 @@ int parse_img(const char *image, boot_img *boot) { exit(ELF64_RET); case AOSP: // Read the header - memcpy(&boot->hdr, head + pos, sizeof(boot->hdr)); - pos += boot->hdr.page_size; + if (((boot_img_hdr*) head)->page_size >= 0x02000000) { + boot->flags |= PXA_FLAG; + fprintf(stderr, "PXA_BOOT_HDR\n"); + boot->hdr = malloc(sizeof(pxa_boot_img_hdr)); + memcpy(boot->hdr, head, sizeof(pxa_boot_img_hdr)); + } else { + boot->hdr = malloc(sizeof(boot_img_hdr)); + memcpy(boot->hdr, head, sizeof(boot_img_hdr)); + } + pos += header(boot, page_size); - print_hdr(&boot->hdr); + print_hdr(boot); boot->kernel = head + pos; - pos += boot->hdr.kernel_size; - mem_align(&pos, boot->hdr.page_size); + pos += header(boot, kernel_size); + mem_align(&pos, header(boot, page_size)); boot->ramdisk = head + pos; - pos += boot->hdr.ramdisk_size; - mem_align(&pos, boot->hdr.page_size); + pos += header(boot, ramdisk_size); + mem_align(&pos, header(boot, page_size)); - if (boot->hdr.second_size) { + if (header(boot, second_size)) { boot->second = head + pos; - pos += boot->hdr.second_size; - mem_align(&pos, boot->hdr.page_size); + pos += header(boot, second_size); + mem_align(&pos, header(boot, page_size)); } - if (boot->hdr.extra_size) { + if (header(boot, extra_size)) { boot->extra = head + pos; - pos += boot->hdr.extra_size; - mem_align(&pos, boot->hdr.page_size); + pos += header(boot, extra_size); + mem_align(&pos, header(boot, page_size)); } if (pos < boot->map_size) { @@ -108,33 +137,40 @@ int parse_img(const char *image, boot_img *boot) { } // Search for dtb in kernel - for (uint32_t i = 0; i < boot->hdr.kernel_size; ++i) { + for (uint32_t i = 0; i < header(boot, kernel_size); ++i) { if (memcmp(boot->kernel + i, DTB_MAGIC, 4) == 0) { boot->dtb = boot->kernel + i; - boot->dt_size = boot->hdr.kernel_size - i; - boot->hdr.kernel_size = i; + boot->dt_size = header(boot, kernel_size) - i; + lheader(boot, kernel_size, = i); fprintf(stderr, "DTB [%u]\n", boot->dt_size); + break; } } - boot->ramdisk_type = check_type(boot->ramdisk); boot->kernel_type = check_type(boot->kernel); + boot->ramdisk_type = check_type(boot->ramdisk); // Check MTK if (boot->kernel_type == MTK) { - fprintf(stderr, "MTK_KERNEL_HDR [512]\n"); + fprintf(stderr, "MTK_KERNEL_HDR\n"); boot->flags |= MTK_KERNEL; - memcpy(&boot->mtk_kernel_hdr, boot->kernel, sizeof(mtk_hdr)); + boot->k_hdr = malloc(sizeof(mtk_hdr)); + memcpy(boot->k_hdr, boot->kernel, sizeof(mtk_hdr)); + fprintf(stderr, "KERNEL [%u]\n", boot->k_hdr->size); + fprintf(stderr, "NAME [%s]\n", boot->k_hdr->name); boot->kernel += 512; - boot->hdr.kernel_size -= 512; + lheader(boot, kernel_size, -= 512); boot->kernel_type = check_type(boot->kernel); } if (boot->ramdisk_type == MTK) { - fprintf(stderr, "MTK_RAMDISK_HDR [512]\n"); + fprintf(stderr, "MTK_RAMDISK_HDR\n"); boot->flags |= MTK_RAMDISK; - memcpy(&boot->mtk_ramdisk_hdr, boot->ramdisk, sizeof(mtk_hdr)); + boot->r_hdr = malloc(sizeof(mtk_hdr)); + memcpy(boot->r_hdr, boot->kernel, sizeof(mtk_hdr)); + fprintf(stderr, "RAMDISK [%u]\n", boot->r_hdr->size); + fprintf(stderr, "NAME [%s]\n", boot->r_hdr->name); boot->ramdisk += 512; - boot->hdr.ramdisk_size -= 512; + lheader(boot, ramdisk_size, -= 512); boot->ramdisk_type = check_type(boot->ramdisk); } @@ -154,7 +190,7 @@ int parse_img(const char *image, boot_img *boot) { LOGE("No boot image magic found!\n"); } -void unpack(const char* image) { +int unpack(const char *image) { boot_img boot; int ret = parse_img(image, &boot); int fd; @@ -162,10 +198,10 @@ void unpack(const char* image) { // Dump kernel if (COMPRESSED(boot.kernel_type)) { fd = creat(KERNEL_FILE, 0644); - decomp(boot.kernel_type, fd, boot.kernel, boot.hdr.kernel_size); + decomp(boot.kernel_type, fd, boot.kernel, header(&boot, kernel_size)); close(fd); } else { - dump(boot.kernel, boot.hdr.kernel_size, KERNEL_FILE); + dump(boot.kernel, header(&boot, kernel_size), KERNEL_FILE); } if (boot.dt_size) { @@ -176,32 +212,32 @@ void unpack(const char* image) { // Dump ramdisk if (COMPRESSED(boot.ramdisk_type)) { fd = creat(RAMDISK_FILE, 0644); - decomp(boot.ramdisk_type, fd, boot.ramdisk, boot.hdr.ramdisk_size); + decomp(boot.ramdisk_type, fd, boot.ramdisk, header(&boot, ramdisk_size)); close(fd); } else { - dump(boot.ramdisk, boot.hdr.ramdisk_size, RAMDISK_FILE ".raw"); + dump(boot.ramdisk, header(&boot, ramdisk_size), RAMDISK_FILE ".raw"); LOGE("Unknown ramdisk format! Dumped to %s\n", RAMDISK_FILE ".raw"); } - if (boot.hdr.second_size) { + if (header(&boot, second_size)) { // Dump second - dump(boot.second, boot.hdr.second_size, SECOND_FILE); + dump(boot.second, header(&boot, second_size), SECOND_FILE); } - if (boot.hdr.extra_size) { + if (header(&boot, extra_size)) { // Dump extra - dump(boot.extra, boot.hdr.extra_size, EXTRA_FILE); + dump(boot.extra, header(&boot, extra_size), EXTRA_FILE); } - munmap(boot.map_addr, boot.map_size); - exit(ret); + clean_boot(&boot); + return ret; } void repack(const char* orig_image, const char* out_image) { boot_img boot; // There are possible two MTK headers - size_t mtk_kernel_off, mtk_ramdisk_off; + off_t mtk_kernel_off, mtk_ramdisk_off; // Parse original image parse_img(orig_image, &boot); @@ -212,7 +248,7 @@ void repack(const char* orig_image, const char* out_image) { int fd = creat(out_image, 0644); // Skip a page for header - write_zero(fd, boot.hdr.page_size); + write_zero(fd, header(&boot, page_size)); if (boot.flags & MTK_KERNEL) { // Record position and skip MTK header @@ -223,16 +259,16 @@ void repack(const char* orig_image, const char* out_image) { size_t raw_size; void *kernel_raw; mmap_ro(KERNEL_FILE, &kernel_raw, &raw_size); - boot.hdr.kernel_size = comp(boot.kernel_type, fd, kernel_raw, raw_size); + lheader(&boot, kernel_size, = comp(boot.kernel_type, fd, kernel_raw, raw_size)); munmap(kernel_raw, raw_size); } else { - boot.hdr.kernel_size = restore(KERNEL_FILE, fd); + lheader(&boot, kernel_size, = restore(KERNEL_FILE, fd)); } // Restore dtb if (boot.dt_size && access(DTB_FILE, R_OK) == 0) { - boot.hdr.kernel_size += restore(DTB_FILE, fd); + lheader(&boot, kernel_size, += restore(DTB_FILE, fd)); } - file_align(fd, boot.hdr.page_size, 1); + file_align(fd, header(&boot, page_size), 1); if (boot.flags & MTK_RAMDISK) { // Record position and skip MTK header @@ -244,7 +280,7 @@ void repack(const char* orig_image, const char* out_image) { size_t cpio_size; void *cpio; mmap_ro(RAMDISK_FILE, &cpio, &cpio_size); - boot.hdr.ramdisk_size = comp(boot.ramdisk_type, fd, cpio, cpio_size); + lheader(&boot, ramdisk_size, = comp(boot.ramdisk_type, fd, cpio, cpio_size)); munmap(cpio, cpio_size); } else { // Find compressed ramdisk @@ -259,20 +295,20 @@ void repack(const char* orig_image, const char* out_image) { } if (!found) LOGE("No ramdisk exists!\n"); - boot.hdr.ramdisk_size = restore(name, fd); + lheader(&boot, ramdisk_size, = restore(name, fd)); } - file_align(fd, boot.hdr.page_size, 1); + file_align(fd, header(&boot, page_size), 1); // Restore second - if (boot.hdr.second_size && access(SECOND_FILE, R_OK) == 0) { - boot.hdr.second_size = restore(SECOND_FILE, fd); - file_align(fd, boot.hdr.page_size, 1); + if (header(&boot, second_size) && access(SECOND_FILE, R_OK) == 0) { + lheader(&boot, second_size, = restore(SECOND_FILE, fd)); + file_align(fd, header(&boot, page_size), 1); } // Restore extra - if (boot.hdr.extra_size && access(EXTRA_FILE, R_OK) == 0) { - boot.hdr.extra_size = restore(EXTRA_FILE, fd); - file_align(fd, boot.hdr.page_size, 1); + if (header(&boot, extra_size) && access(EXTRA_FILE, R_OK) == 0) { + lheader(&boot, extra_size, = restore(EXTRA_FILE, fd)); + file_align(fd, header(&boot, page_size), 1); } // Check tail info, currently only for LG Bump and Samsung SEANDROIDENFORCE @@ -286,23 +322,23 @@ void repack(const char* orig_image, const char* out_image) { // Write MTK headers back if (boot.flags & MTK_KERNEL) { lseek(fd, mtk_kernel_off, SEEK_SET); - boot.mtk_kernel_hdr.size = boot.hdr.kernel_size; - boot.hdr.kernel_size += 512; - restore_buf(fd, &boot.mtk_kernel_hdr, sizeof(mtk_hdr)); + boot.k_hdr->size = header(&boot, kernel_size); + lheader(&boot, kernel_size, += 512); + restore_buf(fd, boot.k_hdr, sizeof(mtk_hdr)); } if (boot.flags & MTK_RAMDISK) { lseek(fd, mtk_ramdisk_off, SEEK_SET); - boot.mtk_ramdisk_hdr.size = boot.hdr.ramdisk_size; - boot.hdr.ramdisk_size += 512; - restore_buf(fd, &boot.mtk_ramdisk_hdr, sizeof(mtk_hdr)); + boot.r_hdr->size = header(&boot, ramdisk_size); + lheader(&boot, ramdisk_size, += 512); + restore_buf(fd, boot.r_hdr, sizeof(mtk_hdr)); } // Main header lseek(fd, 0, SEEK_SET); - restore_buf(fd, &boot.hdr, sizeof(boot.hdr)); + restore_buf(fd, boot.hdr, (boot.flags & PXA_FLAG) ? sizeof(pxa_boot_img_hdr) : sizeof(boot_img_hdr)); // Print new image info - print_hdr(&boot.hdr); + print_hdr(&boot); - munmap(boot.map_addr, boot.map_size); + clean_boot(&boot); close(fd); } diff --git a/native/jni/magiskboot/bootimg.h b/native/jni/magiskboot/bootimg.h index f871f53d9..98c91d4ec 100644 --- a/native/jni/magiskboot/bootimg.h +++ b/native/jni/magiskboot/bootimg.h @@ -21,48 +21,69 @@ #ifndef _BOOT_IMAGE_H_ #define _BOOT_IMAGE_H_ -typedef struct boot_img_hdr boot_img_hdr; - #define BOOT_MAGIC "ANDROID!" -#define BOOT_MAGIC_SIZE 8 -#define BOOT_NAME_SIZE 16 -#define BOOT_ARGS_SIZE 512 -#define BOOT_EXTRA_ARGS_SIZE 1024 -struct boot_img_hdr -{ - uint8_t magic[BOOT_MAGIC_SIZE]; +typedef struct boot_img_hdr { + char magic[8]; - uint32_t kernel_size; /* size in bytes */ - uint32_t kernel_addr; /* physical load addr */ + uint32_t kernel_size; /* size in bytes */ + uint32_t kernel_addr; /* physical load addr */ - uint32_t ramdisk_size; /* size in bytes */ - uint32_t ramdisk_addr; /* physical load addr */ + uint32_t ramdisk_size; /* size in bytes */ + uint32_t ramdisk_addr; /* physical load addr */ - uint32_t second_size; /* size in bytes */ - uint32_t second_addr; /* physical load addr */ + uint32_t second_size; /* size in bytes */ + uint32_t second_addr; /* physical load addr */ - uint32_t tags_addr; /* physical addr for kernel tags */ - uint32_t page_size; /* flash page size we assume */ - uint32_t extra_size; /* extra blob size in bytes */ + uint32_t tags_addr; /* physical addr for kernel tags */ + uint32_t page_size; /* flash page size we assume */ + uint32_t extra_size; /* extra blob size in bytes */ - /* operating system version and security patch level; for - * version "A.B.C" and patch level "Y-M-D": - * ver = A << 14 | B << 7 | C (7 bits for each of A, B, C) - * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) - * os_version = ver << 11 | lvl */ - uint32_t os_version; + /* operating system version and security patch level; for + * version "A.B.C" and patch level "Y-M-D": + * ver = A << 14 | B << 7 | C (7 bits for each of A, B, C) + * lvl = ((Y - 2000) & 127) << 4 | M (7 bits for Y, 4 bits for M) + * os_version = ver << 11 | lvl */ + uint32_t os_version; - uint8_t name[BOOT_NAME_SIZE]; /* asciiz product name */ + char name[16]; /* asciiz product name */ - uint8_t cmdline[BOOT_ARGS_SIZE]; + char cmdline[512]; - uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ + uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ - /* Supplemental command line data; kept here to maintain - * binary compatibility with older versions of mkbootimg */ - uint8_t extra_cmdline[BOOT_EXTRA_ARGS_SIZE]; -} __attribute__((packed)); + /* Supplemental command line data; kept here to maintain + * binary compatibility with older versions of mkbootimg */ + char extra_cmdline[1024]; +} __attribute__((packed)) boot_img_hdr ; + +typedef struct pxa_boot_img_hdr { + char magic[8]; + + uint32_t kernel_size; /* size in bytes */ + uint32_t kernel_addr; /* physical load addr */ + + uint32_t ramdisk_size; /* size in bytes */ + uint32_t ramdisk_addr; /* physical load addr */ + + uint32_t second_size; /* size in bytes */ + uint32_t second_addr; /* physical load addr */ + + uint32_t extra_size; /* extra blob size in bytes */ + uint32_t unknown; /* unknown value */ + uint32_t tags_addr; /* physical addr for kernel tags */ + uint32_t page_size; /* flash page size we assume */ + + char name[24]; /* asciiz product name */ + + char cmdline[512]; + + uint32_t id[8]; /* timestamp / checksum / sha1 / etc */ + + /* Supplemental command line data; kept here to maintain + * binary compatibility with older versions of mkbootimg */ + char extra_cmdline[1024]; +} __attribute__((packed)) pxa_boot_img_hdr; /* ** +-----------------+ @@ -74,7 +95,7 @@ struct boot_img_hdr ** +-----------------+ ** | second stage | o pages ** +-----------------+ -** | extra blobs | p pages +** | extra blob | p pages ** +-----------------+ ** ** n = (kernel_size + page_size - 1) / page_size @@ -95,33 +116,47 @@ struct boot_img_hdr */ typedef struct mtk_hdr { - uint8_t magic[4]; /* MTK magic */ - uint32_t size; /* Size of the content */ - uint8_t name[32]; /* The type of the header */ -} mtk_hdr; + uint32_t magic; /* MTK magic */ + uint32_t size; /* Size of the content */ + char name[32]; /* The type of the header */ +} __attribute__((packed)) mtk_hdr; // Flags -#define MTK_KERNEL 0x1 -#define MTK_RAMDISK 0x2 -#define CHROMEOS_FLAG 0x4 +#define MTK_KERNEL 0x01 +#define MTK_RAMDISK 0x02 +#define CHROMEOS_FLAG 0x04 +#define PXA_FLAG 0x08 typedef struct boot_img { - size_t map_size; - uint32_t dt_size; - size_t tail_size; - uint8_t flags; - file_t kernel_type, ramdisk_type; + // Memory map of the whole image + void *map_addr; + size_t map_size; - boot_img_hdr hdr; - mtk_hdr mtk_kernel_hdr, mtk_ramdisk_hdr; + // Headers + void *hdr; /* Either boot_img_hdr or pxa_boot_img_hdr */ + mtk_hdr *k_hdr; /* MTK kernel header */ + mtk_hdr *r_hdr; /* MTK ramdisk header */ - void *map_addr; - void *kernel; - void *dtb; - void *ramdisk; - void *second; - void *extra; - void *tail; + // Flags to indicate the state of current boot image + uint8_t flags; + + // The format of kernel and ramdisk + file_t kernel_type; + file_t ramdisk_type; + + // Pointer to dtb that is appended after kernel + void *dtb; + uint32_t dt_size; + + // Pointer to end of image + void *tail; + size_t tail_size; + + // Pointers to blocks defined in header + void *kernel; + void *ramdisk; + void *second; + void *extra; } boot_img; #endif diff --git a/native/jni/magiskboot/magiskboot.h b/native/jni/magiskboot/magiskboot.h index dfcd06efe..2839993d4 100644 --- a/native/jni/magiskboot/magiskboot.h +++ b/native/jni/magiskboot/magiskboot.h @@ -14,7 +14,7 @@ #define NEW_BOOT "new-boot.img" // Main entries -void unpack(const char *image); +int unpack(const char *image); void repack(const char* orig_image, const char* out_image); void hexpatch(const char *image, const char *from, const char *to); int parse_img(const char *image, boot_img *boot); diff --git a/native/jni/magiskboot/main.c b/native/jni/magiskboot/main.c index 8417173d9..08eeba521 100644 --- a/native/jni/magiskboot/main.c +++ b/native/jni/magiskboot/main.c @@ -136,9 +136,9 @@ int main(int argc, char *argv[]) { munmap(buf, size); } else if (argc > 2 && strcmp(argv[1], "--parse") == 0) { boot_img boot; - exit(parse_img(argv[2], &boot)); + return parse_img(argv[2], &boot); } else if (argc > 2 && strcmp(argv[1], "--unpack") == 0) { - unpack(argv[2]); + return unpack(argv[2]); } else if (argc > 2 && strcmp(argv[1], "--repack") == 0) { repack(argv[2], argc > 3 ? argv[3] : NEW_BOOT); } else if (argc > 2 && strcmp(argv[1], "--decompress") == 0) { @@ -157,7 +157,8 @@ int main(int argc, char *argv[]) { char *cmd = argv[1] + 5; if (*cmd == '\0') usage(argv[0]); else ++cmd; - if (dtb_commands(cmd, argc - 2, argv + 2)) usage(argv[0]); + if (dtb_commands(cmd, argc - 2, argv + 2)) + usage(argv[0]); } else { usage(argv[0]); } diff --git a/native/jni/magiskboot/types.c b/native/jni/magiskboot/types.c index 4833b0b3e..87e33865e 100644 --- a/native/jni/magiskboot/types.c +++ b/native/jni/magiskboot/types.c @@ -6,7 +6,7 @@ file_t check_type(const void *buf) { if (memcmp(buf, CHROMEOS_MAGIC, 8) == 0) { return CHROMEOS; - } else if (memcmp(buf, BOOT_MAGIC, BOOT_MAGIC_SIZE) == 0) { + } else if (memcmp(buf, BOOT_MAGIC, 8) == 0) { return AOSP; } else if (memcmp(buf, ELF32_MAGIC, 5) == 0) { return ELF32;