From 7f21c9550348d3a18682c64c9fa75df6c1d87beb Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:05:09 +1100 Subject: [PATCH 1/9] misc(Cargo.toml): bump `sc` Signed-off-by: Anhad Singh --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index d5d078172d..be96f42c01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,7 +59,7 @@ default-features = false features = ["c_api"] [target.'cfg(target_os = "linux")'.dependencies] -sc = "0.2.3" +sc = "0.2.7" [target.'cfg(target_os = "redox")'.dependencies] redox_syscall = "0.5.13" From 35a10eb940531b4057c61bd8feec156507c87fce Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:23:55 +1100 Subject: [PATCH 2/9] feat(ld_so): add linker script for aarch64-unknown-linux-gnu Signed-off-by: Anhad Singh --- ld_so/ld_script/aarch64-unknown-linux-gnu.ld | 253 +++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 ld_so/ld_script/aarch64-unknown-linux-gnu.ld diff --git a/ld_so/ld_script/aarch64-unknown-linux-gnu.ld b/ld_so/ld_script/aarch64-unknown-linux-gnu.ld new file mode 100644 index 0000000000..1df7e5c015 --- /dev/null +++ b/ld_so/ld_script/aarch64-unknown-linux-gnu.ld @@ -0,0 +1,253 @@ +/* Script for -z combreloc */ +/* Copyright (C) 2014-2025 Free Software Foundation, Inc. + Copying and distribution of this script, with or without modification, + are permitted in any medium without royalty provided the copyright + notice and this notice are preserved. */ +OUTPUT_FORMAT("elf64-littleaarch64", "elf64-bigaarch64", "elf64-littleaarch64") +OUTPUT_ARCH(aarch64) +ENTRY(_start) +SEARCH_DIR("=/usr/aarch64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/aarch64-linux-gnu/lib"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib"); +SECTIONS +{ + /* Read-only sections, merged into text segment: */ + PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); + . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS; + /* Place the build-id as close to the ELF headers as possible. This + maximises the chance the build-id will be present in core files, + which GDB can then use to locate the associated debuginfo file. */ + .note.gnu.build-id : { *(.note.gnu.build-id) } + .interp : { *(.interp) } + .hash : { *(.hash) } + .gnu.hash : { *(.gnu.hash) } + .dynsym : { *(.dynsym) } + .dynstr : { *(.dynstr) } + .gnu.version : { *(.gnu.version) } + .gnu.version_d : { *(.gnu.version_d) } + .gnu.version_r : { *(.gnu.version_r) } + .rela.dyn : + { + *(.rela.init) + *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) + *(.rela.fini) + *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) + *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) + *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) + *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) + *(.rela.ctors) + *(.rela.dtors) + *(.rela.got) + *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) + *(.rela.ifunc) + } + .rela.plt : + { + *(.rela.plt) + PROVIDE_HIDDEN (__rela_iplt_start = .); + *(.rela.iplt) + PROVIDE_HIDDEN (__rela_iplt_end = .); + } + .relr.dyn : { *(.relr.dyn) } + /* Start of the executable code region. */ + .init : + { + KEEP (*(SORT_NONE(.init))) + } =0x1f2003d5 + .plt : ALIGN(16) { *(.plt) *(.iplt) } + .text : + { + *(.text.unlikely .text.*_unlikely .text.unlikely.*) + *(.text.exit .text.exit.*) + *(.text.startup .text.startup.*) + *(.text.hot .text.hot.*) + *(SORT(.text.sorted.*)) + *(.text .stub .text.* .gnu.linkonce.t.*) + /* .gnu.warning sections are handled specially by elf.em. */ + *(.gnu.warning) + } =0x1f2003d5 + .fini : + { + KEEP (*(SORT_NONE(.fini))) + } =0x1f2003d5 + PROVIDE (__etext = .); + PROVIDE (_etext = .); + PROVIDE (etext = .); + /* Start of the Read Only Data region. */ + .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } + .rodata1 : { *(.rodata1) } + .eh_frame_hdr : { *(.eh_frame_hdr) *(.eh_frame_entry .eh_frame_entry.*) } + .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .sframe : ONLY_IF_RO { *(.sframe) *(.sframe.*) } + .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) } + .gnu_extab : ONLY_IF_RO { *(.gnu_extab*) } + /* These sections are generated by the Sun/Oracle C++ compiler. */ + .exception_ranges : ONLY_IF_RO { *(.exception_ranges*) } + /* Various note sections. Placed here so that they are always included + in the read-only segment and not treated as orphan sections. The + current orphan handling algorithm does place note sections after R/O + data, but this is not guaranteed to always be the case. */ + .note.build-id : { *(.note.build-id) } + .note.GNU-stack : { *(.note.GNU-stack) } + .note.gnu-property : { *(.note.gnu-property) } + .note.ABI-tag : { *(.note.ABI-tag) } + .note.package : { *(.note.package) } + .note.dlopen : { *(.note.dlopen) } + .note.netbsd.ident : { *(.note.netbsd.ident) } + .note.openbsd.ident : { *(.note.openbsd.ident) } + /* Start of the Read Write Data region. */ + /* Adjust the address for the data segment. We want to adjust up to + the same address within the page on the next page up. */ + . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE)); + /* Exception handling. */ + .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) *(.eh_frame.*) } + .sframe : ONLY_IF_RW { *(.sframe) *(.sframe.*) } + .gnu_extab : ONLY_IF_RW { *(.gnu_extab) } + .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } + .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } + /* Thread Local Storage sections. */ + .tdata : + { + PROVIDE_HIDDEN (__tdata_start = .); + *(.tdata .tdata.* .gnu.linkonce.td.*) + } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .preinit_array : + { + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP (*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + } + .init_array : + { + PROVIDE_HIDDEN (__init_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) + KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) + PROVIDE_HIDDEN (__init_array_end = .); + } + .fini_array : + { + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*))) + KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors)) + PROVIDE_HIDDEN (__fini_array_end = .); + } + .ctors : + { + /* gcc uses crtbegin.o to find the start of + the constructors, so we make sure it is + first. Because this is a wildcard, it + doesn't matter if the user does not + actually link against crtbegin.o; the + linker won't look for a file to match a + wildcard. The wildcard also means that it + doesn't matter which directory crtbegin.o + is in. */ + KEEP (*crtbegin.o(.ctors)) + KEEP (*crtbegin?.o(.ctors)) + /* We don't want to include the .ctor section from + the crtend.o file until after the sorted ctors. + The .ctor section from the crtend file contains the + end of ctors marker and it must be last */ + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors)) + KEEP (*(SORT(.ctors.*))) + KEEP (*(.ctors)) + } + .dtors : + { + KEEP (*crtbegin.o(.dtors)) + KEEP (*crtbegin?.o(.dtors)) + KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors)) + KEEP (*(SORT(.dtors.*))) + KEEP (*(.dtors)) + } + .jcr : { KEEP (*(.jcr)) } + .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) } + .dynamic : { *(.dynamic) } + .got : { *(.got) *(.igot) } + . = DATA_SEGMENT_RELRO_END (24, .); + .got.plt : { *(.got.plt) *(.igot.plt) } + .data : + { + PROVIDE (__data_start = .); + *(.data .data.* .gnu.linkonce.d.*) + SORT(CONSTRUCTORS) + } + .data1 : { *(.data1) } + _edata = .; + PROVIDE (edata = .); + . = ALIGN(ALIGNOF(NEXT_SECTION)); + __bss_start = .; + __bss_start__ = .; + .bss : + { + *(.dynbss) + *(.bss .bss.* .gnu.linkonce.b.*) + *(COMMON) + /* Align here to ensure that in the common case of there only being one + type of .bss section, the section occupies space up to _end. + Align after .bss to ensure correct alignment even if the + .bss section disappears because there are no input sections. + FIXME: Why do we need it? When there is no .bss section, we do not + pad the .data section. */ + . = ALIGN(. != 0 ? 64 / 8 : 1); + } + _bss_end__ = .; __bss_end__ = .; + . = ALIGN(64 / 8); + /* Start of the Large Data region. */ + . = SEGMENT_START("ldata-segment", .); + . = ALIGN(64 / 8); + __end__ = .; + _end = .; + PROVIDE (end = .); + . = DATA_SEGMENT_END (.); + /* Start of the Tiny Data region. */ + /* Stabs debugging sections. */ + .stab 0 : { *(.stab) } + .stabstr 0 : { *(.stabstr) } + .stab.excl 0 : { *(.stab.excl) } + .stab.exclstr 0 : { *(.stab.exclstr) } + .stab.index 0 : { *(.stab.index) } + .stab.indexstr 0 : { *(.stab.indexstr) } + .comment 0 (INFO) : { *(.comment); LINKER_VERSION; } + .gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) } + /* DWARF debug sections. + Symbols in the DWARF debugging sections are relative to the beginning + of the section so we begin them at 0. */ + /* DWARF 1. */ + .debug 0 : { *(.debug) } + .line 0 : { *(.line) } + /* GNU DWARF 1 extensions. */ + .debug_srcinfo 0 : { *(.debug_srcinfo) } + .debug_sfnames 0 : { *(.debug_sfnames) } + /* DWARF 1.1 and DWARF 2. */ + .debug_aranges 0 : { *(.debug_aranges) } + .debug_pubnames 0 : { *(.debug_pubnames) } + /* DWARF 2. */ + .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } + .debug_abbrev 0 : { *(.debug_abbrev) } + .debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) } + .debug_frame 0 : { *(.debug_frame) } + .debug_str 0 : { *(.debug_str) } + .debug_loc 0 : { *(.debug_loc) } + .debug_macinfo 0 : { *(.debug_macinfo) } + /* SGI/MIPS DWARF 2 extensions. */ + .debug_weaknames 0 : { *(.debug_weaknames) } + .debug_funcnames 0 : { *(.debug_funcnames) } + .debug_typenames 0 : { *(.debug_typenames) } + .debug_varnames 0 : { *(.debug_varnames) } + /* DWARF 3. */ + .debug_pubtypes 0 : { *(.debug_pubtypes) } + .debug_ranges 0 : { *(.debug_ranges) } + /* DWARF 5. */ + .debug_addr 0 : { *(.debug_addr) } + .debug_line_str 0 : { *(.debug_line_str) } + .debug_loclists 0 : { *(.debug_loclists) } + .debug_macro 0 : { *(.debug_macro) } + .debug_names 0 : { *(.debug_names) } + .debug_rnglists 0 : { *(.debug_rnglists) } + .debug_str_offsets 0 : { *(.debug_str_offsets) } + .debug_sup 0 : { *(.debug_sup) } + .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } + .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } + /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) } +} + From 6262c4ae503d77c9f2665c4911abbfaeb237cf49 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:25:55 +1100 Subject: [PATCH 3/9] fix(ld_so): getting TP on linux `ARCH_GET_FS` is x86_64 specific. On aarch64 it is not platform specific and just need to read out the TP from `TPIDR_EL0` Signed-off-by: Anhad Singh --- src/ld_so/mod.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ld_so/mod.rs b/src/ld_so/mod.rs index 5b20a70798..9e75a79394 100644 --- a/src/ld_so/mod.rs +++ b/src/ld_so/mod.rs @@ -139,14 +139,14 @@ pub unsafe fn init( ) { let tp: usize; - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", target_arch = "x86_64"))] { const ARCH_GET_FS: usize = 0x1003; let mut val = 0usize; syscall!(ARCH_PRCTL, ARCH_GET_FS, &mut val as *mut usize); tp = val; } - #[cfg(all(target_os = "redox", target_arch = "aarch64"))] + #[cfg(target_arch = "aarch64")] unsafe { core::arch::asm!( "mrs {}, tpidr_el0", From 4f1920ab96ece66c104497a8d2ddffce3fcf58c8 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:35:10 +1100 Subject: [PATCH 4/9] feat(ld_so/tcb): implement `os_arch_activate` for aarch64 linux Signed-off-by: Anhad Singh --- src/ld_so/tcb.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/ld_so/tcb.rs b/src/ld_so/tcb.rs index 6dbf4cbb39..2375ce1228 100644 --- a/src/ld_so/tcb.rs +++ b/src/ld_so/tcb.rs @@ -343,6 +343,19 @@ impl Tcb { } } + #[cfg(all(target_os = "linux", target_arch = "aarch64"))] + unsafe fn os_arch_activate(_os: &(), tls_end: usize, tls_len: usize) { + // Uses ABI page + let abi_ptr = tls_end - tls_len - 16; + unsafe { + core::ptr::write(abi_ptr as *mut usize, tls_end); + core::arch::asm!( + "msr tpidr_el0, {}", + in(reg) abi_ptr, + ); + } + } + #[cfg(target_os = "redox")] unsafe fn os_arch_activate( os: &OsSpecific, From 90963fdfb9829ce6b16c884c460764f57c9b8857 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:40:24 +1100 Subject: [PATCH 5/9] feat(platform/linux): stub rlct_clone Signed-off-by: Anhad Singh --- src/platform/linux/mod.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 4bf23aa6cf..6d6fe31e1c 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -645,10 +645,17 @@ impl Pal for Sys { Ok(crate::pthread::OsTid { thread_id: tid }) } + + #[cfg(target_arch = "aarch64")] + unsafe fn rlct_clone(stack: *mut usize) -> Result { + todo!("rlct_clone not implemented for aarch64 yet") + } + unsafe fn rlct_kill(os_tid: crate::pthread::OsTid, signal: usize) -> Result<()> { let tgid = Self::getpid(); e_raw(unsafe { syscall!(TGKILL, tgid, os_tid.thread_id, signal) }).map(|_| ()) } + fn current_os_tid() -> crate::pthread::OsTid { crate::pthread::OsTid { thread_id: unsafe { syscall!(GETTID) }, From 6d68ca995794a7d5f4fb04f97cc01768775e332c Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:41:52 +1100 Subject: [PATCH 6/9] fix(platform/linux): use `FACCESSAT` to implement access(2) `ACCESS` syscall is not available on aarch64. Signed-off-by: Anhad Singh --- src/platform/linux/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 6d6fe31e1c..84b18f93ec 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -79,10 +79,16 @@ impl Sys { } impl Pal for Sys { + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] fn access(path: CStr, mode: c_int) -> Result<()> { e_raw(unsafe { syscall!(ACCESS, path.as_ptr(), mode) }).map(|_| ()) } + #[cfg(target_arch = "aarch64")] + fn access(path: CStr, mode: c_int) -> Result<()> { + e_raw(unsafe { syscall!(FACCESSAT, AT_FDCWD, path.as_ptr(), mode, 0) }).map(|_| ()) + } + unsafe fn brk(addr: *mut c_void) -> Result<*mut c_void> { Ok(e_raw(unsafe { syscall!(BRK, addr) })? as *mut c_void) } From 6bcdac420279f505092bef5c99cf7eb9ff0e4deb Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:44:40 +1100 Subject: [PATCH 7/9] fix(platform/linux): use `FCHOWNAT` to implement lchown(2) `LCHOWN` syscall is not available on aarch64. Signed-off-by: Anhad Singh --- src/platform/linux/mod.rs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/platform/linux/mod.rs b/src/platform/linux/mod.rs index 84b18f93ec..4c05f39bca 100644 --- a/src/platform/linux/mod.rs +++ b/src/platform/linux/mod.rs @@ -455,10 +455,26 @@ impl Pal for Sys { unsafe { syscall!(GETUID) as uid_t } } + #[cfg(any(target_arch = "x86_64", target_arch = "x86"))] fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { e_raw(unsafe { syscall!(LCHOWN, path.as_ptr(), owner, group) }).map(|_| ()) } + #[cfg(target_arch = "aarch64")] + fn lchown(path: CStr, owner: uid_t, group: gid_t) -> Result<()> { + e_raw(unsafe { + syscall!( + FCHOWNAT, + AT_FDCWD, + path.as_ptr(), + owner as u32, + group as u32, + AT_SYMLINK_NOFOLLOW + ) + }) + .map(|_| ()) + } + fn link(path1: CStr, path2: CStr) -> Result<()> { e_raw(unsafe { syscall!( From a7d08aa37e62703f13e8954c9f9169908798310b Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 14:55:00 +1100 Subject: [PATCH 8/9] fix(tests/getopt_long): `c` should be an `int` not a `char` `getopt_long` returns an `int` not a `char`. On aarch64 `char` is unsigned but on x86 is signed. This is why it had worked so far without any issues. Signed-off-by: Anhad Singh --- tests/unistd/getopt_long.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/unistd/getopt_long.c b/tests/unistd/getopt_long.c index 1efb0a4a12..92716068ce 100644 --- a/tests/unistd/getopt_long.c +++ b/tests/unistd/getopt_long.c @@ -31,7 +31,7 @@ void runner(int argc, char *argv[]) { }; int option_index = 0; - char c; + int c; while((c = getopt_long(argc, argv, ":a", long_options, &option_index)) != -1) { switch(c) { case 'a': From 1fdddef6a07a4e54013f0b028ef0216f3cdcf0d5 Mon Sep 17 00:00:00 2001 From: Anhad Singh Date: Mon, 1 Dec 2025 15:10:50 +1100 Subject: [PATCH 9/9] fix(ld_so): linker script for aarch64-unknown-linux-gnu Ignore TLS. Signed-off-by: Anhad Singh --- ld_so/ld_script/aarch64-unknown-linux-gnu.ld | 22 ++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/ld_so/ld_script/aarch64-unknown-linux-gnu.ld b/ld_so/ld_script/aarch64-unknown-linux-gnu.ld index 1df7e5c015..a344feef5d 100644 --- a/ld_so/ld_script/aarch64-unknown-linux-gnu.ld +++ b/ld_so/ld_script/aarch64-unknown-linux-gnu.ld @@ -104,25 +104,25 @@ SECTIONS .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) } .exception_ranges : ONLY_IF_RW { *(.exception_ranges*) } /* Thread Local Storage sections. */ - .tdata : + /* .tdata : { PROVIDE_HIDDEN (__tdata_start = .); *(.tdata .tdata.* .gnu.linkonce.td.*) } - .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } + .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } */ .preinit_array : { PROVIDE_HIDDEN (__preinit_array_start = .); KEEP (*(.preinit_array)) PROVIDE_HIDDEN (__preinit_array_end = .); } - .init_array : + /* .init_array : { PROVIDE_HIDDEN (__init_array_start = .); KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*))) KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors)) PROVIDE_HIDDEN (__init_array_end = .); - } + } */ .fini_array : { PROVIDE_HIDDEN (__fini_array_start = .); @@ -248,6 +248,16 @@ SECTIONS .debug_sup 0 : { *(.debug_sup) } .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) } .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) } - /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) *(.gnu_object_only) } + /DISCARD/ : { + *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) + /* + * XXX: As of now, ld.so links with relibc which has the main functionality. In the next refactor, + * ld.so will be moved out of relibc. So, till that time, we have to discard any sections + * that may reference use thread local storage. + * + * .init_array also depends on TLS and is discarded as we don't need it. + */ + *(.gnu.linkonce.tb.*) *(.tcommon) + *(.init_array) + } } -