summaryrefslogtreecommitdiff
path: root/sys/lib/libsa
diff options
context:
space:
mode:
authormaxv <maxv@NetBSD.org>2017-10-18 16:29:56 +0000
committermaxv <maxv@NetBSD.org>2017-10-18 16:29:56 +0000
commitb42f485c60c4ac8ca522faad805e9b216cab5bc2 (patch)
tree48b17718fb00c451fb460f8106b72eb179bbaca3 /sys/lib/libsa
parentc9714648d090669299d03ae66f5ba0f32dd2ff15 (diff)
Group the sections into segments, and align to KERNALIGN only between
segments. Prerequisite for other changes. Unfortunately the code is not very compact, but whatever.
Diffstat (limited to 'sys/lib/libsa')
-rw-r--r--sys/lib/libsa/loadfile_elf32.c104
1 files changed, 97 insertions, 7 deletions
diff --git a/sys/lib/libsa/loadfile_elf32.c b/sys/lib/libsa/loadfile_elf32.c
index 0fb648cd880..c96f391da4a 100644
--- a/sys/lib/libsa/loadfile_elf32.c
+++ b/sys/lib/libsa/loadfile_elf32.c
@@ -1,4 +1,4 @@
-/* $NetBSD: loadfile_elf32.c,v 1.47 2017/10/13 10:39:26 maxv Exp $ */
+/* $NetBSD: loadfile_elf32.c,v 1.48 2017/10/18 16:29:56 maxv Exp $ */
/*
* Copyright (c) 1997, 2008, 2017 The NetBSD Foundation, Inc.
@@ -341,7 +341,7 @@ ELFNAMEEND(loadfile_dynamic)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
{
const u_long offset = 0;
Elf_Shdr *shdr;
- Elf_Addr shpp, addr;
+ Elf_Addr shpp, addr, align;
int i, j, loaded;
size_t size, shdrsz;
Elf_Addr maxp, elfp = 0;
@@ -383,11 +383,22 @@ ELFNAMEEND(loadfile_dynamic)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
maxp += roundup(shdrsz, ELFROUND);
/*
- * Load the KERNEL SECTIONS.
+ * Load the KERNEL SECTIONS, and group them into segments. First text,
+ * then rodata, then data. Between sections, we align to the requested
+ * section alignment. Between segments, we align to KERNALIGN.
*/
+
+ /* text */
maxp = roundup(maxp, KERNALIGN);
for (i = 0; i < elf->e_shnum; i++) {
- addr = maxp;
+ if (!(shdr[i].sh_flags & SHF_EXECINSTR)) {
+ continue;
+ }
+ align = shdr[i].sh_addralign;
+ if (align == 0) {
+ align = ELFROUND;
+ }
+ addr = roundup(maxp, align);
size = (size_t)shdr[i].sh_size;
loaded = 0;
@@ -411,15 +422,94 @@ ELFNAMEEND(loadfile_dynamic)(int fd, Elf_Ehdr *elf, u_long *marks, int flags)
}
if (loaded) {
- shdr[i].sh_offset = maxp - elfp;
- maxp = roundup(maxp + size, KERNALIGN);
+ shdr[i].sh_offset = addr - elfp;
+ maxp = addr + size;
+ }
+ }
+
+ /* rodata */
+ maxp = roundup(maxp, KERNALIGN);
+ for (i = 0; i < elf->e_shnum; i++) {
+ if ((shdr[i].sh_flags & (SHF_EXECINSTR|SHF_WRITE))) {
+ continue;
+ }
+ align = shdr[i].sh_addralign;
+ if (align == 0) {
+ align = ELFROUND;
+ }
+ addr = roundup(maxp, align);
+ size = (size_t)shdr[i].sh_size;
+
+ loaded = 0;
+ switch (shdr[i].sh_type) {
+ case SHT_NOBITS:
+ /* Zero out bss. */
+ BZERO(addr, size);
+ loaded = 1;
+ break;
+ case SHT_PROGBITS:
+ ret = ELFNAMEEND(readfile_global)(fd, offset,
+ shdr[i].sh_offset, addr, size);
+ if (ret == -1) {
+ goto out;
+ }
+ loaded = 1;
+ break;
+ default:
+ loaded = 0;
+ break;
+ }
+
+ if (loaded) {
+ shdr[i].sh_offset = addr - elfp;
+ maxp = addr + size;
+ }
+ }
+
+ /* data */
+ maxp = roundup(maxp, KERNALIGN);
+ for (i = 0; i < elf->e_shnum; i++) {
+ if (!(shdr[i].sh_flags & SHF_WRITE) ||
+ (shdr[i].sh_flags & SHF_EXECINSTR)) {
+ continue;
+ }
+ align = shdr[i].sh_addralign;
+ if (align == 0) {
+ align = ELFROUND;
+ }
+ addr = roundup(maxp, align);
+ size = (size_t)shdr[i].sh_size;
+
+ loaded = 0;
+ switch (shdr[i].sh_type) {
+ case SHT_NOBITS:
+ /* Zero out bss. */
+ BZERO(addr, size);
+ loaded = 1;
+ break;
+ case SHT_PROGBITS:
+ ret = ELFNAMEEND(readfile_global)(fd, offset,
+ shdr[i].sh_offset, addr, size);
+ if (ret == -1) {
+ goto out;
+ }
+ loaded = 1;
+ break;
+ default:
+ loaded = 0;
+ break;
+ }
+
+ if (loaded) {
+ shdr[i].sh_offset = addr - elfp;
+ maxp = addr + size;
}
}
/*
* Load the SYM+REL SECTIONS.
*/
- maxp = roundup(maxp, ELFROUND);
+ maxp = roundup(maxp, KERNALIGN);
for (i = 0; i < elf->e_shnum; i++) {
addr = maxp;
size = (size_t)shdr[i].sh_size;