mirror of
https://github.com/switchbrew/switch-tools.git
synced 2025-08-10 18:39:23 +02:00
elf2nro, elf2nso: Add ARM support (32-bit)
This commit is contained in:
parent
8243e86c15
commit
fb3204d69c
125
src/elf2nro.c
125
src/elf2nro.c
@ -119,20 +119,43 @@ int main(int argc, char* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Ehdr* hdr = (Elf64_Ehdr*) elf;
|
||||
if (hdr->e_machine != EM_AARCH64) {
|
||||
fprintf(stderr, "Invalid ELF: expected AArch64!\n");
|
||||
Elf64_Ehdr* hdr64 = (Elf64_Ehdr*) elf;
|
||||
Elf32_Ehdr* hdr32 = (Elf32_Ehdr*) elf;
|
||||
Elf64_Half e_phnum, e_shnum;
|
||||
Elf64_Off e_phoff, e_shoff;
|
||||
Elf64_Half e_shentsize;
|
||||
int elf64;
|
||||
if (hdr64->e_machine == EM_AARCH64) {
|
||||
elf64 = 1;
|
||||
e_phnum = hdr64->e_phnum;
|
||||
e_shnum = hdr64->e_shnum;
|
||||
e_phoff = hdr64->e_phoff;
|
||||
e_shoff = hdr64->e_shoff;
|
||||
e_shentsize = hdr64->e_shentsize;
|
||||
} else if (hdr64->e_machine == EM_ARM) {
|
||||
elf64 = 0;
|
||||
e_phnum = hdr32->e_phnum;
|
||||
e_shnum = hdr32->e_shnum;
|
||||
e_phoff = hdr32->e_phoff;
|
||||
e_shoff = hdr32->e_shoff;
|
||||
e_shentsize = hdr32->e_shentsize;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid ELF: expected AArch64 or ARM!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Off ph_end = hdr->e_phoff + hdr->e_phnum * sizeof(Elf64_Phdr);
|
||||
Elf64_Off ph_end;
|
||||
if (elf64)
|
||||
ph_end = e_phoff + e_phnum * sizeof(Elf64_Phdr);
|
||||
else
|
||||
ph_end = e_phoff + e_phnum * sizeof(Elf32_Phdr);
|
||||
|
||||
if (ph_end < hdr->e_phoff || ph_end > elf_len) {
|
||||
if (ph_end < e_phoff || ph_end > elf_len) {
|
||||
fprintf(stderr, "Invalid ELF: phdrs outside file!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Phdr* phdrs = (Elf64_Phdr*) &elf[hdr->e_phoff];
|
||||
void *phdrs = &elf[e_phoff];
|
||||
size_t i, j = 0;
|
||||
size_t file_off = 0;
|
||||
size_t tmpsize;
|
||||
@ -140,11 +163,19 @@ int main(int argc, char* argv[]) {
|
||||
uint8_t* buf[3];
|
||||
|
||||
for (i=0; i<4; i++) {
|
||||
Elf64_Phdr* phdr = NULL;
|
||||
while (j < hdr->e_phnum) {
|
||||
Elf64_Phdr* cur = &phdrs[j];
|
||||
if (i < 2 || (i==2 && cur->p_type != PT_LOAD)) j++;
|
||||
if (cur->p_type == PT_LOAD || i == 3) {
|
||||
void* phdr = NULL;
|
||||
while (j < e_phnum) {
|
||||
void *cur;
|
||||
Elf64_Word p_type;
|
||||
if (elf64) {
|
||||
cur = &((Elf64_Phdr*)phdrs)[j];
|
||||
p_type = ((Elf64_Phdr*)cur)->p_type;
|
||||
} else {
|
||||
cur = &((Elf32_Phdr*)phdrs)[j];
|
||||
p_type = ((Elf32_Phdr*)cur)->p_type;
|
||||
}
|
||||
if (i < 2 || (i==2 && p_type != PT_LOAD)) j++;
|
||||
if (p_type == PT_LOAD || i == 3) {
|
||||
phdr = cur;
|
||||
break;
|
||||
}
|
||||
@ -155,18 +186,33 @@ int main(int argc, char* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Addr p_vaddr;
|
||||
Elf64_Xword p_filesz, p_memsz;
|
||||
Elf64_Off p_offset;
|
||||
if (elf64) {
|
||||
p_vaddr = ((Elf64_Phdr*)phdr)->p_vaddr;
|
||||
p_filesz = ((Elf64_Phdr*)phdr)->p_filesz;
|
||||
p_memsz = ((Elf64_Phdr*)phdr)->p_memsz;
|
||||
p_offset = ((Elf64_Phdr*)phdr)->p_offset;
|
||||
} else {
|
||||
p_vaddr = ((Elf32_Phdr*)phdr)->p_vaddr;
|
||||
p_filesz = ((Elf32_Phdr*)phdr)->p_filesz;
|
||||
p_memsz = ((Elf32_Phdr*)phdr)->p_memsz;
|
||||
p_offset = ((Elf32_Phdr*)phdr)->p_offset;
|
||||
}
|
||||
|
||||
// .bss is special
|
||||
if (i == 3) {
|
||||
tmpsize = (phdr->p_filesz + 0xFFF) & ~0xFFF;
|
||||
if ( phdr->p_memsz > tmpsize)
|
||||
nro_hdr.bssSize = ((phdr->p_memsz - tmpsize) + 0xFFF) & ~0xFFF;
|
||||
tmpsize = (p_filesz + 0xFFF) & ~0xFFF;
|
||||
if (p_memsz > tmpsize)
|
||||
nro_hdr.bssSize = ((p_memsz - tmpsize) + 0xFFF) & ~0xFFF;
|
||||
else
|
||||
nro_hdr.bssSize = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
nro_hdr.Segments[i].FileOff = phdr->p_vaddr;
|
||||
nro_hdr.Segments[i].Size = (phdr->p_filesz + 0xFFF) & ~0xFFF;
|
||||
nro_hdr.Segments[i].FileOff = p_vaddr;
|
||||
nro_hdr.Segments[i].Size = (p_filesz + 0xFFF) & ~0xFFF;
|
||||
buf[i] = malloc(nro_hdr.Segments[i].Size);
|
||||
memset(buf[i], 0, nro_hdr.Segments[i].Size);
|
||||
|
||||
@ -175,29 +221,54 @@ int main(int argc, char* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
memcpy(buf[i], &elf[phdr->p_offset], phdr->p_filesz);
|
||||
memcpy(buf[i], &elf[p_offset], p_filesz);
|
||||
|
||||
file_off += nro_hdr.Segments[i].Size;
|
||||
file_off = (file_off + 0xFFF) & ~0xFFF;
|
||||
}
|
||||
|
||||
/* Iterate over sections to find build id. */
|
||||
size_t cur_sect_hdr_ofs = hdr->e_shoff;
|
||||
for (unsigned int i = 0; i < hdr->e_shnum; i++) {
|
||||
Elf64_Shdr *cur_shdr = (Elf64_Shdr *)(elf + cur_sect_hdr_ofs);
|
||||
if (cur_shdr->sh_type == SHT_NOTE) {
|
||||
Elf64_Nhdr *note_hdr = (Elf64_Nhdr *)(elf + cur_shdr->sh_offset);
|
||||
u8 *note_name = (u8 *)((uintptr_t)note_hdr + sizeof(Elf64_Nhdr));
|
||||
u8 *note_desc = note_name + note_hdr->n_namesz;
|
||||
if (note_hdr->n_type == NT_GNU_BUILD_ID && note_hdr->n_namesz == 4 && memcmp(note_name, "GNU\x00", 4) == 0) {
|
||||
size_t build_id_size = note_hdr->n_descsz;
|
||||
Elf64_Off cur_sect_hdr_ofs = e_shoff;
|
||||
for (unsigned int i = 0; i < e_shnum; i++) {
|
||||
Elf64_Word sh_type;
|
||||
Elf64_Off sh_offset;
|
||||
void *cur_shdr = elf + cur_sect_hdr_ofs;
|
||||
if (elf64) {
|
||||
sh_type = ((Elf64_Shdr *)cur_shdr)->sh_type;
|
||||
sh_offset = ((Elf64_Shdr *)cur_shdr)->sh_offset;
|
||||
} else {
|
||||
sh_type = ((Elf32_Shdr *)cur_shdr)->sh_type;
|
||||
sh_offset = ((Elf32_Shdr *)cur_shdr)->sh_offset;
|
||||
}
|
||||
|
||||
if (sh_type == SHT_NOTE) {
|
||||
Elf64_Word n_namesz;
|
||||
Elf64_Word n_descsz;
|
||||
Elf64_Word n_type;
|
||||
u8 *note_name;
|
||||
void *note_hdr = elf + sh_offset;
|
||||
if (elf64) {
|
||||
n_namesz = ((Elf64_Nhdr *)note_hdr)->n_namesz;
|
||||
n_descsz = ((Elf64_Nhdr *)note_hdr)->n_descsz;
|
||||
n_type = ((Elf64_Nhdr *)note_hdr)->n_type;
|
||||
note_name = (u8 *)note_hdr + sizeof(Elf64_Nhdr);
|
||||
} else {
|
||||
n_namesz = ((Elf32_Nhdr *)note_hdr)->n_namesz;
|
||||
n_descsz = ((Elf32_Nhdr *)note_hdr)->n_descsz;
|
||||
n_type = ((Elf32_Nhdr *)note_hdr)->n_type;
|
||||
note_name = (u8 *)note_hdr + sizeof(Elf32_Nhdr);
|
||||
}
|
||||
|
||||
u8 *note_desc = note_name + n_namesz;
|
||||
if (n_type == NT_GNU_BUILD_ID && n_namesz == 4 && memcmp(note_name, "GNU\x00", 4) == 0) {
|
||||
size_t build_id_size = n_descsz;
|
||||
if (build_id_size > 0x20) {
|
||||
build_id_size = 0x20;
|
||||
}
|
||||
memcpy(nro_hdr.BuildId, note_desc, build_id_size);
|
||||
}
|
||||
}
|
||||
cur_sect_hdr_ofs += hdr->e_shentsize;
|
||||
cur_sect_hdr_ofs += e_shentsize;
|
||||
}
|
||||
|
||||
FILE* out = fopen(argv[2], "wb");
|
||||
|
124
src/elf2nso.c
124
src/elf2nso.c
@ -88,20 +88,44 @@ int main(int argc, char* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Ehdr* hdr = (Elf64_Ehdr*) elf;
|
||||
if (hdr->e_machine != EM_AARCH64) {
|
||||
fprintf(stderr, "Invalid ELF: expected AArch64!\n");
|
||||
Elf64_Ehdr* hdr64 = (Elf64_Ehdr*) elf;
|
||||
Elf32_Ehdr* hdr32 = (Elf32_Ehdr*) elf;
|
||||
Elf64_Half e_phnum, e_shnum;
|
||||
Elf64_Off e_phoff, e_shoff;
|
||||
Elf64_Half e_shentsize;
|
||||
int elf64;
|
||||
if (hdr64->e_machine == EM_AARCH64) {
|
||||
elf64 = 1;
|
||||
e_phnum = hdr64->e_phnum;
|
||||
e_shnum = hdr64->e_shnum;
|
||||
e_phoff = hdr64->e_phoff;
|
||||
e_shoff = hdr64->e_shoff;
|
||||
e_shentsize = hdr64->e_shentsize;
|
||||
} else if (hdr64->e_machine == EM_ARM) {
|
||||
elf64 = 0;
|
||||
e_phnum = hdr32->e_phnum;
|
||||
e_shnum = hdr32->e_shnum;
|
||||
e_phoff = hdr32->e_phoff;
|
||||
e_shoff = hdr32->e_shoff;
|
||||
e_shentsize = hdr32->e_shentsize;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid ELF: expected AArch64 or ARM!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Off ph_end = hdr->e_phoff + hdr->e_phnum * sizeof(Elf64_Phdr);
|
||||
Elf64_Off ph_end;
|
||||
if (elf64)
|
||||
ph_end = e_phoff + e_phnum * sizeof(Elf64_Phdr);
|
||||
else
|
||||
ph_end = e_phoff + e_phnum * sizeof(Elf32_Phdr);
|
||||
|
||||
if (ph_end < hdr->e_phoff || ph_end > elf_len) {
|
||||
if (ph_end < e_phoff || ph_end > elf_len) {
|
||||
fprintf(stderr, "Invalid ELF: phdrs outside file!\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Phdr* phdrs = (Elf64_Phdr*) &elf[hdr->e_phoff];
|
||||
void *phdrs = &elf[e_phoff];
|
||||
|
||||
size_t i, j = 0;
|
||||
size_t file_off = sizeof(NsoHeader);
|
||||
|
||||
@ -109,10 +133,18 @@ int main(int argc, char* argv[]) {
|
||||
int comp_sz[3];
|
||||
|
||||
for (i=0; i<3; i++) {
|
||||
Elf64_Phdr* phdr = NULL;
|
||||
while (j < hdr->e_phnum) {
|
||||
Elf64_Phdr* cur = &phdrs[j++];
|
||||
if (cur->p_type == PT_LOAD) {
|
||||
void* phdr = NULL;
|
||||
while (j < e_phnum) {
|
||||
void *cur;
|
||||
Elf64_Word p_type;
|
||||
if (elf64) {
|
||||
cur = &((Elf64_Phdr*)phdrs)[j++];
|
||||
p_type = ((Elf64_Phdr*)cur)->p_type;
|
||||
} else {
|
||||
cur = &((Elf32_Phdr*)phdrs)[j++];
|
||||
p_type = ((Elf32_Phdr*)cur)->p_type;
|
||||
}
|
||||
if (p_type == PT_LOAD) {
|
||||
phdr = cur;
|
||||
break;
|
||||
}
|
||||
@ -123,22 +155,37 @@ int main(int argc, char* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
Elf64_Addr p_vaddr;
|
||||
Elf64_Xword p_filesz, p_memsz;
|
||||
Elf64_Off p_offset;
|
||||
if (elf64) {
|
||||
p_vaddr = ((Elf64_Phdr*)phdr)->p_vaddr;
|
||||
p_filesz = ((Elf64_Phdr*)phdr)->p_filesz;
|
||||
p_memsz = ((Elf64_Phdr*)phdr)->p_memsz;
|
||||
p_offset = ((Elf64_Phdr*)phdr)->p_offset;
|
||||
} else {
|
||||
p_vaddr = ((Elf32_Phdr*)phdr)->p_vaddr;
|
||||
p_filesz = ((Elf32_Phdr*)phdr)->p_filesz;
|
||||
p_memsz = ((Elf32_Phdr*)phdr)->p_memsz;
|
||||
p_offset = ((Elf32_Phdr*)phdr)->p_offset;
|
||||
}
|
||||
|
||||
nso_hdr.Segments[i].FileOff = file_off;
|
||||
nso_hdr.Segments[i].DstOff = phdr->p_vaddr;
|
||||
nso_hdr.Segments[i].DecompSz = phdr->p_filesz;
|
||||
nso_hdr.Segments[i].DstOff = p_vaddr;
|
||||
nso_hdr.Segments[i].DecompSz = p_filesz;
|
||||
|
||||
// for .data segment this field contains bss size
|
||||
if (i == 2)
|
||||
nso_hdr.Segments[i].AlignOrTotalSz = phdr->p_memsz - phdr->p_filesz;
|
||||
nso_hdr.Segments[i].AlignOrTotalSz = p_memsz - p_filesz;
|
||||
else
|
||||
nso_hdr.Segments[i].AlignOrTotalSz = 1;
|
||||
|
||||
SHA256_CTX ctx;
|
||||
sha256_init(&ctx);
|
||||
sha256_update(&ctx, &elf[phdr->p_offset], phdr->p_filesz);
|
||||
sha256_update(&ctx, &elf[p_offset], p_filesz);
|
||||
sha256_final(&ctx, (u8*) &nso_hdr.Hashes[i]);
|
||||
|
||||
size_t comp_max = LZ4_compressBound(phdr->p_filesz);
|
||||
size_t comp_max = LZ4_compressBound(p_filesz);
|
||||
comp_buf[i] = malloc(comp_max);
|
||||
|
||||
if (comp_buf[i] == NULL) {
|
||||
@ -147,7 +194,7 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
// TODO check p_offset
|
||||
comp_sz[i] = LZ4_compress_default(&elf[phdr->p_offset], comp_buf[i], phdr->p_filesz, comp_max);
|
||||
comp_sz[i] = LZ4_compress_default(&elf[p_offset], comp_buf[i], p_filesz, comp_max);
|
||||
|
||||
if (comp_sz[i] < 0) {
|
||||
fprintf(stderr, "Failed to compress!\n");
|
||||
@ -159,22 +206,47 @@ int main(int argc, char* argv[]) {
|
||||
}
|
||||
|
||||
/* Iterate over sections to find build id. */
|
||||
size_t cur_sect_hdr_ofs = hdr->e_shoff;
|
||||
for (unsigned int i = 0; i < hdr->e_shnum; i++) {
|
||||
Elf64_Shdr *cur_shdr = (Elf64_Shdr *)(elf + cur_sect_hdr_ofs);
|
||||
if (cur_shdr->sh_type == SHT_NOTE) {
|
||||
Elf64_Nhdr *note_hdr = (Elf64_Nhdr *)(elf + cur_shdr->sh_offset);
|
||||
u8 *note_name = (u8 *)((uintptr_t)note_hdr + sizeof(Elf64_Nhdr));
|
||||
u8 *note_desc = note_name + note_hdr->n_namesz;
|
||||
if (note_hdr->n_type == NT_GNU_BUILD_ID && note_hdr->n_namesz == 4 && memcmp(note_name, "GNU\x00", 4) == 0) {
|
||||
size_t build_id_size = note_hdr->n_descsz;
|
||||
Elf64_Off cur_sect_hdr_ofs = e_shoff;
|
||||
for (unsigned int i = 0; i < e_shnum; i++) {
|
||||
Elf64_Word sh_type;
|
||||
Elf64_Off sh_offset;
|
||||
void *cur_shdr = elf + cur_sect_hdr_ofs;
|
||||
if (elf64) {
|
||||
sh_type = ((Elf64_Shdr *)cur_shdr)->sh_type;
|
||||
sh_offset = ((Elf64_Shdr *)cur_shdr)->sh_offset;
|
||||
} else {
|
||||
sh_type = ((Elf32_Shdr *)cur_shdr)->sh_type;
|
||||
sh_offset = ((Elf32_Shdr *)cur_shdr)->sh_offset;
|
||||
}
|
||||
|
||||
if (sh_type == SHT_NOTE) {
|
||||
Elf64_Word n_namesz;
|
||||
Elf64_Word n_descsz;
|
||||
Elf64_Word n_type;
|
||||
u8 *note_name;
|
||||
void *note_hdr = elf + sh_offset;
|
||||
if (elf64) {
|
||||
n_namesz = ((Elf64_Nhdr *)note_hdr)->n_namesz;
|
||||
n_descsz = ((Elf64_Nhdr *)note_hdr)->n_descsz;
|
||||
n_type = ((Elf64_Nhdr *)note_hdr)->n_type;
|
||||
note_name = (u8 *)note_hdr + sizeof(Elf64_Nhdr);
|
||||
} else {
|
||||
n_namesz = ((Elf32_Nhdr *)note_hdr)->n_namesz;
|
||||
n_descsz = ((Elf32_Nhdr *)note_hdr)->n_descsz;
|
||||
n_type = ((Elf32_Nhdr *)note_hdr)->n_type;
|
||||
note_name = (u8 *)note_hdr + sizeof(Elf32_Nhdr);
|
||||
}
|
||||
|
||||
u8 *note_desc = note_name + n_namesz;
|
||||
if (n_type == NT_GNU_BUILD_ID && n_namesz == 4 && memcmp(note_name, "GNU\x00", 4) == 0) {
|
||||
size_t build_id_size = n_descsz;
|
||||
if (build_id_size > 0x20) {
|
||||
build_id_size = 0x20;
|
||||
}
|
||||
memcpy(nso_hdr.BuildId, note_desc, build_id_size);
|
||||
}
|
||||
}
|
||||
cur_sect_hdr_ofs += hdr->e_shentsize;
|
||||
cur_sect_hdr_ofs += e_shentsize;
|
||||
}
|
||||
|
||||
FILE* out = fopen(argv[2], "wb");
|
||||
|
Loading…
Reference in New Issue
Block a user