Skip to content

Commit bf469ed

Browse files
authored
Fix aarch64-linker, take 2 (#1791)
This one moves most of the allocation logic into the m32 allocator, while also completely ignoring the lower requirement. This of course is not ideal, however we've been mapping pages at the oder of 100x (4096 vs 40) the required space, and thus often ran out of memory due to sections per function. This is now much improved. It also revealed at least one out-of-bounds memory write issue.
1 parent 7f8ccbd commit bf469ed

File tree

3 files changed

+447
-12
lines changed

3 files changed

+447
-12
lines changed

overlays/bootstrap.nix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ in {
220220

221221
# the following is a partial reversal of https://gitlab.haskell.org/ghc/ghc/-/merge_requests/4391, to address haskell.nix#1227
222222
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.targetPlatform.isAarch64) ./patches/ghc/mmap-next.patch
223+
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.targetPlatform.isAarch64) ./patches/ghc/m32_alloc.patch
223224
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.targetPlatform.isAndroid) ./patches/ghc/rts-android-jemalloc-qemu.patch
224225
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.targetPlatform.isAndroid) ./patches/ghc/stack-protector-symbols.patch
225226
++ final.lib.optional (versionAtLeast "8.10" && versionLessThan "9.0" && final.targetPlatform.isAndroid) ./patches/ghc/libraries-prim-os-android.patch

overlays/patches/ghc/m32_alloc.patch

