arm64: fix non-converging vmlinux link
PATCH 1/1 arm64: fix non-converging vmlinux link
From: Ard Biesheuvel <[email protected]>
When the size of the vmlinux file is just below 64MB, the kernel may fail to link with lld, producing output such as
ld.lld: error: assignment to symbol init_pg_end does not converge ld.lld: error: assignment to symbol __pecoff_data_size does not converge
Change the INIT_DIR_SIZE definition to include init_pg_dir to get a stable size calculation.
Arnd did the original report and analysis, but Ard figured what to do about and wrote the changes to the code.
---
Ard, I had this in my randconfig tree with comment "Ard will submit this with a proper changelog", but it seems we both forgot about it, or maybe there was something wrong with it in the end.
While looking for randconfig -Werror warnings in mainline I came across it again and can confirm that this patch (or something like it) is still needed. Let me know if you are happy with this version or if you have a better description for it. I unfortunately forgot the details of how this works.
--- arch/arm64/include/asm/kernel-pgtable.h | 2 +- arch/arm64/kernel/head.S | 5 ++--- arch/arm64/kernel/vmlinux.lds.S | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-)
arch/arm64/include/asm/kernel-pgtable.h +1 -1
@@ -86,7 +86,7 @@ + EARLY_PGDS((vstart), (vend)) /* each PGDIR needs a next level page table */ \ + EARLY_PUDS((vstart), (vend)) /* each PUD needs a next level page table */ \ + EARLY_PMDS((vstart), (vend))) /* each PMD needs a next level page table */ -#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end)) +#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, init_pg_dir))#define IDMAP_DIR_SIZE (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)/* Initial memory map size */
arch/arm64/kernel/head.S +2 -3
@@ -366,10 +366,9 @@ SYM_FUNC_START_LOCAL(__create_page_tables) mov_q x5, KIMAGE_VADDR // compile time __va(_text) add x5, x5, x23 // add KASLR displacement mov x4, PTRS_PER_PGD - adrp x6, _end // runtime __pa(_end) adrp x3, _text // runtime __pa(_text) - sub x6, x6, x3 // _end - _text - add x6, x6, x5 // runtime __va(_end) + sub x6, x0, x3 // init_pg_dir - _text + add x6, x6, x5 // runtime __va(init_pg_dir) map_memory x0, x1, x5, x6, x7, x3, x4, x10, x11, x12, x13, x14
arch/arm64/kernel/vmlinux.lds.S +3 -0
@@ -287,6 +287,9 @@ SECTIONS BSS_SECTION(SBSS_ALIGN, 0, 0) . = ALIGN(PAGE_SIZE); + + /* ----- kernel virtual mapping ends here ---- */ + init_pg_dir = .; . += INIT_DIR_SIZE; init_pg_end = .;
Signature · 1 line
2.29.2
Mark Rutland
reviewerHi Arnd, Ard,
Quoted 9 lines · Arnd Bergmann
From: Ard Biesheuvel <[email protected]>
When the size of the vmlinux file is just below 64MB, the kernel may fail to link with lld, producing output such as
ld.lld: error: assignment to symbol
init_pg_enddoes not converge ld.lld: error: assignment to symbol__pecoff_data_sizedoes not convergeChange the
INIT_DIR_SIZEdefinition to includeinit_pg_dir
^
Missing "not" here ---------------------'
We *need* to access init_pg_dir while using init_pg_dir, since e.g. early_fixmap_init() needs to conntect the fixmap tables into it, so we *must* map at least a portion of init_pg_dir.
We happen to over-map when using 4K pages, and so depending on the alignment and size of the kernel Image this can work by chance. Also, prior to v5.15-rc1, we'd over-map in all configurations, and this could happen to work, but that was fixed in commit:
90268574a3e8a6b8 ("arm64: head: avoid over-mapping in map_memory")
So as-is, this patch regresses working configurations at runtime, including all 16K and 64K configs.
Is there some way we can over-estimate the size such that this will converge? e.g. add some alignment padding such that _end won't oscillate as init_pg_end changes?
Thanks,
Mark.
Quoted 72 lines
to get a stable size calculation.
Arnd did the original report and analysis, but Ard figured what to do about and wrote the changes to the code.
Co-developed-by Ard Biesheuvel <[email protected]>Signed-off-by Arnd Bergmann <[email protected]>---
Ard, I had this in my randconfig tree with comment "Ard will submit this with a proper changelog", but it seems we both forgot about it, or maybe there was something wrong with it in the end.While looking for randconfig -Werror warnings in mainline I came across it again and can confirm that this patch (or something like it) is still needed. Let me know if you are happy with this version or if you have a better description for it. I unfortunately forgot the details of how this works.
--- arch/arm64/include/asm/kernel-pgtable.h | 2 +- arch/arm64/kernel/head.S | 5 ++--- arch/arm64/kernel/vmlinux.lds.S | 3 +++ 3 files changed, 6 insertions(+), 4 deletions(-)arch/arm64/include/asm/kernel-pgtable.h +1
-1@@ -86,7 +86,7 @@ + EARLY_PGDS((vstart), (vend)) /* each PGDIR needs a next level page table */ \ + EARLY_PUDS((vstart), (vend)) /* each PUD needs a next level page table */ \ + EARLY_PMDS((vstart), (vend))) /* each PMD needs a next level page table */ -#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, _end)) +#define INIT_DIR_SIZE (PAGE_SIZE * EARLY_PAGES(KIMAGE_VADDR, init_pg_dir))#define IDMAP_DIR_SIZE (IDMAP_PGTABLE_LEVELS * PAGE_SIZE)/* Initial memory map size */ arch/arm64/kernel/head.S +2
-3@@ -366,10 +366,9 @@ SYM_FUNC_START_LOCAL(__create_page_tables) mov_q x5, KIMAGE_VADDR // compile time __va(_text) add x5, x5, x23 // add KASLR displacement mov x4, PTRS_PER_PGD - adrp x6, _end // runtime __pa(_end) adrp x3, _text // runtime __pa(_text) - sub x6, x6, x3 // _end - _text - add x6, x6, x5 // runtime __va(_end) + sub x6, x0, x3 // init_pg_dir - _text + add x6, x6, x5 // runtime __va(init_pg_dir) map_memory x0, x1, x5, x6, x7, x3, x4, x10, x11, x12, x13, x14arch/arm64/kernel/vmlinux.lds.S +3
-0@@ -287,6 +287,9 @@ SECTIONS BSS_SECTION(SBSS_ALIGN, 0, 0) . = ALIGN(PAGE_SIZE); + + /* ----- kernel virtual mapping ends here ---- */ + init_pg_dir = .; . += INIT_DIR_SIZE; init_pg_end = .;Signature · 1 line
2.29.2