Lines changed: 223 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,223 @@
1+
diff --git a/rts/Linker.c b/rts/Linker.c
2+
index aaca823..f476702 100644
3+
--- a/rts/Linker.c
4+
+++ b/rts/Linker.c
5+
@@ -1037,6 +1037,12 @@ typedef struct _info {
6+
7+
static info *infos = NULL;
8+
9+
+info *mkInfo(void *addr, size_t length);
10+
+info *lookupInfo(void *addr, size_t length);
11+
+info *lookupOrCreateInfo(void *addr, size_t length);
12+
+void printInfo(info *cur);
13+
+void printInfos(void);
14+
+
15+
info *mkInfo(void *addr, size_t length) {
16+
info *i = NULL;
17+
i = (info *)calloc(sizeof(info), 1);
18+
@@ -1083,7 +1089,7 @@ info *lookupOrCreateInfo(void *addr, size_t length) {
19+
void printInfo(info *cur) {
20+
printf("%p %8zu %p; n = %zu; total = %zu\n", cur->addr, cur->length, cur->next_addr, cur->count, cur->total_length);
21+
}
22+
-void printInfos() {
23+
+void printInfos(void) {
24+
printf("Infos:\n");
25+
for (info *cur = infos; cur != NULL; cur = cur->next) {
26+
printInfo(cur);
27+
diff --git a/rts/linker/Elf.c b/rts/linker/Elf.c
28+
index 0bbbbf2..85054ea 100644
29+
--- a/rts/linker/Elf.c
30+
+++ b/rts/linker/Elf.c
31+
@@ -739,7 +739,6 @@ ocGetNames_ELF ( ObjectCode* oc )
32+
oc->sections[i].info->stubs = NULL;
33+
} else if (kind != SECTIONKIND_OTHER && size > 0) {
34+
35+
-#if defined(NEED_PLT)
36+
/* To support stubs next to sections, we will use the following
37+
* layout:
38+
*
39+
@@ -758,26 +757,7 @@ ocGetNames_ELF ( ObjectCode* oc )
40+
unsigned nstubs = numberOfStubsForSection(oc, i);
41+
unsigned stub_space = STUB_SIZE * nstubs;
42+
43+
- void * mem = mmapAnonForLinker(size+stub_space, true, "anon:stub_space");
44+
-
45+
- if( mem == NULL ) {
46+
- barf("failed to mmap allocated memory to load section %d. "
47+
- "errno = %d", i, errno);
48+
- }
49+
-
50+
- /* copy only the image part over; we don't want to copy data
51+
- * into the stub part.
52+
- */
53+
- memcpy( mem, oc->image + offset, size );
54+
-
55+
- alloc = SECTION_MMAP;
56+
-
57+
- mapped_offset = 0;
58+
- mapped_size = roundUpToPage(size+stub_space);
59+
- start = mem;
60+
- mapped_start = mem;
61+
-#else
62+
- if (USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
63+
+ if (false) { //USE_CONTIGUOUS_MMAP || RtsFlags.MiscFlags.linkerAlwaysPic) {
64+
// already mapped.
65+
start = oc->image + offset;
66+
alloc = SECTION_NOMEM;
67+
@@ -793,32 +773,46 @@ ocGetNames_ELF ( ObjectCode* oc )
68+
// RODATA sections. Specifically .rodata.cst16. However we don't
69+
// handle the cst part in any way what so ever, so 16 seems
70+
// better than 8.
71+
- start = m32_alloc(allocator, size, 16);
72+
+ start = m32_alloc(allocator, size+stub_space, 16);
73+
if (start == NULL) goto fail;
74+
memcpy(start, oc->image + offset, size);
75+
alloc = SECTION_M32;
76+
} else {
77+
- start = mapObjectFileSection(fd, offset, size,
78+
+#if defined(NEED_PLT)
79+
+ char buf[512];
80+
+ sprintf(buf, "anon:%s, sec %d, kind %d, size %ld, stub %d, total %ld", oc->fileName, i, kind, size, stub_space, size + stub_space);
81+
+
82+
+ start = mmapAnonForLinker(size+stub_space, true, buf);
83+
+
84+
+ if( start == NULL ) {
85+
+ barf("failed to mmap allocated memory to load section %d. "
86+
+ "errno = %d", i, errno);
87+
+ }
88+
+
89+
+ /* copy only the image part over; we don't want to copy data
90+
+ * into the stub part.
91+
+ */
92+
+ memcpy( start, oc->image + offset, size );
93+
+
94+
+ mapped_offset = 0;
95+
+ mapped_size = roundUpToPage(size+stub_space);
96+
+ mapped_start = start;
97+
+
98+
+#else
99+
+ start = mapObjectFileSection(fd, offset, size+stub_space,
100+
&mapped_start, &mapped_size,
101+
&mapped_offset);
102+
if (start == NULL) goto fail;
103+
+#endif
104+
alloc = SECTION_MMAP;
105+
}
106+
-#endif
107+
addSection(&sections[i], kind, alloc, start, size,
108+
mapped_offset, mapped_start, mapped_size);
109+
110+
-#if defined(NEED_PLT)
111+
oc->sections[i].info->nstubs = 0;
112+
- oc->sections[i].info->stub_offset = (uint8_t*)mem + size;
113+
+ oc->sections[i].info->stub_offset = (uint8_t*)start + size;
114+
oc->sections[i].info->stub_size = stub_space;
115+
oc->sections[i].info->stubs = NULL;
116+
-#else
117+
- oc->sections[i].info->nstubs = 0;
118+
- oc->sections[i].info->stub_offset = NULL;
119+
- oc->sections[i].info->stub_size = 0;
120+
- oc->sections[i].info->stubs = NULL;
121+
-#endif
122+
123+
addProddableBlock(oc, start, size);
124+
} else {
125+
diff --git a/rts/linker/M32Alloc.c b/rts/linker/M32Alloc.c
126+
index 089fbeb..8d80b02 100644
127+
--- a/rts/linker/M32Alloc.c
128+
+++ b/rts/linker/M32Alloc.c
129+
@@ -264,10 +264,10 @@ m32_alloc_page(void)
130+
*/
131+
const size_t pgsz = getPageSize();
132+
const size_t map_sz = pgsz * M32_MAP_PAGES;
133+
- uint8_t *chunk = mmapAnonForLinker(map_sz, false, "anon:m32_alloc_page");
134+
- if (chunk + map_sz > (uint8_t *) 0xffffffff) {
135+
- barf("m32_alloc_page: failed to get allocation in lower 32-bits");
136+
- }
137+
+ uint8_t *chunk = mmapAnonForLinker(map_sz, true, "anon:m32_alloc_page");
138+
+ // if (chunk + map_sz > (uint8_t *) 0xffffffff) {
139+
+ // barf("m32_alloc_page: failed to get allocation in lower 32-bits");
140+
+ // }
141+
142+
#define GET_PAGE(i) ((struct m32_page_t *) (chunk + (i) * pgsz))
143+
for (int i=0; i < M32_MAP_PAGES; i++) {
144+
@@ -467,6 +467,18 @@ m32_alloc(struct m32_allocator_t *alloc, size_t size, size_t alignment)
145+
size+ROUND_UP(sizeof(struct m32_page_t),alignment);
146+
return (char*)page + ROUND_UP(sizeof(struct m32_page_t),alignment);
147+
}
148+
+void
149+
+m32_list(m32_allocator *alloc) {
150+
+ for(struct m32_page_t *page = alloc->unprotected_list; page != NULL; page = m32_filled_page_get_next(page)) {
151+
+ printf("%p (%d) %0x %0x %0x %0x\n", page, page->filled_page.size,
152+
+ ((uint32_t*)page)[0],
153+
+ ((uint32_t*)page)[1],
154+
+ ((uint32_t*)page)[2],
155+
+ ((uint32_t*)page)[3]
156+
+ );
157+
+ }
158+
+}
159+
+
160+
161+
#else
162+
163+
@@ -499,4 +511,9 @@ m32_alloc(m32_allocator *alloc STG_UNUSED,
164+
barf("%s: RTS_LINKER_USE_MMAP is %d", __func__, RTS_LINKER_USE_MMAP);
165+
}
166+
167+
+void
168+
+m32_list(m32_allocator *alloc STG_UNUSED) {
169+
+ barf("%s: RTS_LINKER_USE_MMAP is %d", __func__, RTS_LINKER_USE_MMAP);
170+
+}
171+
+
172+
#endif
173+
diff --git a/rts/linker/M32Alloc.h b/rts/linker/M32Alloc.h
174+
index 8a349a3..ab116eb 100644
175+
--- a/rts/linker/M32Alloc.h
176+
+++ b/rts/linker/M32Alloc.h
177+
@@ -35,4 +35,6 @@ void m32_allocator_flush(m32_allocator *alloc) M32_NO_RETURN;
178+
179+
void * m32_alloc(m32_allocator *alloc, size_t size, size_t alignment) M32_NO_RETURN;
180+
181+
+void m32_list(m32_allocator *alloc);
182+
+
183+
#include "EndPrivate.h"
184+
diff --git a/rts/linker/elf_got.c b/rts/linker/elf_got.c
185+
index b55a443..c30ebef 100644
186+
--- a/rts/linker/elf_got.c
187+
+++ b/rts/linker/elf_got.c
188+
@@ -110,8 +110,18 @@ fillGot(ObjectCode * oc) {
189+
190+
if(0x0 == symbol->addr) {
191+
errorBelch(
192+
- "Something went wrong! Symbol %s has null address.\n",
193+
- symbol->name);
194+
+ "In oc: %s\n"
195+
+ "in symbtab: %d (%ld symbols total)\n"
196+
+ "Something went wrong! Symbol %ld: %s has null address.\n"
197+
+ "type: %d, bind: %d\n",
198+
+
199+
+ oc->archiveMemberName ? oc->archiveMemberName : oc->fileName,
200+
+ symTab->index, symTab->n_symbols,
201+
+ i,
202+
+ symbol->name,
203+
+ ELF_ST_TYPE(symbol->elf_sym->st_info),
204+
+ ELF_ST_BIND(symbol->elf_sym->st_info)
205+
+ );
206+
return EXIT_FAILURE;
207+
}
208+
209+
diff --git a/rts/linker/elf_plt.c b/rts/linker/elf_plt.c
210+
index 9cd42ef..913d788 100644
211+
--- a/rts/linker/elf_plt.c
212+
+++ b/rts/linker/elf_plt.c
213+
@@ -56,8 +56,9 @@ makeStub(Section * section,
214+
s->target = *addr;
215+
s->flags = flags;
216+
s->next = NULL;
217+
- s->addr = (uint8_t *)section->info->stub_offset + 8
218+
+ s->addr = (uint8_t *)section->info->stub_offset
219+
+ STUB_SIZE * section->info->nstubs;
220+
+ ASSERT(s->addr >= section->info->stub_offset && s->addr <= (void*)((uintptr_t)section->info->stub_offset + section->info->stub_size - STUB_SIZE));
221+
222+
if((*_makeStub)(s))
223+
return EXIT_FAILURE;

0 commit comments

Comments
 (0)