Merge upstream/master into submodule/relibc

Sync the relibc fork with 50 upstream commits (socket layer rework,
exec/signal/ptrace/path/timer updates, pthread cleanup, ld_so lifecycle
work bringing mark_ready/run_fini into the tree, dynamically-linked
init support, start.rs allocator-model rewrite, test harness updates).
Satisfies the verify-fork-functions gate (2 previously-missing ld_so
functions now present).

Conflicts resolved (4 files; 46 auto-merged):

- src/start.rs: took upstream's version wholesale. Upstream moved
  allocator/linker initialization into ld_so's new lifecycle (the
  mark_ready/run_fini work this merge brings in), superseding the RB
  alloc_init cluster; the old model's function was already merged out
  and its lone call would not compile.

- redox-rt/src/sys.rs: kept the RB refresh flow with the non-fatal
  lseek fallback (upstream adopted the refresh as a fatal '?' —
  RB's conservative fallback protects spawn for uid-dropped /
  namespace-restricted exec where the kernel cannot refresh).

- src/platform/redox/exec.rs: kept the RB root exec-permission bypass
  (ruid/euid != 0 gate, Linux-matching behavior).

- Cargo.lock: syn 2.0.118 -> 2.0.119 (upstream).

Verified: repo cook relibc --force-rebuild successful;
verify-fork-functions.sh --no-fetch relibc passes;
all 9 forks now pass the gate.
This commit is contained in:
Red Bear OS
2026-07-19 07:12:56 +09:00
54 changed files with 745 additions and 2333 deletions
Generated
+5 -5
View File
@@ -318,7 +318,7 @@ dependencies = [
[[package]]
name = "object"
version = "0.36.7"
source = "git+https://gitlab.redox-os.org/andypython/object#7270e3f0d06e5ef4c2b80abc6166d31f4ddf4fea"
source = "git+https://gitlab.redox-os.org/andypython/object?branch=new#da781336d847df0deb897ed1162785f6c2057c56"
dependencies = [
"memchr",
]
@@ -610,9 +610,9 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]]
name = "spin"
version = "0.9.8"
version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
dependencies = [
"lock_api",
]
@@ -625,9 +625,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]]
name = "syn"
version = "2.0.118"
version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [
"proc-macro2",
"quote",
+1
View File
@@ -117,6 +117,7 @@ features = ["c_api"]
[dependencies.object]
version = "0.36.7"
git = "https://gitlab.redox-os.org/andypython/object"
branch = "new"
default-features = false
features = ["elf", "read_core"]
+14 -13
View File
@@ -40,7 +40,7 @@ BUILTINS_VERSION=0.1.70
all: | headers libs
headers: $(HEADERS_DEPS)
headers: $(BUILD)/$(PROFILE)/librelibc.a $(HEADERS_DEPS)
rm -rf $(TARGET_HEADERS)
mkdir -p $(TARGET_HEADERS)
cp -r include/* $(TARGET_HEADERS)
@@ -51,13 +51,13 @@ endif
@set -e ; \
for header in $(HEADERS_UNPARSED); do \
if test -f "src/header/$$header/cbindgen.toml"; then \
echo -e "\033[0;36;49mWriting Header $$header\033[0m"; \
printf "\033[0;36;49mWriting Header $$header\033[0m\n"; \
out=`echo "$$header" | sed 's/_/\//g'`; \
out="$(TARGET_HEADERS)/$$out.h"; \
cat "src/header/$$header/cbindgen.toml" cbindgen.globdefs.toml \
| cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out"; \
fi \
done; echo -e "\033[0;36;49mAll headers written\033[0m";
done; printf "\033[0;36;49mAll headers written\033[0m\n";
clean:
$(CARGO) clean
@@ -79,20 +79,19 @@ libs: \
$(BUILD)/$(PROFILE)/libc.so \
$(BUILD)/$(PROFILE)/crt0.o \
$(BUILD)/$(PROFILE)/crti.o \
$(BUILD)/$(PROFILE)/crtn.o \
$(BUILD)/$(PROFILE)/ld.so
$(BUILD)/$(PROFILE)/crtn.o
install-libs: headers libs
mkdir -pv "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/libc.so" "$(DESTDIR)/lib"
ln -vnfs libc.so "$(DESTDIR)/lib/libc.so.6"
ln -vnfs libc.so "$(DESTDIR)/lib/$(LD_SONAME)"
cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib"
ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o"
ln -vnfs crt0.o "$(DESTDIR)/lib/Scrt1.o"
cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/crtn.o" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/ld.so" "$(DESTDIR)/$(LD_SO_PATH)"
ifeq ($(USE_RUST_LIBM),)
cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
else
@@ -135,10 +134,16 @@ test-once: sysroot/$(TARGET)
$(MAKE) -C tests run-once TESTBIN=$(TESTBIN)
$(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/libc.a
$(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/ld_so.o $(BUILD)/$(PROFILE)/libc.a
# Specifying a dynamic list makes all non-local `STV_DEFAULT`
# definitions non-preemptible, except for the symbols listed in
# `dynlst.txt`. So, the symbols defined in `dynlst.txt` may be
# interposed by other definitions at runtime (either from the
# executable or some shared library).
$(CC) -nostdlib \
-shared \
-Wl,--gc-sections \
-Wl,--dynamic-list=dynlst.txt \
-Wl,-z,pack-relative-relocs \
-Wl,--sort-common \
-Wl,--whole-archive $^ -Wl,--no-whole-archive \
@@ -146,10 +151,6 @@ $(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/libc.a
$(LINKFLAGS) \
-o $@
$(BUILD)/$(PROFILE)/ld.so: $(BUILD)/$(PROFILE)/ld_so.o $(BUILD)/$(PROFILE)/libc.a
# TODO: merge ld.so with libc.so: --dynamic-list=dynamic-list-file
$(LD) --shared -Bsymbolic --no-relax -T ld_so/ld_script/$(TARGET).ld --gc-sections $^ -o $@
$(BUILD)/$(PROFILE)/libc.a: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a
echo "create $@" > "$@.mri"
for lib in $^; do\
@@ -219,9 +220,9 @@ $(BUILD)/openlibm: openlibm
touch $@
ifeq ($(USE_RUST_LIBM),)
$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm $(BUILD)/$(PROFILE)/librelibc.a
$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm headers $(BUILD)/$(PROFILE)/librelibc.a
$(MAKE) -s AR=$(AR) CC="$(CC_WRAPPER) $(CC)" LD=$(LD) CPPFLAGS="$(CPPFLAGS) -fno-stack-protector -I$(shell pwd)/include -I$(TARGET_HEADERS)" -C $< libopenlibm.a
./renamesyms.sh "$@" "$(BUILD)/release/deps/"
./renamesyms.sh "$@" "$(BUILD)/$(PROFILE)/deps/"
else
$(BUILD)/openlibm/libopenlibm.a:
mkdir -p "$(BUILD)/openlibm"
+9 -9
View File
@@ -9,7 +9,7 @@ ifeq ($(TARGET),aarch64-unknown-linux-gnu)
export NM=aarch64-linux-gnu-nm
export OBJCOPY=aarch64-linux-gnu-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
LD_SONAME=ld.so.1
endif
ifeq ($(TARGET),aarch64-unknown-linux-relibc)
@@ -19,7 +19,7 @@ ifeq ($(TARGET),aarch64-unknown-linux-relibc)
export NM=aarch64-linux-relibc-nm
export OBJCOPY=aarch64-linux-relibc-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
LD_SONAME=ld.so.1
endif
@@ -30,7 +30,7 @@ ifeq ($(TARGET),aarch64-unknown-redox)
export NM=aarch64-unknown-redox-nm
export OBJCOPY=aarch64-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1
LD_SONAME=ld.so.1
endif
ifeq ($(TARGET),i586-unknown-redox)
@@ -40,7 +40,7 @@ ifeq ($(TARGET),i586-unknown-redox)
export NM=i586-unknown-redox-nm
export OBJCOPY=i586-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1
LD_SONAME=ld.so.1
endif
ifeq ($(TARGET),i686-unknown-redox)
@@ -50,7 +50,7 @@ ifeq ($(TARGET),i686-unknown-redox)
export NM=i686-unknown-redox-nm
export OBJCOPY=i686-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1
LD_SONAME=ld.so.1
endif
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
@@ -60,7 +60,7 @@ ifeq ($(TARGET),x86_64-unknown-linux-gnu)
export NM=x86_64-linux-gnu-nm
export OBJCOPY=objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
LD_SONAME=ld64.so.1
endif
ifeq ($(TARGET),x86_64-unknown-linux-relibc)
@@ -70,7 +70,7 @@ ifeq ($(TARGET),x86_64-unknown-linux-relibc)
export NM=x86_64-linux-relibc-nm
export OBJCOPY=x86_64-linux-relibc-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
LD_SONAME=ld64.so.1
endif
ifeq ($(TARGET),x86_64-unknown-redox)
@@ -80,7 +80,7 @@ ifeq ($(TARGET),x86_64-unknown-redox)
export NM=x86_64-unknown-redox-nm
export OBJCOPY=x86_64-unknown-redox-objcopy
export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1
LD_SONAME=ld64.so.1
endif
ifeq ($(TARGET),riscv64gc-unknown-redox)
@@ -90,5 +90,5 @@ ifeq ($(TARGET),riscv64gc-unknown-redox)
export NM=riscv64-unknown-redox-nm
export OBJCOPY=riscv64-unknown-redox-objcopy
export CPPFLAGS=-march=rv64gc -mabi=lp64d
LD_SO_PATH=lib/ld.so.1
LD_SONAME=ld.so.1
endif
+27
View File
@@ -0,0 +1,27 @@
{
environ;
stdin;
stdout;
stderr;
timezone;
daylight;
tzname;
__timezone;
__daylight;
__tzname;
signgam;
__signgam;
optarg;
optind;
opterr;
optreset;
__optreset;
getdate_err;
__stack_chk_guard;
};
-1
View File
@@ -1,6 +1,5 @@
#![no_std]
#![allow(internal_features)]
#![feature(core_intrinsics)]
#![deny(unsafe_op_in_unsafe_fn)]
use core::{
@@ -1,263 +0,0 @@
/* 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_*)
/*
* 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)
}
}
@@ -1 +0,0 @@
./aarch64-unknown-linux-gnu.ld
-255
View File
@@ -1,255 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 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-littleaarch64",
"elf64-littleaarch64")
OUTPUT_ARCH(aarch64)
ENTRY(_start)
SEARCH_DIR("/aarch64-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
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", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.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.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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.*) }
.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*) }
/* 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.*) }
.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 (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss 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);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* 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 : { *(.comment) }
.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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/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 need to be not discarded unlike x86_64 linker variant
*/
*(.gnu.linkonce.tb.*) *(.tcommon)
}
}
-256
View File
@@ -1,256 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 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("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/i686-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib32");
SEARCH_DIR("/lib32");
SEARCH_DIR("/usr/lib32");
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", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.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.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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.*) }
.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*) }
/* 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.*) }
.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 (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss 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);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* 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 : { *(.comment) }
.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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/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)
}
}
-256
View File
@@ -1,256 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 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("elf32-i386", "elf32-i386",
"elf32-i386")
OUTPUT_ARCH(i386)
ENTRY(_start)
SEARCH_DIR("/i686-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib32");
SEARCH_DIR("/lib32");
SEARCH_DIR("/usr/lib32");
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", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.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.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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.*) }
.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*) }
/* 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.*) }
.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 (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss 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);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* 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 : { *(.comment) }
.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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/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)
}
}
-247
View File
@@ -1,247 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 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-littleriscv", "elf64-littleriscv", "elf64-littleriscv" )
OUTPUT_ARCH(riscv)
ENTRY(_start)
SEARCH_DIR("/riscv64-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
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", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.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.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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.*) }
.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*) }
/* 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.*) }
.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 (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss 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);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* 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 : { *(.comment) }
.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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/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)
}
}
-259
View File
@@ -1,259 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 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-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib64");
SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.164");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
SEARCH_DIR("/usr/x86_64-pc-linux-gnu/lib");
SEARCH_DIR("/usr/lib64/binutils/x86_64-pc-linux-gnu/2.33.1");
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", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.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.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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.*) }
.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*) }
/* 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.*) }
.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 : ALIGN(4K)
{
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 (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss 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);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* 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 : { *(.comment) }
.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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/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)
}
}
@@ -1 +0,0 @@
./x86_64-unknown-linux-gnu.ld
-256
View File
@@ -1,256 +0,0 @@
/* Script for -z combreloc */
/* Copyright (C) 2014-2020 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-x86-64", "elf64-x86-64",
"elf64-x86-64")
OUTPUT_ARCH(i386:x86-64)
ENTRY(_start)
SEARCH_DIR("/x86_64-unknown-redox/lib");
SEARCH_DIR("/usr/local/lib64");
SEARCH_DIR("/lib64");
SEARCH_DIR("/usr/lib64");
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", 0x20000000) + SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.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.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
*(.rela.ifunc)
}
.rela.plt :
{
*(.rela.plt)
PROVIDE_HIDDEN (__rela_iplt_start = .);
*(.rela.iplt)
PROVIDE_HIDDEN (__rela_iplt_end = .);
}
. = ALIGN(CONSTANT (MAXPAGESIZE));
.init :
{
KEEP (*(SORT_NONE(.init)))
}
.plt : { *(.plt) *(.iplt) }
.plt.got : { *(.plt.got) }
.plt.sec : { *(.plt.sec) }
.text :
{
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf.em. */
*(.gnu.warning)
}
.fini :
{
KEEP (*(SORT_NONE(.fini)))
}
PROVIDE (__etext = .);
PROVIDE (_etext = .);
PROVIDE (etext = .);
. = ALIGN(CONSTANT (MAXPAGESIZE));
/* Adjust the address for the rodata segment. We want to adjust up to
the same address within the page on the next page up. */
. = SEGMENT_START("rodata-segment", ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)));
.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.*) }
.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*) }
/* 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.*) }
.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 : ALIGN(4K)
{
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 (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
.got.plt : { *(.got.plt) *(.igot.plt) }
.data :
{
*(.data .data.* .gnu.linkonce.d.*)
SORT(CONSTRUCTORS)
}
.data1 : { *(.data1) }
_edata = .; PROVIDE (edata = .);
. = .;
__bss_start = .;
.bss :
{
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
*(COMMON)
/* Align here to ensure that the .bss 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);
}
.lbss :
{
*(.dynlbss)
*(.lbss .lbss.* .gnu.linkonce.lb.*)
*(LARGE_COMMON)
}
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
}
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
{
*(.ldata .ldata.* .gnu.linkonce.l.*)
. = ALIGN(. != 0 ? 64 / 8 : 1);
}
. = ALIGN(64 / 8);
_end = .; PROVIDE (end = .);
. = DATA_SEGMENT_END (.);
/* 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 : { *(.comment) }
.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 Extension. */
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
/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)
}
}
+1 -1
View File
@@ -112,7 +112,7 @@ global_asm!(
.globl _start
_start:
mv a0, sp
jal relibc_ld_so_start
call relibc_ld_so_start
unimp
"
);
+1
View File
@@ -706,6 +706,7 @@ impl<'a> MmapGuard<'a> {
Ok(())
}
#[expect(clippy::mut_from_ref)]
pub unsafe fn map_mut_anywhere(
fd: &'a FdGuardUpper,
offset: usize,
+12
View File
@@ -953,6 +953,10 @@ impl FdTbl {
pub const CONTEXT_MAX_FILES: u32 = 65_536;
pub const DEFAULT_CAPACITY: usize = usize::BITS as usize;
#[expect(
clippy::new_without_default,
reason = "default not expected for this type"
)]
pub const fn new() -> Self {
Self {
fd: None,
@@ -1300,6 +1304,10 @@ bitflags::bitflags! {
}
impl PosixFdTbl {
#[expect(
clippy::new_without_default,
reason = "default not expected for this type"
)]
pub const fn new() -> Self {
Self {
table: Vec::new(),
@@ -1628,6 +1636,10 @@ pub struct UpperFdTbl {
}
impl UpperFdTbl {
#[expect(
clippy::new_without_default,
reason = "default not expected for this type"
)]
pub const fn new() -> Self {
Self {
table: Vec::new(),
+1
View File
@@ -258,6 +258,7 @@ impl<'a, T: Kind> NulStr<'a, T> {
/// Scan the string to get its length.
#[doc(alias = "strlen")]
#[doc(alias = "wcslen")]
#[expect(clippy::len_without_is_empty, reason = "len() signature intentional")]
pub fn len(self) -> usize {
self.to_chars().len()
}
+2 -1
View File
@@ -76,7 +76,7 @@ macro_rules! pthread_assert_equal_size(
// Fail at compile-time if alignments differ.
let a = [0_u8; core::mem::align_of::<$export>()];
#[allow(clippy::useless_transmute)]
#[expect(clippy::useless_transmute)]
let b: [u8; core::mem::align_of::<Wrapped>()] = core::mem::transmute(a);
};
// TODO: Turn into a macro?
@@ -88,6 +88,7 @@ macro_rules! pthread_assert_equal_size(
let _: libc::$export = core::mem::transmute(export.__relibc_internal_size);
let a = [0_u8; core::mem::align_of::<$export>()];
#[expect(clippy::useless_transmute)]
let b: [u8; core::mem::align_of::<libc::$export>()] = core::mem::transmute(a);
};
+2 -2
View File
@@ -68,13 +68,13 @@ impl<'a> From<&'a syscall::TimeSpec> for timespec {
fn from(value: &'a syscall::TimeSpec) -> Self {
Self {
tv_sec: value.tv_sec as _,
tv_nsec: value.tv_nsec as _,
tv_nsec: value.tv_nsec.into(),
}
}
}
#[cfg(target_os = "redox")]
impl<'a> From<&'a timespec> for syscall::TimeSpec {
impl From<&timespec> for syscall::TimeSpec {
fn from(tp: &timespec) -> Self {
Self {
tv_sec: tp.tv_sec as _,
+13 -15
View File
@@ -11,10 +11,13 @@ use core::{
sync::atomic::{AtomicUsize, Ordering},
};
use alloc::sync::Arc;
use crate::{
c_str::CStr,
ld_so::{
linker::{DlError, ObjectHandle, Resolve, ScopeKind},
dso::DSO,
linker::{DlError, Resolve, ScopeKind},
tcb::Tcb,
},
platform::types::{c_char, c_int, c_void},
@@ -123,11 +126,8 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
let mut linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow();
match (cbs.load_library)(&mut linker, filename, resolve, scope, noload) {
Ok(handle) => handle.as_ptr().cast_mut(),
match linker.load_library(filename, resolve, scope, noload) {
Ok(handle) => Arc::into_raw(handle).cast::<c_void>().cast_mut(),
Err(error) => {
set_last_error(error);
ptr::null_mut()
@@ -138,7 +138,7 @@ pub unsafe extern "C" fn dlopen(cfilename: *const c_char, flags: c_int) -> *mut
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dlsym.html>.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void {
let handle = ObjectHandle::from_ptr(handle);
let handle = unsafe { handle.cast::<DSO>().as_ref() };
if symbol.is_null() {
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
@@ -161,9 +161,8 @@ pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *m
}
let linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow();
match (cbs.get_sym)(&linker, handle, symbol_str) {
match linker.get_sym(handle, symbol_str) {
Some(sym) => sym,
_ => {
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst);
@@ -185,15 +184,14 @@ pub unsafe extern "C" fn dlclose(handle: *mut c_void) -> c_int {
return -1;
};
let Some(handle) = ObjectHandle::from_ptr(handle) else {
if handle.is_null() {
set_last_error(DlError::InvalidHandle);
return -1;
};
}
let mut linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow();
(cbs.unload)(&mut linker, handle);
let obj = unsafe { Arc::from_raw(handle.cast::<DSO>()) };
linker.unload(obj);
0
}
+7 -2
View File
@@ -98,11 +98,16 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig
continue;
}
#[expect(clippy::needless_update)]
#[cfg(target_os = "redox")]
let mut event = epoll_event {
events: 0,
data: epoll_data { u64: i as u64 },
..Default::default()
};
#[cfg(target_os = "linux")]
let mut event = epoll_event {
events: 0,
data: epoll_data { u64: i as u64 },
..Default::default() // needed only on redox for _pad field
};
for (p, ep) in event_map.iter() {
+1 -1
View File
@@ -5,7 +5,7 @@ pub fn split(line: &mut [u8]) -> Option<passwd> {
let mut parts = line.split_mut(|&c| c == b'\0');
Some(passwd {
pw_name: parts.next()?.as_mut_ptr().cast::<c_char>(),
pw_passwd: c"x".as_ptr() as *const c_char as *mut c_char,
pw_passwd: c"x".as_ptr().cast::<c_char>().cast_mut(),
pw_uid: parsed(parts.next())?,
pw_gid: parsed(parts.next())?,
pw_gecos: parts.next()?.as_mut_ptr().cast::<c_char>(),
+16 -16
View File
@@ -22,7 +22,9 @@ fn dup_read<T>(fd: c_int, name: &str, t: &mut T) -> syscall::Result<usize> {
let size = mem::size_of::<T>();
let bytes = dup.read(unsafe { slice::from_raw_parts_mut(t as *mut T as *mut u8, size) })?;
let bytes = dup.read(unsafe {
slice::from_raw_parts_mut(core::ptr::from_mut::<T>(t).cast::<u8>(), size)
})?;
Ok(bytes / size)
}
@@ -33,7 +35,8 @@ fn dup_write<T>(fd: c_int, name: &str, t: &T) -> Result<usize> {
let size = mem::size_of::<T>();
let bytes = dup.write(unsafe { slice::from_raw_parts(t as *const T as *const u8, size) })?;
let bytes = dup
.write(unsafe { slice::from_raw_parts(core::ptr::from_ref::<T>(t).cast::<u8>(), size) })?;
Ok(bytes / size)
}
@@ -50,13 +53,13 @@ impl IoctlBuffer {
unsafe fn read<T>(&self) -> Result<T> {
let (ptr, size) = match *self {
Self::Write(ptr, size) => (ptr, size),
Self::ReadWrite(ptr, size) => (ptr as *const c_void, size),
Self::ReadWrite(ptr, size) => (ptr.cast_const(), size),
_ => {
return Err(Errno(EINVAL));
}
};
if size == mem::size_of::<T>() {
let value = unsafe { ptr::read(ptr as *const T) };
let value = unsafe { ptr::read(ptr.cast::<T>()) };
Ok(value)
} else {
Err(Errno(EINVAL))
@@ -64,14 +67,11 @@ impl IoctlBuffer {
}
unsafe fn write<T>(&mut self, value: T) -> Result<()> {
let (ptr, size) = match *self {
Self::Read(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size),
_ => {
return Err(Errno(EINVAL));
}
let (Self::Read(ptr, size) | Self::ReadWrite(ptr, size)) = *self else {
return Err(Errno(EINVAL));
};
if size == mem::size_of::<T>() {
unsafe { ptr::write(ptr as *mut T, value) };
unsafe { ptr::write(ptr.cast::<T>(), value) };
Ok(())
} else {
Err(Errno(EINVAL))
@@ -83,7 +83,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
match request {
FIONBIO => {
let mut flags = Sys::fcntl(fd, fcntl::F_GETFL, 0)?;
flags = if unsafe { *(out as *mut c_int) } == 0 {
flags = if unsafe { *out.cast::<c_int>() } == 0 {
flags & !fcntl::O_NONBLOCK
} else {
flags | fcntl::O_NONBLOCK
@@ -91,7 +91,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
Sys::fcntl(fd, fcntl::F_SETFL, flags as c_ulonglong)?;
}
TCGETS => {
let termios = unsafe { &mut *(out as *mut termios::termios) };
let termios = unsafe { &mut *out.cast::<termios::termios>() };
dup_read(fd, "termios", termios)?;
}
// TODO: give these different behaviors
@@ -119,7 +119,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
todo_skip!(0, "ioctl TIOCSCTTY");
}
TIOCGPGRP => {
let pgrp = unsafe { &mut *(out as *mut pid_t) };
let pgrp = unsafe { &mut *out.cast::<pid_t>() };
dup_read(fd, "pgrp", pgrp)?;
}
TIOCSPGRP => {
@@ -127,7 +127,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
dup_write(fd, "pgrp", pgrp)?;
}
TIOCGWINSZ => {
let winsize = unsafe { &mut *(out as *mut winsize) };
let winsize = unsafe { &mut *out.cast::<winsize>() };
dup_read(fd, "winsize", winsize)?;
}
TIOCSWINSZ => {
@@ -135,7 +135,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
dup_write(fd, "winsize", winsize)?;
}
TIOCGPTLCK => {
let lock = unsafe { &mut *(out as *mut c_int) };
let lock = unsafe { &mut *out.cast::<c_int>() };
dup_read(fd, "ptlock", lock)?;
}
TIOCSPTLCK => {
@@ -143,7 +143,7 @@ pub unsafe fn ioctl_inner(fd: c_int, request: c_ulong, out: *mut c_void) -> Resu
dup_write(fd, "ptlock", lock)?;
}
TIOCGPTN => {
let name = unsafe { &mut *(out as *mut c_int) };
let name = unsafe { &mut *out.cast::<c_int>() };
dup_read(fd, "ptsname", name)?;
}
SIOCATMARK => {
+1 -1
View File
@@ -72,7 +72,7 @@ pub(crate) struct timer_internal_t {
#[cfg(target_os = "redox")]
impl timer_internal_t {
pub unsafe fn from_raw(timerid: timer_t) -> &'static mut Self {
unsafe { &mut *(timerid as *mut Self) }
unsafe { &mut *timerid.cast::<Self>() }
}
}
+3 -1
View File
@@ -1,4 +1,6 @@
/// sysconf.h: <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sysconf.html>.
//! `sysconf.h` implementation.
//!
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/sysconf.html>.
#[cfg(target_os = "redox")]
#[path = "sysconf/redox.rs"]
+3 -3
View File
@@ -40,7 +40,7 @@ pub(super) fn sysconf_impl(name: c_int) -> c_long {
_SC_TIMEOUTS => 202405,
_SC_TIMERS => 202405,
_SC_SYMLOOP_MAX => -1,
_SC_HOST_NAME_MAX => limits::HOST_NAME_MAX.try_into().unwrap_or(-1),
_SC_HOST_NAME_MAX => limits::HOST_NAME_MAX,
_SC_NPROCESSORS_CONF => get_cpu_count().unwrap_or(None).unwrap_or(1),
_SC_NPROCESSORS_ONLN => get_cpu_count().unwrap_or(None).unwrap_or(1),
_SC_PHYS_PAGES => get_mem_stat().map(|s| s.f_blocks as c_long).unwrap_or(-1),
@@ -77,6 +77,6 @@ pub fn get_mem_stat() -> Result<sys_statvfs::statvfs, Errno> {
let mut buf = sys_statvfs::statvfs::default();
let res = Sys::fstatvfs(fd, Out::from_mut(&mut buf));
if let Ok(()) = Sys::close(fd) {}; // TODO handle error
let _ = res?;
return Ok(buf);
res?;
Ok(buf)
}
-39
View File
@@ -1,39 +0,0 @@
use super::linker::{Linker, ObjectHandle, Resolve, Result, ScopeKind};
use crate::platform::types::c_void;
use alloc::boxed::Box;
pub struct LinkerCallbacks {
pub unload: Box<dyn Fn(&mut Linker, ObjectHandle)>,
pub load_library:
Box<dyn Fn(&mut Linker, Option<&str>, Resolve, ScopeKind, bool) -> Result<ObjectHandle>>,
pub get_sym: Box<dyn Fn(&Linker, Option<ObjectHandle>, &str) -> Option<*mut c_void>>,
}
impl LinkerCallbacks {
#[allow(clippy::new_without_default)]
pub fn new() -> LinkerCallbacks {
LinkerCallbacks {
unload: Box::new(unload),
load_library: Box::new(load_library),
get_sym: Box::new(get_sym),
}
}
}
fn unload(linker: &mut Linker, handle: ObjectHandle) {
linker.unload(handle)
}
fn load_library(
linker: &mut Linker,
name: Option<&str>,
resolve: Resolve,
scope: ScopeKind,
noload: bool,
) -> Result<ObjectHandle> {
linker.load_library(name, resolve, scope, noload)
}
fn get_sym(linker: &Linker, handle: Option<ObjectHandle>, name: &str) -> Option<*mut c_void> {
linker.get_sym(handle, name)
}
+216 -67
View File
@@ -3,7 +3,7 @@
//! * <https://www.akkadia.org/drepper/dsohowto.pdf>
use object::{
NativeEndian, Object, StringTable, SymbolIndex, elf,
NativeEndian, Object, StringTable, SymbolIndex, U32, elf,
read::elf::{
Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _,
Rela as _, Sym as _, Version, VersionTable,
@@ -42,25 +42,29 @@ pub type Relr = usize;
#[cfg(target_pointer_width = "32")]
mod shim {
use object::{NativeEndian, elf::*, read::elf::ElfFile32};
pub type Dyn = Dyn32<NativeEndian>;
pub type Rel = Rel32<NativeEndian>;
pub type Rela = Rela32<NativeEndian>;
pub type Sym = Sym32<NativeEndian>;
pub type FileHeader = FileHeader32<NativeEndian>;
pub type ProgramHeader = ProgramHeader32<NativeEndian>;
use object::{NativeEndian, elf, read::elf::ElfFile32};
pub type Dyn = elf::Dyn32<NativeEndian>;
pub type Rel = elf::Rel32<NativeEndian>;
pub type Rela = elf::Rela32<NativeEndian>;
pub type Sym = elf::Sym32<NativeEndian>;
pub type FileHeader = elf::FileHeader32<NativeEndian>;
pub type ProgramHeader = elf::ProgramHeader32<NativeEndian>;
pub type GnuHashHeader = elf::GnuHashHeader<NativeEndian>;
pub type SysVHashHeader = elf::HashHeader<NativeEndian>;
pub type ElfFile<'a> = ElfFile32<'a, NativeEndian>;
}
#[cfg(target_pointer_width = "64")]
mod shim {
use object::{NativeEndian, elf::*, read::elf::ElfFile64};
pub type Dyn = Dyn64<NativeEndian>;
pub type Rel = Rel64<NativeEndian>;
pub type Rela = Rela64<NativeEndian>;
pub type Sym = Sym64<NativeEndian>;
pub type FileHeader = FileHeader64<NativeEndian>;
pub type ProgramHeader = ProgramHeader64<NativeEndian>;
use object::{NativeEndian, elf, read::elf::ElfFile64};
pub type Dyn = elf::Dyn64<NativeEndian>;
pub type Rel = elf::Rel64<NativeEndian>;
pub type Rela = elf::Rela64<NativeEndian>;
pub type Sym = elf::Sym64<NativeEndian>;
pub type FileHeader = elf::FileHeader64<NativeEndian>;
pub type ProgramHeader = elf::ProgramHeader64<NativeEndian>;
pub type GnuHashHeader = elf::GnuHashHeader<NativeEndian>;
pub type SysVHashHeader = elf::HashHeader<NativeEndian>;
pub type ElfFile<'a> = ElfFile64<'a, NativeEndian>;
}
@@ -176,7 +180,7 @@ impl<'data> Dynamic<'data> {
unsafe impl Send for Dynamic<'_> {}
unsafe impl Sync for Dynamic<'_> {}
#[derive(Debug)]
#[derive(Debug, Copy, Clone)]
pub(super) struct Relocation {
pub(super) offset: usize,
pub(super) addend: Option<usize>,
@@ -331,14 +335,35 @@ impl SymbolBinding {
}
}
pub struct MemoryMapHandle {
ptr: *const u8,
size: usize,
}
impl MemoryMapHandle {
pub fn as_ptr(&self) -> *const u8 {
self.ptr
}
pub fn size(&self) -> usize {
self.size
}
}
impl Drop for MemoryMapHandle {
fn drop(&mut self) {
unsafe { Sys::munmap(self.ptr as *mut c_void, self.size).unwrap() };
}
}
/// Use to represent a library as well as all the symbols that is loaded withen it.
pub struct DSO {
pub name: String,
pub id: usize,
pub dlopened: bool,
pub entry_point: usize,
/// Loaded library in-memory data
pub mmap: &'static [u8],
pub base: *const u8,
pub mmap: Option<MemoryMapHandle>,
pub tls_module_id: usize,
pub tls_offset: usize,
@@ -350,9 +375,56 @@ pub struct DSO {
/// Whether this DSO *and* its dependencies have been successfully loaded.
is_ready: AtomicBool,
/// Is this DSO for ld.so?
is_me: bool,
}
impl DSO {
#[expect(clippy::not_unsafe_ptr_arg_deref, reason = "see FIXME note")]
pub fn from_raw(
base: *const u8,
dyns: &[Dyn],
phdrs: &[ProgramHeader],
id: usize,
tls_module_id: usize,
tls_offset: usize,
) -> (Self, Master) {
// FIXME: What should `path` be set to?
// FIXME: this function and `parse_dynamic` should be unsafe.
let (dynamic, _debug) = Self::parse_dynamic("", base, true, dyns).unwrap();
let tcb_master = phdrs
.iter()
.find(|ph| ph.p_type(NativeEndian) == elf::PT_TLS)
.map(|ph| Master {
ptr: unsafe { base.byte_add(ph.p_vaddr(NativeEndian) as usize) },
image_size: ph.p_filesz(NativeEndian) as usize,
segment_size: ph.p_memsz(NativeEndian) as usize,
offset: tls_offset + ph.p_memsz(NativeEndian) as usize,
})
.unwrap();
(
Self {
name: String::from("libc.so.6"),
id,
tls_offset: tcb_master.offset,
tls_module_id,
dlopened: false,
entry_point: 0,
base,
mmap: None,
dynamic,
scope: spin::Once::new(),
pie: true,
is_ready: AtomicBool::new(false),
is_me: true,
},
tcb_master,
)
}
pub fn new(
path: &str,
data: &[u8],
@@ -385,7 +457,10 @@ impl DSO {
id,
dlopened,
entry_point,
mmap,
base: mmap.as_ptr(),
mmap: Some(mmap),
tls_module_id: if tcb_master.is_some() {
tls_module_id
} else {
@@ -397,13 +472,14 @@ impl DSO {
dynamic,
scope: spin::Once::new(),
is_ready: AtomicBool::new(false),
is_me: false,
};
Ok((dso, tcb_master, elf.elf_program_headers().to_vec()))
}
#[inline]
pub fn mark_ready(&self) {
pub unsafe fn mark_ready(&self) {
self.is_ready.store(true, Ordering::SeqCst);
}
@@ -444,11 +520,7 @@ impl DSO {
Some((
Symbol {
name,
base: if self.pie {
self.mmap.as_ptr() as usize
} else {
0
},
base: if self.pie { self.base as usize } else { 0 },
value: sym.st_value(NativeEndian) as usize,
size: sym.st_size(NativeEndian) as usize,
sym_type: sym.st_type(),
@@ -468,7 +540,7 @@ impl DSO {
}
}
pub fn run_fini(&self) {
pub unsafe fn run_fini(&self) {
for f in self.dynamic.fini_array.iter().rev() {
unsafe { f() }
}
@@ -480,7 +552,7 @@ impl DSO {
data: &'a [u8],
base_addr: Option<usize>,
tls_offset: usize,
) -> Result<(&'static [u8], Option<Master>, Dynamic<'static>), String> {
) -> Result<(MemoryMapHandle, Option<Master>, Dynamic<'static>), String> {
let endian = elf.endian();
log::trace!("# {}", path);
// data for struct LinkMap
@@ -640,8 +712,9 @@ impl DSO {
let dynamic = dynamic.ok_or_else(|| "Unable to find PT_DYNAMIC section".to_string())?;
let (parsed_dynamic, debug) = Self::parse_dynamic(path, mmap, is_pie_enabled(elf), dynamic)
.map_err(|e| e.to_string())?;
let (parsed_dynamic, debug) =
Self::parse_dynamic(path, mmap.as_ptr(), is_pie_enabled(elf), dynamic.1)
.map_err(|e| e.to_string())?;
if let Some(i) = debug {
// FIXME: cleanup
@@ -664,14 +737,21 @@ impl DSO {
}
}
Ok((mmap, tcb_master, parsed_dynamic))
Ok((
MemoryMapHandle {
ptr: mmap.as_ptr(),
size: mmap.len(),
},
tcb_master,
parsed_dynamic,
))
}
fn parse_dynamic<'a>(
path: &str,
mmap: &'a [u8],
mmap: *const u8,
is_pie: bool,
(_, entries): (&ProgramHeader, &[Dyn]),
entries: &[Dyn],
) -> object::Result<(Dynamic<'a>, Option<usize>)> {
let mut runpath = None;
let mut got = None;
@@ -692,28 +772,79 @@ impl DSO {
for (i, entry) in entries.iter().enumerate() {
let val = entry.d_val(NativeEndian);
let relative_idx = val as usize - if is_pie { 0 } else { mmap.as_ptr() as usize };
let ptr = (val as usize + if is_pie { mmap.as_ptr() as usize } else { 0 }) as *const u8;
let relative_idx = val as usize - if is_pie { 0 } else { mmap as usize };
let ptr = (val as usize + if is_pie { mmap as usize } else { 0 }) as *const u8;
let tag = entry.d_tag(NativeEndian) as u32;
match tag {
elf::DT_DEBUG => debug = Some(i),
// {Gnu,SysV}HashTable::parse()
//
// > The header does not contain a length field, and so all of
// > `data` will be used as the hash table values. It does not
// > matter if this is longer than needed...
elf::DT_GNU_HASH => {
let value = GnuHashTable::parse(NativeEndian, &mmap[relative_idx..])?;
hash_table = Some(HashTable::Gnu(value));
let header = unsafe { ptr.cast::<GnuHashHeader>().as_ref() }.unwrap();
let bloom_count = header.bloom_count.get(NativeEndian) as usize;
let bucket_count = header.bucket_count.get(NativeEndian) as usize;
let symbol_base = header.symbol_base.get(NativeEndian);
let bloom_size = bloom_count * size_of::<usize>();
let mut ptr = unsafe { ptr.byte_add(size_of::<GnuHashHeader>()) };
let bloom_filters = unsafe { slice::from_raw_parts(ptr, bloom_size) };
unsafe { ptr = ptr.byte_add(bloom_size) };
let buckets = unsafe {
slice::from_raw_parts(ptr.cast::<U32<NativeEndian>>(), bucket_count)
};
unsafe { ptr = ptr.byte_add(bucket_count * size_of::<u32>()) };
let mut max_symbol = 0;
for bucket in buckets {
let bucket = bucket.get(NativeEndian);
if max_symbol < bucket {
max_symbol = bucket;
}
}
assert_ne!(max_symbol, 0);
let chains_ptr = ptr.cast::<u32>();
let mut i = max_symbol - symbol_base;
while unsafe { chains_ptr.add(i as usize).read() & 1 == 0 } {
i += 1;
}
let values = unsafe {
slice::from_raw_parts(ptr.cast::<U32<NativeEndian>>(), i as usize + 1)
};
let table = GnuHashTable {
symbol_base,
bloom_shift: header.bloom_shift.get(NativeEndian),
bloom_filters,
buckets,
values,
};
hash_table = Some(HashTable::Gnu(table));
}
// XXX: Both GNU_HASH and HASH may be present, we give priority
// to GNU_HASH as it is significantly faster.
elf::DT_HASH if hash_table.is_none() => {
let value = SysVHashTable::parse(NativeEndian, &mmap[relative_idx..])?;
hash_table = Some(HashTable::Sysv(value));
let header = unsafe { ptr.cast::<SysVHashHeader>().as_ref() }.unwrap();
let bucket_count = header.bucket_count.get(NativeEndian) as usize;
let chain_count = header.chain_count.get(NativeEndian) as usize;
let mut ptr = unsafe {
ptr.byte_add(size_of::<SysVHashHeader>())
.cast::<U32<NativeEndian>>()
};
let buckets = unsafe { slice::from_raw_parts(ptr, bucket_count) };
unsafe { ptr = ptr.add(bucket_count) };
let chains = unsafe { slice::from_raw_parts(ptr, chain_count) };
let table = SysVHashTable { buckets, chains };
hash_table = Some(HashTable::Sysv(table));
}
elf::DT_PLTGOT => {
@@ -771,14 +902,16 @@ impl DSO {
}
}
let strtab_offset = strtab_offset.expect("mandatory DT_STRTAB not present");
let strtab_size = strtab_size.expect("mandatory DT_STRSZ not present");
let hash_table = hash_table.expect("either DT_GNU_HASH and/or DT_HASH mut be present");
let strtab_offset = strtab_offset.expect("DT_STRTAB must be present");
let strtab_size = strtab_size.expect("DT_STRSZ must be present");
#[expect(clippy::unnecessary_cast, reason = "needed on i586")]
let dynstrtab = StringTable::new(
mmap,
strtab_offset as u64,
strtab_offset as u64 + strtab_size as u64,
unsafe { slice::from_raw_parts(mmap.byte_add(strtab_offset), strtab_size as usize) },
0,
strtab_size as u64,
);
let get_str = |entry: &Dyn| {
@@ -812,7 +945,6 @@ impl DSO {
let soname = soname.map(get_str).transpose()?;
let jmprel = jmprel.unwrap_or_default();
let hash_table = hash_table.expect("either DT_GNU_HASH and/or DT_HASH mut be present");
let init_array = unsafe { get_array(init_array_ptr, init_array_len) };
let fini_array = unsafe { get_array(fini_array_ptr, fini_array_len) };
@@ -889,8 +1021,6 @@ impl DSO {
}
fn static_relocate(&self, global_scope: &Scope, reloc: Relocation) -> object::Result<()> {
let b = self.mmap.as_ptr() as usize;
let (sym, my_sym) = if reloc.sym != STN_UNDEF {
let name = self.dynamic.symbol_name(reloc.sym).unwrap();
@@ -923,7 +1053,7 @@ impl DSO {
.unwrap_or((0, self));
let ptr = if self.pie {
(b + reloc.offset) as *mut u8
unsafe { self.base.byte_add(reloc.offset).cast_mut() }
} else {
reloc.offset as *mut u8
};
@@ -956,7 +1086,7 @@ impl DSO {
}
RelocationKind::GOT => set_usize(s),
RelocationKind::OFFSET => set_usize((s + a).wrapping_sub(p)),
RelocationKind::RELATIVE => set_usize(b + a),
RelocationKind::RELATIVE => set_usize(self.base as usize + a),
RelocationKind::SYMBOLIC => set_usize(s + a),
RelocationKind::TPOFF => {
assert!(
@@ -974,7 +1104,8 @@ impl DSO {
}
}
RelocationKind::IRELATIVE => unsafe {
let f: unsafe extern "C" fn() -> usize = core::mem::transmute(b + a);
let f: unsafe extern "C" fn() -> usize =
core::mem::transmute(self.base as usize + a);
set_usize(f());
},
RelocationKind::COPY => unsafe {
@@ -1007,7 +1138,6 @@ impl DSO {
return Ok(());
};
let object_base_addr = self.mmap.as_ptr() as usize;
let jmprel = self.dynamic.jmprel;
let pltrelsz = self.dynamic.pltrelsz;
@@ -1031,14 +1161,14 @@ impl DSO {
};
let ptr = if self.pie {
(object_base_addr + reloc.offset) as *mut usize
(self.base as usize + reloc.offset) as *mut usize
} else {
reloc.offset as *mut usize
};
match (reloc.kind, resolve) {
(RelocationKind::PLT, Resolve::Lazy) if self.pie => unsafe {
*ptr += object_base_addr;
*ptr += self.base as usize;
},
(RelocationKind::PLT, Resolve::Lazy) => {
@@ -1082,20 +1212,31 @@ impl DSO {
Ok(())
}
pub fn relocate(&self, ph: &[ProgramHeader], resolve: Resolve) -> object::Result<()> {
pub fn relocate(&self, ph: Option<&[ProgramHeader]>, resolve: Resolve) -> object::Result<()> {
let global_scope = GLOBAL_SCOPE.read();
let base = self.mmap.as_ptr();
unsafe {
apply_relr(base, self.dynamic.relr);
if !self.is_me {
unsafe {
apply_relr(self.base, self.dynamic.relr);
}
}
self.dynamic
.static_relocations()
.try_for_each(|reloc| self.static_relocate(&global_scope, reloc))?;
for reloc in self.dynamic.static_relocations() {
if reloc.kind == RelocationKind::RELATIVE && self.is_me {
continue;
}
self.static_relocate(&global_scope, reloc)?;
}
if self.is_me {
// TODO: assert that ld.so have no lazy relocations.
return Ok(());
}
self.lazy_relocate(&global_scope, resolve)?;
let ph = ph.unwrap();
// Protect pages
for ph in ph
.iter()
@@ -1120,7 +1261,7 @@ impl DSO {
unsafe {
let ptr = if self.pie {
self.mmap.as_ptr().add(vaddr)
self.base.add(vaddr)
} else {
vaddr as *const u8
};
@@ -1135,12 +1276,16 @@ impl DSO {
impl Drop for DSO {
fn drop(&mut self) {
if self.is_me {
return;
}
if self.is_ready.load(Ordering::SeqCst) {
// `run_fini` should not be called if we are being prematurely
// dropped (e.g. failed to satisfy dependencies).
self.run_fini();
unsafe {
self.run_fini();
}
}
unsafe { Sys::munmap(self.mmap.as_ptr() as *mut c_void, self.mmap.len()).unwrap() };
}
}
@@ -1309,3 +1454,7 @@ pub unsafe fn apply_relr(base: *const u8, relr: &[Relr]) {
}
}
}
// TODO: Add safety comment.
unsafe impl Send for DSO {}
unsafe impl Sync for DSO {}
+90 -75
View File
@@ -1,6 +1,5 @@
use alloc::{
collections::BTreeMap,
rc::Rc,
string::{String, ToString},
sync::{Arc, Weak},
vec::Vec,
@@ -12,13 +11,9 @@ use object::{
read::elf::{Rela as _, Sym},
};
use core::{
cell::RefCell,
ptr::{self, NonNull},
};
use core::ptr;
use crate::{
ALLOCATOR,
c_str::{CStr, CString},
error::Errno,
header::{
@@ -26,7 +21,7 @@ use crate::{
fcntl, sys_mman,
unistd::F_OK,
},
ld_so::dso::SymbolBinding,
ld_so::dso::{Dyn, SymbolBinding},
out::Out,
platform::{
Pal, Sys,
@@ -43,7 +38,6 @@ use super::dso::Rela;
use super::{
PATH_SEP,
access::accessible,
callbacks::LinkerCallbacks,
debug::{_dl_debug_state, _r_debug, RTLDState},
dso::{DSO, ProgramHeader},
tcb::{Master, Tcb},
@@ -328,41 +322,6 @@ impl Scope {
}
}
// Used by dlfcn.h
//
// We need this as the handle must be created and destroyed with the dynamic
// linker's allocator.
pub struct ObjectHandle(*const DSO);
impl ObjectHandle {
#[inline]
fn new(obj: Arc<DSO>) -> Self {
Self(Arc::into_raw(obj))
}
#[inline]
fn into_inner(self) -> Arc<DSO> {
unsafe { Arc::from_raw(self.0) }
}
#[inline]
pub fn as_ptr(&self) -> *const c_void {
self.0.cast()
}
#[inline]
pub fn from_ptr(ptr: *const c_void) -> Option<Self> {
NonNull::new(ptr as *mut DSO).map(|ptr| Self(ptr.as_ptr()))
}
}
impl AsRef<DSO> for ObjectHandle {
#[inline]
fn as_ref(&self) -> &DSO {
unsafe { &*self.0 }
}
}
bitflags::bitflags! {
#[derive(Debug, Default)]
pub struct DebugFlags: u32 {
@@ -417,29 +376,36 @@ impl Config {
}
}
pub struct Me {
pub base: *const u8,
pub phdrs: &'static [ProgramHeader],
pub dyns: &'static [Dyn],
}
pub struct Linker {
config: Config,
me: Me,
next_object_id: usize,
next_tls_module_id: usize,
tls_size: usize,
objects: BTreeMap<usize, Arc<DSO>>,
name_to_object_id_map: BTreeMap<String, usize>,
pub cbs: Rc<RefCell<LinkerCallbacks>>,
}
const ROOT_ID: usize = 1;
impl Linker {
pub fn new(config: Config) -> Self {
pub fn new(me: Me, config: Config) -> Self {
Self {
me,
config,
next_object_id: ROOT_ID,
next_tls_module_id: 1,
tls_size: 0,
objects: BTreeMap::new(),
name_to_object_id_map: BTreeMap::new(),
cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
}
}
@@ -465,7 +431,7 @@ impl Linker {
resolve: Resolve,
scope: ScopeKind,
noload: bool,
) -> Result<ObjectHandle> {
) -> Result<Arc<DSO>> {
log::trace!(
"[ld.so] load_library(name={:?}, resolve={:#?}, scope={:#?}, noload={})",
name,
@@ -500,14 +466,14 @@ impl Linker {
self.scope_debug();
}
Ok(ObjectHandle::new(obj.clone()))
Ok(obj.clone())
} else if !noload {
let parent_runpath = &self
.objects
.get(&ROOT_ID)
.and_then(|parent| parent.runpath().cloned());
Ok(ObjectHandle::new(self.load_object(
Ok(self.load_object(
name,
parent_runpath,
None,
@@ -518,29 +484,24 @@ impl Linker {
resolve
},
scope,
)?))
)?)
} else {
// FIXME: LoadError?
// Err(Error::Malformed(format!(
// "object '{}' has not yet been loaded",
// name
// )))
Ok(ObjectHandle(ptr::null()))
Err(DlError::NotFound)
}
}
None => match self.objects.get(&ROOT_ID) {
Some(obj) => Ok(ObjectHandle::new(obj.clone())),
Some(obj) => Ok(obj.clone()),
None => Err(DlError::NotFound),
},
}
}
pub fn get_sym(&self, handle: Option<ObjectHandle>, name: &str) -> Option<*mut c_void> {
pub fn get_sym(&self, handle: Option<&DSO>, name: &str) -> Option<*mut c_void> {
let guard;
if let Some(handle) = handle.as_ref() {
handle.as_ref().scope()
if let Some(handle) = handle {
handle.scope()
} else {
guard = GLOBAL_SCOPE.read();
&guard
@@ -560,8 +521,7 @@ impl Linker {
})
}
pub fn unload(&mut self, handle: ObjectHandle) {
let obj = handle.into_inner();
pub fn unload(&mut self, obj: Arc<DSO>) {
if !obj.dlopened {
return;
}
@@ -590,7 +550,7 @@ impl Linker {
if let Some(name) = self.name_to_object_id_map.get(*dep)
&& let Some(object_name) = self.objects.get(name)
{
self.unload(ObjectHandle::new(object_name.clone()));
self.unload(object_name.clone());
}
}
self.name_to_object_id_map.remove(&obj.name);
@@ -603,7 +563,9 @@ impl Linker {
pub fn fini(&self) {
for obj in self.objects.values() {
obj.run_fini();
unsafe {
obj.run_fini();
}
}
}
@@ -642,7 +604,7 @@ impl Linker {
)?;
for (i, obj) in new_objects.iter().enumerate() {
obj.relocate(&objects_data[i], resolve).unwrap();
obj.relocate(objects_data[i].as_deref(), resolve).unwrap();
}
unsafe {
@@ -664,14 +626,18 @@ impl Linker {
let new_tcb_len = new_tcb.generic.tcb_len;
// Unmap just the TCB page.
Sys::munmap(new_tcb as *mut Tcb as *mut c_void, syscall::PAGE_SIZE).unwrap();
Sys::munmap(
core::ptr::from_mut::<Tcb>(new_tcb).cast::<c_void>(),
syscall::PAGE_SIZE,
)
.unwrap();
let new_addr = ptr::addr_of!(*new_tcb) as usize;
assert_eq!(
syscall::syscall5(
syscall::SYS_MREMAP,
old_tcb as *mut Tcb as usize,
core::ptr::from_mut::<Tcb>(old_tcb) as usize,
syscall::PAGE_SIZE,
new_addr,
syscall::PAGE_SIZE,
@@ -692,7 +658,11 @@ impl Linker {
new_tcb.generic.tcb_len = new_tcb_len;
drop(_guard);
(new_tcb, old_tcb as *mut Tcb as *mut c_void, thr_fd)
(
new_tcb,
core::ptr::from_mut::<Tcb>(old_tcb).cast::<c_void>(),
thr_fd,
)
};
#[cfg(not(target_os = "redox"))]
@@ -735,7 +705,6 @@ impl Linker {
#[cfg(target_os = "redox")]
Some(thr_fd),
);
tcb.mspace = ALLOCATOR.get();
#[cfg(target_os = "redox")]
{
@@ -751,7 +720,10 @@ impl Linker {
}
for obj in new_objects.into_iter() {
obj.mark_ready();
// SAFETY: `obj` and its dependencies have been successfuly loaded.
unsafe {
obj.mark_ready();
}
self.run_init(&obj);
self.register_object(obj);
}
@@ -788,7 +760,7 @@ impl Linker {
base_addr: Option<usize>,
dlopened: bool,
new_objects: &mut Vec<Arc<DSO>>,
objects_data: &mut Vec<Vec<ProgramHeader>>,
objects_data: &mut Vec<Option<Vec<ProgramHeader>>>,
tcb_masters: &mut Vec<Master>,
// Scope of the object that caused this object to be loaded.
dependent_scope: Option<&mut Scope>,
@@ -821,6 +793,49 @@ impl Linker {
let debug = self.config.debug_flags.contains(DebugFlags::LOAD);
if name == "libc.so.6" || name == "libc.so" {
if debug {
println!(
"[ld.so]: loading libc.so.6 (aka. ld.so) at {:#?}",
self.me.base
);
}
let (me, master) = DSO::from_raw(
self.me.base,
self.me.dyns,
self.me.phdrs,
self.next_object_id,
self.next_tls_module_id,
self.tls_size.next_multiple_of(16),
);
self.tls_size = master.offset;
self.next_tls_module_id += 1;
self.next_object_id += 1;
let obj = Arc::new(me);
tcb_masters.push(master);
objects_data.push(None);
new_objects.push(obj.clone());
if let Some(dependent_scope) = dependent_scope {
match scope_kind {
ScopeKind::Local => dependent_scope.add(&obj),
ScopeKind::Global => GLOBAL_SCOPE.write().add(&obj),
}
} else if let ScopeKind::Global = scope_kind {
GLOBAL_SCOPE.write().add(&obj);
}
let mut scope = Scope::local();
scope.set_owner(Arc::downgrade(&obj));
obj.scope.call_once(|| scope);
return Ok(obj);
}
let path = self.search_object(name, parent_runpath)?;
let file = self.read_file(&path)?;
let data = file.data();
@@ -846,8 +861,8 @@ impl Linker {
eprintln!(
"[ld.so]: loading object: {} at {:#x}:{:#x} (pie: {})",
name,
obj.mmap.as_ptr() as usize,
obj.mmap.as_ptr() as usize + obj.mmap.len(),
obj.mmap.as_ref().unwrap().as_ptr() as usize,
obj.mmap.as_ref().unwrap().as_ptr() as usize + obj.mmap.as_ref().unwrap().size(),
obj.pie,
);
}
@@ -896,7 +911,7 @@ impl Linker {
)?;
}
objects_data.push(elf);
objects_data.push(Some(elf));
new_objects.push(obj.clone());
scope.set_owner(Arc::downgrade(&obj));
@@ -1011,7 +1026,7 @@ impl Linker {
#[cfg(target_pointer_width = "64")]
extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) -> *mut c_void {
let obj = unsafe { &*obj };
let obj_base = obj.mmap.as_ptr() as usize;
let obj_base = obj.base as usize;
let jmprel = obj.dynamic.jmprel;
let rela = unsafe { &*(jmprel as *const Rela).add(relocation_index as usize) };
+1 -2
View File
@@ -21,9 +21,8 @@ use crate::{
pub const PATH_SEP: char = ':';
mod access;
pub mod callbacks;
pub mod debug;
mod dso;
pub mod dso;
pub mod linker;
pub mod start;
pub mod tcb;
+45 -20
View File
@@ -1,6 +1,6 @@
// Start code adapted from https://gitlab.redox-os.org/redox-os/relibc/blob/master/src/start.rs
use core::slice;
use core::{slice, str::FromStr};
use alloc::{
borrow::ToOwned,
@@ -9,10 +9,11 @@ use alloc::{
string::{String, ToString},
vec::Vec,
};
use log::LevelFilter;
use object::{
NativeEndian,
elf::{self, PT_DYNAMIC, PT_PHDR},
read::elf::{Dyn as _, ProgramHeader as _},
read::elf::{Dyn as _, FileHeader as _, ProgramHeader as _},
};
use crate::{
@@ -23,12 +24,12 @@ use crate::{
},
ld_so::{
dso::{
DT_RELR, DT_RELRENT, DT_RELRSZ, Dyn, ProgramHeader, Rel, Rela, Relocation,
DT_RELR, DT_RELRENT, DT_RELRSZ, Dyn, FileHeader, ProgramHeader, Rel, Rela, Relocation,
RelocationKind, Relr, apply_relr,
},
linker::DebugFlags,
linker::{DebugFlags, Me},
},
platform::{auxv_iter, get_auxvs, types::c_char},
platform::{auxv_iter, get_auxvs, logger::RELIBC_LOG_ENV_VAR, types::c_char},
start::Stack,
sync::mutex::Mutex,
};
@@ -41,12 +42,6 @@ use super::{
tcb::Tcb,
};
#[cfg(target_pointer_width = "32")]
pub const SIZEOF_EHDR: usize = 52;
#[cfg(target_pointer_width = "64")]
pub const SIZEOF_EHDR: usize = 64;
unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
//traverse the stack and collect argument vector
let mut argv = Vec::new();
@@ -211,7 +206,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
let is_manual = at_entry == ld_entry; // Whether the dynamic linker was invoked as a command.
let mut i = dynamic;
let mut i = 0;
let mut rela_ptr = None;
let mut rela_len = None;
let mut relr_ptr = None;
@@ -219,7 +214,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
let mut rel_ptr = None;
let mut rel_len = None;
loop {
let entry = unsafe { &*i };
let entry = unsafe { &*dynamic.add(i) };
let val = entry.d_val(NativeEndian);
let ptr = val as *const u8;
match entry.d_tag(NativeEndian) as u32 {
@@ -241,9 +236,11 @@ pub unsafe extern "C" fn relibc_ld_so_start(
}
_ => {}
}
i = unsafe { i.add(1) };
i += 1;
}
let dyns = unsafe { slice::from_raw_parts(dynamic, i) };
unsafe fn get_array<'a, T>(
ptr: Option<*const T>,
len: Option<usize>,
@@ -251,7 +248,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
) -> &'a [T] {
if let Some(ptr) = ptr {
let len = len.expect("dynamic entry was present without it's corresponding size");
unsafe { core::slice::from_raw_parts(ptr.byte_add(base_addr), len) }
unsafe { slice::from_raw_parts(ptr.byte_add(base_addr), len) }
} else {
&[]
}
@@ -298,7 +295,23 @@ pub unsafe extern "C" fn relibc_ld_so_start(
}
}
stage2(sp, self_base, is_manual, base_addr)
unsafe extern "C" {
safe static __ehdr_start: FileHeader;
}
let ph_off = __ehdr_start.e_phoff(NativeEndian) as usize;
let ph_num = __ehdr_start.e_phnum(NativeEndian) as usize;
let my_phdrs = unsafe {
slice::from_raw_parts(
core::ptr::addr_of!(__ehdr_start)
.byte_add(ph_off)
.cast::<ProgramHeader>(),
ph_num,
)
};
stage2(sp, self_base, is_manual, base_addr, dyns, my_phdrs)
}
fn stage2(
@@ -306,6 +319,8 @@ fn stage2(
self_base: usize,
is_manual: bool,
base_addr: Option<usize>,
my_dyns: &'static [Dyn],
my_phdrs: &'static [ProgramHeader],
) -> usize {
// Setup TCB for ourselves.
unsafe {
@@ -392,9 +407,12 @@ fn stage2(
.collect::<Vec<_>>(),
);
crate::platform::environ = crate::platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr();
crate::platform::logger::init();
if let Some(env) = envs.get(RELIBC_LOG_ENV_VAR.to_str().unwrap())
&& let Ok(level) = LevelFilter::from_str(env)
&& let Err(_) = crate::platform::logger::init(level)
{
log::error!("Logger has already been initialised");
}
}
// we might need global lock for this kind of stuff
@@ -435,7 +453,14 @@ fn stage2(
}
}
let mut linker = Linker::new(config);
let mut linker = Linker::new(
Me {
base: self_base as *const u8,
phdrs: my_phdrs,
dyns: my_dyns,
},
config,
);
let entry = match linker.load_program(&path, base_addr) {
Ok(entry) => entry,
Err(err) => {
+1 -4
View File
@@ -11,7 +11,7 @@ use generic_rt::GenericTcb;
use crate::{
header::sys_mman,
ld_so::linker::Linker,
platform::{Dlmalloc, Pal, Sys},
platform::{Pal, Sys},
pthread::{OsTid, Pthread},
sync::{mutex::Mutex, waitval::Waitval},
};
@@ -56,8 +56,6 @@ pub struct Tcb {
pub num_copied_masters: usize,
/// Pointer to dynamic linker
pub linker_ptr: *const Mutex<Linker>,
/// pointer to rust memory allocator structure
pub mspace: *const Mutex<Dlmalloc>,
/// Underlying pthread_t struct, pthread_self() returns &self.pthread
pub pthread: Pthread,
@@ -98,7 +96,6 @@ impl Tcb {
masters_len: 0,
num_copied_masters: 0,
linker_ptr: ptr::null(),
mspace: ptr::null(),
pthread: Pthread {
waitval: Waitval::new(),
flags: Default::default(),
+1
View File
@@ -117,6 +117,7 @@ macro_rules! trace_expr {
// log::trace! but functions inside them will
// not be evaluated or compiled unless enabled
#[cfg(target_os = "redox")] // currently only used in redox
macro_rules! trace_log {
($($arg:tt)+) => {
#[cfg(not(feature = "no_trace"))]
+6 -20
View File
@@ -3,8 +3,7 @@ use core::{
cell::SyncUnsafeCell,
cmp,
mem::align_of,
ptr::{self, copy_nonoverlapping, write_bytes},
sync::atomic::{AtomicPtr, Ordering},
ptr::{copy_nonoverlapping, write_bytes},
};
mod sys;
@@ -17,31 +16,18 @@ pub type Dlmalloc = DlmallocCApi<sys::System>;
#[allow(clippy::declare_interior_mutable_const)]
pub const NEWALLOCATOR: Allocator = Allocator::new();
pub struct Allocator {
inner: SyncUnsafeCell<Mutex<Dlmalloc>>,
pub ptr: AtomicPtr<Mutex<Dlmalloc>>,
}
pub struct Allocator(SyncUnsafeCell<Mutex<Dlmalloc>>);
impl Allocator {
#[allow(clippy::new_without_default)]
pub const fn new() -> Self {
Allocator {
inner: SyncUnsafeCell::new(Mutex::new(Dlmalloc::new(sys::System::new()))),
ptr: AtomicPtr::new(ptr::null_mut()),
}
Self(SyncUnsafeCell::new(Mutex::new(Dlmalloc::new(
sys::System::new(),
))))
}
pub fn get(&self) -> *const Mutex<Dlmalloc> {
let ptr = self.ptr.load(Ordering::Acquire);
if !ptr.is_null() {
return ptr;
}
self.inner.get()
}
pub fn set(&self, mspace: *const Mutex<Dlmalloc>) {
self.ptr.store(mspace.cast_mut(), Ordering::Release);
self.0.get()
}
}
+15 -16
View File
@@ -1,36 +1,33 @@
use core::{fmt, str::FromStr};
use core::fmt;
use crate::{c_str::CStr, io::prelude::*, sync::Mutex};
use alloc::string::{String, ToString};
use log::{Metadata, Record};
use log::{LevelFilter, Metadata, Record, SetLoggerError};
const DEFAULT_LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info;
pub unsafe fn init() {
pub const RELIBC_LOG_ENV_VAR: &core::ffi::CStr = c"RELIBC_LOG_LEVEL";
pub unsafe fn init(level: LevelFilter) -> Result<(), SetLoggerError> {
let mut logger = RedoxLogger::new();
let log_env = c"RELIBC_LOG_LEVEL".as_ptr();
#[cfg(feature = "no_trace")]
let mut trace_warn = false;
unsafe {
if let Some(env) = CStr::from_nullable_ptr(crate::header::stdlib::getenv(log_env))
&& let Ok(level) = log::LevelFilter::from_str(env.to_str().unwrap_or(""))
{
#[cfg(feature = "no_trace")]
if level == log::LevelFilter::Trace {
trace_warn = true;
}
logger = logger.with_output(OutputBuilder::stderr().with_filter(level).build());
#[cfg(feature = "no_trace")]
if level == log::LevelFilter::Trace {
trace_warn = true;
}
logger = logger.with_output(OutputBuilder::stderr().with_filter(level).build());
if let Some(name) = CStr::from_nullable_ptr(crate::platform::program_invocation_short_name)
{
logger = logger.with_process_name(name.to_str().unwrap_or("").to_string());
}
}
if logger.enable().is_err() {
log::error!("Logger already initialized");
}
logger.enable()?;
#[cfg(feature = "no_trace")]
if trace_warn {
@@ -38,6 +35,8 @@ pub unsafe fn init() {
"The 'no_trace' feature is enabled but RELIBC_LOG_LEVEL=TRACE, there will be no trace logs"
);
}
Ok(())
}
/// Copied from redox_log crate with some modifications, in future we might use it instead?
+4 -5
View File
@@ -102,13 +102,12 @@ impl PalEpoll for Sys {
};
let callback = || {
let res = syscall::read(epfd as usize, unsafe {
syscall::read(epfd as usize, unsafe {
slice::from_raw_parts_mut(
events as *mut u8,
events.cast::<u8>(),
maxevents as usize * mem::size_of::<syscall::Event>(),
)
});
res
})
};
let bytes_read = if sigset.is_null() {
@@ -126,7 +125,7 @@ impl PalEpoll for Sys {
unsafe {
let event_ptr = events.add(i);
let target_ptr = events.add(count);
let event = *(event_ptr as *mut Event);
let event = *event_ptr.cast::<Event>();
*target_ptr = epoll_event {
events: event_flags_to_epoll(event.flags),
data: epoll_data {
+4 -4
View File
@@ -31,7 +31,7 @@ fn fexec_impl(
interp_override: new_interp_override,
} = redox_rt::proc::fexec_impl(
exec_file,
&RtTcb::current().thread_fd(),
RtTcb::current().thread_fd(),
redox_rt::current_proc_fd(),
path,
args,
@@ -49,11 +49,11 @@ fn fexec_impl(
// null-terminated. Violating this should therefore give the "format error" ENOEXEC.
let path_cstr = CStr::from_bytes_with_nul(&path).map_err(|_| Error::new(ENOEXEC))?;
return execve(
execve(
Executable::AtPath(path_cstr),
ArgEnv::Parsed { args, envs },
Some(new_interp_override),
);
)
}
pub enum ArgEnv<'a> {
@@ -166,7 +166,7 @@ pub fn execve(
let mut args: Vec<&[u8]> = Vec::with_capacity(len);
if let Some(interpreter) = &interpreter_path {
image_file = File::open(CStr::borrow(&interpreter), O_RDONLY as c_int)
image_file = File::open(CStr::borrow(interpreter), O_RDONLY as c_int)
.map_err(|_| Error::new(ENOENT))?;
// Push interpreter to arguments
+1 -1
View File
@@ -9,7 +9,7 @@ use syscall::{F_SETFD, F_SETFL, O_CLOEXEC, O_RDONLY, O_WRONLY};
#[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t {
syscall::fpath(fd as usize, unsafe {
slice::from_raw_parts_mut(buf as *mut u8, count)
slice::from_raw_parts_mut(buf.cast::<u8>(), count)
})
.map_err(Errno::from)
.map(|l| l as ssize_t)
+4 -5
View File
@@ -1,8 +1,7 @@
use crate::{c_str::CStr, header::stdlib::getenv, platform::types::*};
use core::ptr;
use crate::{c_str::CStr, header::stdlib::getenv, platform::types::c_char};
use syscall::{EIO, ENOENT, Error, Result, flag::*};
pub const LIBC_SCHEME: &'static str = "libc:";
pub const LIBC_SCHEME: &str = "libc:";
const ENV_MAX_LEN: i32 = i32::MAX;
@@ -10,8 +9,8 @@ macro_rules! env_str {
($lit:expr) => {
#[allow(unused_unsafe)]
{
let val_bytes = unsafe { getenv(concat!($lit, "\0").as_ptr() as *const c_char) };
if val_bytes != ptr::null_mut() {
let val_bytes = unsafe { getenv(concat!($lit, "\0").as_ptr().cast::<c_char>()) };
if !val_bytes.is_null() {
if let Ok(val_str) = unsafe { CStr::from_ptr(val_bytes) }.to_str() {
Some(val_str)
} else {
+17 -11
View File
@@ -31,7 +31,7 @@ pub fn openat(dirfd: c_int, path: RedoxStr<'_>, oflag: c_int, mode: mode_t) -> R
((oflag as usize) & 0xFFFF_0000) | ((mode as usize) & 0xFFFF),
)?;
if let Err(_) = c_int::try_from(usize_fd) {
if c_int::try_from(usize_fd).is_err() {
let _ = redox_rt::sys::close(usize_fd);
return Err(Error::new(EMFILE));
}
@@ -42,7 +42,7 @@ pub fn fchmod(fd: usize, new_mode: u16) -> Result<()> {
std_fs_call_wo(
fd,
&[],
&StdFsCallMeta::new(StdFsCallKind::Fchmod, new_mode as u64, 0),
&StdFsCallMeta::new(StdFsCallKind::Fchmod, u64::from(new_mode), 0),
)?;
Ok(())
}
@@ -77,7 +77,7 @@ pub fn getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
}) => (),
other => {
//println!("REAL GETDENTS {:?}", other);
return Ok(other?);
return other;
}
}
@@ -87,7 +87,7 @@ pub fn getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
let (header, name) = buf.split_at_mut(mem::size_of::<DirentHeader>());
let bytes_read = Sys::pread(fd as c_int, name, opaque as i64)? as usize;
let bytes_read = Sys::pread(fd as c_int, name, opaque as i64)?;
if bytes_read == 0 {
return Ok(0);
}
@@ -122,14 +122,21 @@ pub unsafe fn fstat(fd: usize, buf: *mut crate::header::sys_stat::stat) -> Resul
if let Some(buf) = unsafe { buf.as_mut() } {
buf.st_dev = redox_buf.st_dev as dev_t;
buf.st_ino = redox_buf.st_ino as ino_t;
buf.st_nlink = redox_buf.st_nlink as nlink_t;
buf.st_nlink = nlink_t::from(redox_buf.st_nlink);
buf.st_mode = redox_buf.st_mode as mode_t;
buf.st_uid = redox_buf.st_uid as uid_t;
buf.st_gid = redox_buf.st_gid as gid_t;
// TODO st_rdev
buf.st_rdev = 0;
buf.st_size = redox_buf.st_size as off_t;
buf.st_blksize = redox_buf.st_blksize as blksize_t;
#[cfg(target_pointer_width = "32")]
{
buf.st_blksize = redox_buf.st_blksize as blksize_t;
}
#[cfg(target_pointer_width = "64")]
{
buf.st_blksize = blksize_t::from(redox_buf.st_blksize);
}
buf.st_blocks = redox_buf.st_blocks as blkcnt_t;
buf.st_atim = timespec {
tv_sec: redox_buf.st_atime as time_t,
@@ -202,7 +209,7 @@ pub unsafe fn futimens(fd: usize, times: *const timespec) -> Result<()> {
};
let redox_buf = unsafe {
slice::from_raw_parts(
times.as_ptr() as *const u8,
times.as_ptr().cast::<u8>(),
times.len() * mem::size_of::<syscall::TimeSpec>(),
)
};
@@ -215,7 +222,7 @@ pub unsafe fn futimens(fd: usize, times: *const timespec) -> Result<()> {
}
pub fn clock_gettime(clock: usize, mut tp: Out<timespec>) -> Result<()> {
let mut redox_tp = syscall::TimeSpec::default();
syscall::clock_gettime(clock as usize, &mut redox_tp)?;
syscall::clock_gettime(clock, &mut redox_tp)?;
tp.write((&redox_tp).into());
Ok(())
}
@@ -228,9 +235,8 @@ pub unsafe extern "C" fn redox_open_v1(
mode: u16,
) -> RawResult {
let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
let path = match RedoxStr::new(path) {
Some(path) => path,
None => return Error::mux(Err(Error::new(EINVAL))),
let Some(path) = RedoxStr::new(path) else {
return Error::mux(Err(Error::new(EINVAL)));
};
Error::mux(openat(AT_FDCWD, path, flags as c_int, mode as mode_t))
}
+49 -40
View File
@@ -171,7 +171,7 @@ impl Pal for Sys {
let perms = (if stat.st_uid == uid {
stat.st_mode >> (3 * 2)
} else if stat.st_gid == gid {
stat.st_mode >> (3 * 1)
stat.st_mode >> 3
} else {
stat.st_mode
}) & 0o7;
@@ -204,7 +204,7 @@ impl Pal for Sys {
unsafe {
BRK_CUR = allocated;
BRK_END = (allocated as *mut u8).add(BRK_MAX_SIZE) as *mut c_void
BRK_END = allocated.cast::<u8>().add(BRK_MAX_SIZE).cast::<c_void>()
};
}
@@ -222,7 +222,7 @@ impl Pal for Sys {
}
fn chdir(path: CStr) -> Result<()> {
let path = RedoxStr::new_c(path.to_cstr()).ok_or_else(|| Errno(EINVAL))?;
let path = RedoxStr::new_c(path.to_cstr()).ok_or(Errno(EINVAL))?;
path::chdir(path)?;
Ok(())
}
@@ -243,11 +243,11 @@ impl Pal for Sys {
CLOCK_MONOTONIC => "/scheme/time/4/getres",
_ => return Err(Errno(EINVAL)),
};
let timerfd = FdGuard::open(&path, syscall::O_RDONLY)?;
let timerfd = FdGuard::open(path, syscall::O_RDONLY)?;
let mut redox_res = timespec::default();
let buffer = unsafe {
slice::from_raw_parts_mut(
&mut redox_res as *mut _ as *mut u8,
(&raw mut redox_res).cast::<u8>(),
mem::size_of::<timespec>(),
)
};
@@ -285,8 +285,7 @@ impl Pal for Sys {
}
fn exit(status: c_int) -> ! {
let _ = redox_rt::sys::posix_exit(status);
loop {}
redox_rt::sys::posix_exit(status)
}
unsafe fn execve(path: CStr, argv: *const *mut c_char, envp: *const *mut c_char) -> Result<()> {
@@ -382,7 +381,7 @@ impl Pal for Sys {
let start = start as u64 | if is_ofd { 1 << 63 } else { 0 };
let len = len as u64;
match flock.l_type as i32 {
match i32::from(flock.l_type) {
F_UNLCK => {
let meta = StdFsCallMeta::new(StdFsCallKind::Unlock, start, len);
syscall::std_fs_call(fd as usize, &mut [], &meta)?;
@@ -393,7 +392,7 @@ impl Pal for Sys {
let meta = StdFsCallMeta::new(
StdFsCallKind::Lock,
start,
len | if flock.l_type as i32 == F_WRLCK {
len | if i32::from(flock.l_type) == F_WRLCK {
1 << 63
} else {
0
@@ -429,7 +428,7 @@ impl Pal for Sys {
}
let mut len = len as u64;
if flock.l_type as i32 == F_WRLCK {
if i32::from(flock.l_type) == F_WRLCK {
len |= 1 << 63;
}
@@ -562,7 +561,7 @@ impl Pal for Sys {
#[inline]
unsafe fn futex_wait(addr: *mut u32, val: u32, deadline: Option<&timespec>) -> Result<()> {
let deadline = deadline.map(|d| syscall::TimeSpec::from(d));
let deadline = deadline.map(syscall::TimeSpec::from);
(unsafe { redox_rt::sys::sys_futex_wait(addr, val, deadline.as_ref()) })?;
Ok(())
}
@@ -611,7 +610,7 @@ impl Pal for Sys {
// NOTE: fn is unsafe, but this just means we can assume more things. impl is safe
unsafe fn dent_reclen_offset(this_dent: &[u8], offset: usize) -> Option<(u16, u64)> {
let mut header = DirentHeader::default();
header.copy_from_slice(&this_dent.get(..size_of::<DirentHeader>())?);
header.copy_from_slice(this_dent.get(..size_of::<DirentHeader>())?);
// If scheme does not send a NUL byte, this shouldn't be able to cause UB for the caller.
if this_dent.get(usize::from(header.record_len) - 1) != Some(&b'\0') {
@@ -665,7 +664,7 @@ impl Pal for Sys {
}
if found {
if !list.is_empty() && (count as usize) < list.len() {
if !list.is_empty() && count < list.len() {
list.index(count).write(grp.gr_gid);
}
count += 1;
@@ -674,7 +673,7 @@ impl Pal for Sys {
grp::endgrent();
}
if !list.is_empty() && (count as usize) > list.len() {
if !list.is_empty() && count > list.len() {
return Err(Errno(EINVAL));
}
@@ -698,9 +697,9 @@ impl Pal for Sys {
}
fn getpriority(which: c_int, who: id_t) -> Result<c_int> {
match redox_rt::sys::posix_getpriority(which, who as u32) {
match redox_rt::sys::posix_getpriority(which, who) {
Ok(kernel_prio) => {
let posix_prio = (kernel_prio as i32 * -1) + 40 as i32;
let posix_prio = -(kernel_prio as i32) + 40_i32;
Ok(posix_prio)
}
Err(e) => Err(Errno(e.errno)),
@@ -851,7 +850,7 @@ impl Pal for Sys {
if (flags & !(AT_SYMLINK_FOLLOW)) != 0 {
return Err(Errno(EINVAL));
}
let newpath = RedoxStr::new_c(newpath.to_cstr()).ok_or_else(|| Errno(EINVAL))?;
let newpath = RedoxStr::new_c(newpath.to_cstr()).ok_or(Errno(EINVAL))?;
// By default, we don't follow the symlink if there is one.
// We only follow it if AT_SYMLINK_FOLLOW is passed in flags.
@@ -992,7 +991,7 @@ impl Pal for Sys {
redox_rmtp = unsafe { (&*rmtp).into() };
}
match redox_rt::sys::posix_nanosleep(&redox_rqtp, &mut redox_rmtp) {
Ok(_) => Ok(()),
Ok(()) => Ok(()),
Err(Error { errno: EINTR }) => {
unsafe {
if !rmtp.is_null() {
@@ -1040,7 +1039,7 @@ impl Pal for Sys {
let total_offset = offset.checked_add(length).ok_or(Errno(EFBIG))?;
let mut stat: stat = unsafe { mem::zeroed() };
unsafe { libredox::fstat(fd as usize, &mut stat)? };
unsafe { libredox::fstat(fd as usize, &raw mut stat)? };
let st_size = stat.st_size as u64;
// The difference between total_offset and the file size is the number of bytes to
// allocate. So, if it's negative then the file is already large enough and we don't
@@ -1129,7 +1128,7 @@ impl Pal for Sys {
let redox_path = str::from_utf8(&buf[..count])
.ok()
.and_then(|x| redox_path::RedoxPath::from_absolute(x))
.and_then(redox_path::RedoxPath::from_absolute)
.ok_or(Errno(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().ok_or(Errno(EINVAL))?;
@@ -1216,8 +1215,8 @@ impl Pal for Sys {
let clamped_prio = prio.clamp(-20, 19);
let kernel_prio = (20 + clamped_prio) as u32;
match redox_rt::sys::posix_setpriority(which, who as u32, kernel_prio) {
Ok(_) => Ok(()),
match redox_rt::sys::posix_setpriority(which, who, kernel_prio) {
Ok(()) => Ok(()),
Err(e) => Err(Errno(e.errno)),
}
}
@@ -1290,7 +1289,7 @@ impl Pal for Sys {
}
}
args[0] = &program.to_bytes();
args[0] = program.to_bytes();
let new_file_table = child.thr_fd.dup_into_upper(b"filetable-binary")?;
@@ -1606,7 +1605,7 @@ impl Pal for Sys {
CLOCK_MONOTONIC => "/scheme/time/4",
_ => return Err(Errno(EINVAL)),
};
let timerfd = FdGuard::open_into_upper(&path, syscall::O_RDWR)?;
let timerfd = FdGuard::open_into_upper(path, syscall::O_RDWR)?;
let eventfd = FdGuard::new(Error::demux(unsafe {
event::redox_event_queue_create_v1(0)
})?)
@@ -1627,7 +1626,7 @@ impl Pal for Sys {
let mut memory_pointer: *mut timer_internal_t = ptr::null_mut();
unsafe {
let result = posix_memalign(
(&mut memory_pointer as *mut *mut timer_internal_t).cast(),
(&raw mut memory_pointer).cast(),
align_of::<timer_internal_t>(),
size_of::<timer_internal_t>(),
);
@@ -1653,36 +1652,44 @@ impl Pal for Sys {
Ok(())
}
#[expect(clippy::not_unsafe_ptr_arg_deref)]
fn timer_delete(timerid: timer_t) -> Result<()> {
let timers = &mut TIMERS.lock().0;
let removed = timers.remove(&timerid);
if !removed {
return Err(Errno(EINVAL));
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
let timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let _ = redox_rt::sys::close(timer_st.timerfd);
let _ = redox_rt::sys::close(timer_st.eventfd);
if !timer_st.thread.is_null() {
let _ = unsafe { pthread_cancel(timer_st.thread) };
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
unsafe { free(timerid) };
Ok(())
}
#[expect(clippy::not_unsafe_ptr_arg_deref)]
fn timer_gettime(timerid: timer_t, mut value: Out<itimerspec>) -> Result<()> {
let timers = &mut TIMERS.lock().0;
if !timers.contains(&timerid) {
return Err(Errno(EINVAL));
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
let timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let mut now = timespec::default();
Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?;
if timer_st.evp.sigev_notify == SIGEV_NONE {
if timespec::subtract(&timer_st.next_wake_time.it_value, &now).is_none() {
// error here means the timer is disarmed
let _ = timer_update_wake_time(timer_st);
}
if timer_st.evp.sigev_notify == SIGEV_NONE
&& timespec::subtract(&timer_st.next_wake_time.it_value, &now).is_none()
{
// error here means the timer is disarmed
let _ = timer_update_wake_time(timer_st);
}
let remaining = &timer_st.next_wake_time.it_value;
value.write(if remaining.is_zero() {
@@ -1698,6 +1705,7 @@ impl Pal for Sys {
Ok(())
}
#[expect(clippy::not_unsafe_ptr_arg_deref)]
fn timer_settime(
timerid: timer_t,
flags: c_int,
@@ -1712,6 +1720,8 @@ impl Pal for Sys {
if !timers.contains(&timerid) {
return Err(Errno(EINVAL));
}
// SAFETY: `timerid` should have already been created via `timer_create()`
// before calling `timer_delete()` so should not be NULL
let timer_st = unsafe { timer_internal_t::from_raw(timerid) };
if value.it_value.is_zero() {
@@ -1747,10 +1757,10 @@ impl Pal for Sys {
let mut tid = pthread_t::default();
let result = unsafe {
pthread_create(
&mut tid as *mut _,
&raw mut tid,
ptr::null(),
timer_routine,
timerid as *mut c_void,
timerid.cast::<c_void>(),
)
};
if result != 0 {
@@ -1804,21 +1814,19 @@ impl Pal for Sys {
}
match gethostname(nodename.as_slice_mut().cast_slice_to::<u8>()) {
Ok(_) => (),
Ok(()) => (),
Err(_) => return Err(Errno(EIO)),
}
let file_path = c"/scheme/sys/uname".into();
let mut file = match File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) {
Ok(ok) => ok,
Err(_) => return Err(Errno(EIO)),
let Ok(mut file) = File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) else {
return Err(Errno(EIO));
};
let mut lines = BufReader::new(&mut file).lines();
let mut read_line = |mut dst: Out<[u8]>| {
let mut line = match lines.next() {
Some(Ok(l)) => l,
None | Some(Err(_)) => return Err(Errno(EIO)),
let Some(Ok(mut line)) = lines.next() else {
return Err(Errno(EIO));
};
line.push('\0');
let line_slice: &[u8] = line.as_bytes();
@@ -1864,6 +1872,7 @@ impl Pal for Sys {
Ok(())
}
#[expect(clippy::unnecessary_literal_unwrap, reason = "res needs refactoring")]
fn waitpid(pid: pid_t, stat_loc: Option<Out<'_, c_int>>, options: c_int) -> Result<pid_t> {
let res = None;
let mut status = 0;
@@ -1962,7 +1971,7 @@ impl Sys {
len: off_t,
) -> Result<(off_t, off_t)> {
// let file_off = Self::lseek(fd, 0, SEEK_SET)?;
match whence as i32 {
match i32::from(whence) {
SEEK_SET => {
let (start, len) = if len < 0 {
(start + len, -len)
+23 -14
View File
@@ -29,7 +29,7 @@ pub fn chdir(path: RedoxStr<'_>) -> Result<()> {
let (redox, fd) = match path {
RedoxStr::Absolute(path) => {
let path = path.to_standard_canon();
let fd = FdGuard::open_into_upper(&path.as_reference(), O_STAT);
let fd = FdGuard::open_into_upper(path.as_reference(), O_STAT);
(path.into_owned(), fd)
}
RedoxStr::Relative(redox_reference) => {
@@ -112,7 +112,7 @@ pub struct Cwd<'a> {
static CWD: RwLock<Option<Cwd<'_>>> = RwLock::new(None);
pub fn to_cwd_path(path: &str) -> Result<CwdPath> {
ArrayString::from_str(&path).or(Err(Error::new(ENAMETOOLONG)))
ArrayString::from_str(path).or(Err(Error::new(ENAMETOOLONG)))
}
pub fn set_cwd_manual(path: CwdPath, fd: FdGuardUpper) -> Result<()> {
@@ -126,7 +126,7 @@ pub fn set_cwd_manual(path: CwdPath, fd: FdGuardUpper) -> Result<()> {
pub fn clone_cwd() -> Option<CwdPath> {
let _siglock = tmp_disable_signals();
CWD.read().as_ref().map(|cwd| cwd.path.clone())
CWD.read().as_ref().map(|cwd| cwd.path)
}
fn open_absolute(path: &str, flags: usize) -> Result<usize> {
@@ -138,9 +138,9 @@ fn open_absolute(path: &str, flags: usize) -> Result<usize> {
}
// Read symlink content
fn read_link_content<'a, 'b>(
fn read_link_content<'b>(
dirfd: Option<&FdGuard>,
path: &'a str,
path: &str,
is_relative: bool,
) -> Result<RedoxStr<'b>> {
let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY;
@@ -156,7 +156,7 @@ fn read_link_content<'a, 'b>(
log::trace!(
"read_link_content ({:?} {:?} {}): {:?}",
dirfd,
&path,
path,
is_relative,
fd
);
@@ -180,7 +180,7 @@ fn resolve_sym_links<'a>(mut current_path_string: RedoxPath<'a>, flags: usize) -
let dirname = current_path_string.dirname();
let cow: Cow<'_, str> = current_path_string.into();
let initial_res = open_absolute(&cow, flags);
log::trace!("resolve_sym_links({:?}): {:?}", &cow, initial_res);
log::trace!("resolve_sym_links({:?}): {:?}", cow, initial_res);
match initial_res {
Ok(fd) => return Ok(fd),
Err(e) if e == Error::new(EXDEV) => {
@@ -309,12 +309,21 @@ pub struct FileLock(c_int);
impl FileLock {
pub fn lock(fd: c_int, op: c_int) -> Result<Self> {
if op & sys_file::LOCK_SH | sys_file::LOCK_EX == 0 {
return Err(Error::new(EINVAL));
const LOCK_SH_NB: c_int = sys_file::LOCK_SH | sys_file::LOCK_NB;
const LOCK_EX_NB: c_int = sys_file::LOCK_EX | sys_file::LOCK_NB;
const LOCK_UN_NB: c_int = sys_file::LOCK_UN | sys_file::LOCK_NB;
match op {
sys_file::LOCK_SH
| sys_file::LOCK_EX
| sys_file::LOCK_UN
| LOCK_SH_NB
| LOCK_EX_NB
| LOCK_UN_NB => {
Sys::flock(fd, op)?;
Ok(Self(fd))
}
_ => Err(Error::new(EINVAL)),
}
Sys::flock(fd, op)?;
Ok(Self(fd))
}
pub fn unlock(self) -> Result<()> {
@@ -384,14 +393,14 @@ fn at_flags_to_open_flags(at_flags: c_int) -> c_int {
/// # Arguments
/// * `dirfd` is a directory descriptor to which `path` is resolved.
/// * `path` is a relative or absolute path. Relative paths are resolved in relation to `dirfd`
/// while absolute paths skip `dirfd`.
/// while absolute paths skip `dirfd`.
/// * `at_flags` constrains how `path` is resolved.
/// * `oflags` are flags that are passed to open.
///
/// # Constants
/// `at_flags`:
/// * AT_EMPTY_PATH returns the path at `dirfd` itself if `path` is empty. If `path` is not
/// empty, it's resolved w.r.t `dirfd` like normal.
/// empty, it's resolved w.r.t `dirfd` like normal.
///
/// `dirfd`:
/// `AT_FDCWD` is a special constant for `dirfd` that resolves `path` under the current working
+3 -3
View File
@@ -60,7 +60,7 @@ pub fn init_state() -> &'static State {
if STATE.unsafe_ref().is_none() {
STATE.unsafe_set(Some(State::new()));
}
let state_ptr = STATE.unsafe_ref().as_ref().unwrap() as *const State;
let state_ptr = core::ptr::from_ref::<State>(STATE.unsafe_ref().as_ref().unwrap());
&*state_ptr
}
}
@@ -193,7 +193,7 @@ unsafe fn inner_ptrace(
Ok(0)
}
sys_ptrace::PTRACE_GETREGS => {
let c_regs = unsafe { &mut *(data as *mut user_regs_struct) };
let c_regs = unsafe { &mut *data.cast::<user_regs_struct>() };
let mut redox_regs = syscall::IntRegisters::default();
(&mut &session.regs).read(&mut redox_regs)?;
*c_regs = user_regs_struct {
@@ -228,7 +228,7 @@ unsafe fn inner_ptrace(
Ok(0)
}
sys_ptrace::PTRACE_SETREGS => {
let c_regs = unsafe { &*(data as *mut user_regs_struct) };
let c_regs = unsafe { &*data.cast::<user_regs_struct>() };
let redox_regs = syscall::IntRegisters {
r15: c_regs.r15 as _,
r14: c_regs.r14 as _,
+24 -4
View File
@@ -115,7 +115,14 @@ impl PalSignal for Sys {
SigactionKind::Handled {
handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_int != 0 {
SignalHandler {
sigaction: unsafe { core::mem::transmute(c_act.sa_handler) },
sigaction: unsafe {
core::mem::transmute::<
core::option::Option<extern "C" fn(i32)>,
core::option::Option<
unsafe extern "C" fn(i32, *const (), *mut ()),
>,
>(c_act.sa_handler)
},
}
} else {
SignalHandler {
@@ -138,20 +145,33 @@ impl PalSignal for Sys {
if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) {
*c_oact = match old_action.kind {
SigactionKind::Ignore => sigaction {
sa_handler: unsafe { core::mem::transmute(SIG_IGN) },
sa_handler: unsafe {
core::mem::transmute::<usize, core::option::Option<extern "C" fn(i32)>>(
SIG_IGN,
)
},
sa_flags: 0,
sa_restorer: None,
sa_mask: 0,
},
SigactionKind::Default => sigaction {
sa_handler: unsafe { core::mem::transmute(SIG_DFL) },
sa_handler: unsafe {
core::mem::transmute::<usize, core::option::Option<extern "C" fn(i32)>>(
SIG_DFL,
)
},
sa_flags: 0,
sa_restorer: None,
sa_mask: 0,
},
SigactionKind::Handled { handler } => sigaction {
sa_handler: if old_action.flags.contains(SigactionFlags::SIGINFO) {
unsafe { core::mem::transmute(handler.sigaction) }
unsafe {
core::mem::transmute::<
core::option::Option<unsafe extern "C" fn(i32, *const (), *mut ())>,
core::option::Option<extern "C" fn(i32)>,
>(handler.sigaction)
}
} else {
unsafe { handler.handler }
},
+78 -72
View File
@@ -1,4 +1,4 @@
use alloc::{borrow::Cow, vec::Vec};
use alloc::{borrow::Cow, string::ToString, vec::Vec};
use core::{cmp, mem, ptr, slice, str};
use redox_path::RedoxStr;
use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall};
@@ -42,16 +42,16 @@ unsafe fn bind_or_connect(
return Err(Errno(EINVAL));
}
let path = match unsafe { (*address).sa_family } as c_int {
let path = match c_int::from(unsafe { (*address).sa_family }) {
AF_INET => {
if (address_len as usize) != mem::size_of::<sockaddr_in>() {
return Err(Errno(EINVAL));
}
let data = unsafe { &*(address as *const sockaddr_in) };
let data = unsafe { &*address.cast::<sockaddr_in>() };
let addr = unsafe {
slice::from_raw_parts(
&data.sin_addr.s_addr as *const _ as *const u8,
(&raw const data.sin_addr.s_addr).cast::<u8>(),
mem::size_of_val(&data.sin_addr.s_addr),
)
};
@@ -78,7 +78,7 @@ unsafe fn bind_or_connect(
}
SocketCall::Connect => {
// When a connect is made using AF_UNSPEC TCP and UDP need to disconnect from the default peer
format!("disconnect")
"disconnect".to_string()
}
_ => unreachable!(),
},
@@ -101,12 +101,12 @@ pub unsafe fn bind_or_connect_into(
}
unsafe fn inner_af_unix(buf: &[u8], address: *mut sockaddr, address_len: *mut socklen_t) {
let data = unsafe { &mut *(address as *mut sockaddr_un) };
let data = unsafe { &mut *address.cast::<sockaddr_un>() };
data.sun_family = AF_UNIX as c_ushort;
let path = unsafe {
slice::from_raw_parts_mut(&mut data.sun_path as *mut _ as *mut u8, data.sun_path.len())
slice::from_raw_parts_mut((&raw mut data.sun_path).cast::<u8>(), data.sun_path.len())
};
let len = cmp::min(path.len(), buf.len());
@@ -142,11 +142,11 @@ unsafe fn inner_af_inet(
// Make address be followed by a NUL-byte
colon[0] = b'\0';
log::trace!("address: {:?}, port: {:?}", str::from_utf8(&raw_addr), port);
log::trace!("address: {:?}, port: {:?}", str::from_utf8(raw_addr), port);
let mut addr = in_addr::default();
assert_eq!(
unsafe { inet_aton(raw_addr.as_ptr() as *mut c_char, &mut addr) },
unsafe { inet_aton(raw_addr.as_ptr() as *mut c_char, &raw mut addr) },
1,
"inet_aton might be broken, failed to parse netstack address"
);
@@ -161,7 +161,7 @@ unsafe fn inner_af_inet(
let len = cmp::min(unsafe { *address_len } as usize, mem::size_of_val(&ret));
unsafe {
ptr::copy_nonoverlapping(&ret as *const _ as *const u8, address as *mut u8, len);
ptr::copy_nonoverlapping((&raw const ret).cast::<u8>(), address.cast::<u8>(), len);
*address_len = len as socklen_t;
}
}
@@ -282,11 +282,11 @@ unsafe fn serialize_ancillary_data_to_stream(
let fds_usize: Vec<usize> = c_fds.iter().map(|&fd| fd as usize).collect();
let fds_slice = unsafe {
slice::from_raw_parts(
fds_usize.as_ptr() as *const u8,
fds_usize.as_ptr().cast::<u8>(),
fds_usize.len() * mem::size_of::<usize>(),
)
};
redox_rt::sys::sys_call_wo(socket as usize, &fds_slice, CallFlags::FD, &[])?;
redox_rt::sys::sys_call_wo(socket as usize, fds_slice, CallFlags::FD, &[])?;
}
// Serialize to ancillary_data_stream.
@@ -300,7 +300,7 @@ unsafe fn serialize_ancillary_data_to_stream(
(SOL_SOCKET, SCM_CREDENTIALS) => {
// Our intermediate format: data_len is 0, no data payload
let data_for_stream_len = 0usize;
msg_stream.extend_from_slice(&(data_for_stream_len as usize).to_le_bytes());
msg_stream.extend_from_slice(&data_for_stream_len.to_le_bytes());
}
_ => {
return Err(Errno(EOPNOTSUPP));
@@ -330,8 +330,8 @@ unsafe fn deserialize_name_from_stream(
(unsafe {
inner_get_name_inner(
false,
mhdr.msg_name as *mut sockaddr,
&mut mhdr.msg_namelen,
mhdr.msg_name.cast::<sockaddr>(),
&raw mut mhdr.msg_namelen,
name_buffer,
)
})?;
@@ -380,7 +380,7 @@ unsafe fn deserialize_payload_from_stream(
let bytes_to_write = cmp::min(iov.iov_len, source_bytes_remaining);
if bytes_to_write > 0 {
let dest_slice: &mut [u8] =
unsafe { slice::from_raw_parts_mut(iov.iov_base as *mut u8, iov.iov_len) };
unsafe { slice::from_raw_parts_mut(iov.iov_base.cast::<u8>(), iov.iov_len) };
let source_sub_slice = &payload_data_from_stream
[source_bytes_consumed..source_bytes_consumed + bytes_to_write];
@@ -448,13 +448,13 @@ unsafe fn deserialize_ancillary_data_from_stream(
if cmsg_data_len_in_stream != mem::size_of::<usize>() {
return Err(Errno(EINVAL));
}
let fd_count = read_num::<usize>(&cmsg_data_from_stream)?;
let fd_count = read_num::<usize>(cmsg_data_from_stream)?;
let mut fds_usize = vec![0usize; fd_count];
let fds_bytes = unsafe {
slice::from_raw_parts_mut(
fds_usize.as_mut_ptr() as *mut u8,
fds_usize.as_mut_ptr().cast::<u8>(),
fds_usize.len() * mem::size_of::<usize>(),
)
};
@@ -478,7 +478,7 @@ unsafe fn deserialize_ancillary_data_from_stream(
return Err(Errno(EINVAL));
}
let pid = read_num::<pid_t>(&cmsg_data_from_stream)?;
let pid = read_num::<pid_t>(cmsg_data_from_stream)?;
let uid_offset = mem::size_of::<pid_t>();
let uid = read_num::<uid_t>(&cmsg_data_from_stream[uid_offset..])?;
let gid_offset = uid_offset + mem::size_of::<uid_t>();
@@ -486,10 +486,7 @@ unsafe fn deserialize_ancillary_data_from_stream(
let cred = ucred { pid, uid, gid };
temp_posix_cmsg_data_buf.extend_from_slice(unsafe {
slice::from_raw_parts(
&cred as *const ucred as *const u8,
mem::size_of::<ucred>(),
)
slice::from_raw_parts((&raw const cred).cast::<u8>(), mem::size_of::<ucred>())
});
temp_posix_cmsg_data_buf.len()
}
@@ -513,7 +510,7 @@ unsafe fn deserialize_ancillary_data_from_stream(
unsafe {
ptr::copy_nonoverlapping(
temp_posix_cmsg_data_buf.as_ptr(),
data_ptr_in_user_cmsg as *mut u8,
data_ptr_in_user_cmsg.cast::<u8>(),
actual_posix_cmsg_data_len,
)
};
@@ -539,22 +536,23 @@ impl PalSocket for Sys {
address_len: *mut socklen_t,
) -> Result<c_int> {
let stream = redox_rt::sys::dup(socket as usize, b"listen")?;
if address != ptr::null_mut() && address_len != ptr::null_mut() {
if let Err(err) = unsafe { Self::getpeername(stream as c_int, address, address_len) } {
let _ = redox_rt::sys::close(stream);
return Err(err);
}
if !address.is_null()
&& !address_len.is_null()
&& let Err(err) = unsafe { Self::getpeername(stream as c_int, address, address_len) }
{
let _ = redox_rt::sys::close(stream);
return Err(err);
}
Ok(stream as c_int)
}
unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> Result<()> {
match unsafe { (*address).sa_family } as c_int {
match c_int::from(unsafe { (*address).sa_family }) {
AF_INET => {
(unsafe { bind_or_connect_into(SocketCall::Bind, socket, address, address_len) })?;
}
AF_UNIX => {
let data = unsafe { &*(address as *const sockaddr_un) };
let data = unsafe { &*address.cast::<sockaddr_un>() };
// NOTE: It's UB to access data in given address that exceeds
// the given address length.
@@ -569,11 +567,15 @@ impl PalSocket for Sys {
// The maximum length of the address
maxlen,
// The first NUL byte, if any
unsafe { strnlen(&data.sun_path as *const _, maxlen as size_t) },
// FIXME applying clippy suggestion fails to compile
#[expect(clippy::borrow_as_ptr)]
unsafe {
strnlen(&data.sun_path as *const _, maxlen as size_t)
},
);
let addr =
unsafe { slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len) };
unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::<u8>(), len) };
let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
log::trace!("bind(): path: {:?}", path);
@@ -635,12 +637,12 @@ impl PalSocket for Sys {
address: *const sockaddr,
address_len: socklen_t,
) -> Result<c_int> {
match unsafe { (*address).sa_family } as c_int {
match c_int::from(unsafe { (*address).sa_family }) {
AF_INET => unsafe {
bind_or_connect_into(SocketCall::Connect, socket, address, address_len)
},
AF_UNIX => {
let data = unsafe { &*(address as *const sockaddr_un) };
let data = unsafe { &*address.cast::<sockaddr_un>() };
// NOTE: It's UB to access data in given address that exceeds
// the given address length.
@@ -655,11 +657,15 @@ impl PalSocket for Sys {
// The maximum length of the address
maxlen,
// The first NUL byte, if any
unsafe { strnlen(&data.sun_path as *const _, maxlen as size_t) },
// FIXME applying clippy suggestion fails to compile
#[expect(clippy::borrow_as_ptr)]
unsafe {
strnlen(&data.sun_path as *const _, maxlen as size_t)
},
);
let addr =
unsafe { slice::from_raw_parts(&data.sun_path as *const _ as *const u8, len) };
unsafe { slice::from_raw_parts((&raw const data.sun_path).cast::<u8>(), len) };
let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
log::trace!("bind(): path: {:?}", path);
@@ -743,11 +749,12 @@ impl PalSocket for Sys {
return Err(Errno(EINVAL));
}
Ok(unsafe { &mut *(option_value as *mut c_int) })
Ok(unsafe { &mut *option_value.cast::<c_int>() })
};
match level {
SOL_SOCKET => match option_name {
// TODO convert back to match when we support more levels
if level == SOL_SOCKET {
match option_name {
SO_DOMAIN => {
let option = option_c_int()?;
*option = socket_domain_type(socket)?.0;
@@ -770,7 +777,7 @@ impl PalSocket for Sys {
_ => {
let metadata = [SocketCall::GetSockOpt as u64, option_name as u64];
let payload =
unsafe { slice::from_raw_parts_mut(option_value as *mut u8, option_len) };
unsafe { slice::from_raw_parts_mut(option_value.cast::<u8>(), option_len) };
let call_flags = CallFlags::empty();
unsafe {
*option_len_ptr = redox_rt::sys::sys_call_ro(
@@ -782,8 +789,7 @@ impl PalSocket for Sys {
}
return Ok(());
}
},
_ => (),
}
}
todo_skip!(
@@ -813,7 +819,7 @@ impl PalSocket for Sys {
) -> Result<usize> {
if address.is_null() && flags == 0 {
Self::read(socket, unsafe {
slice::from_raw_parts_mut(buf as *mut u8, len)
slice::from_raw_parts_mut(buf.cast::<u8>(), len)
})
} else {
// Convert to recvmsg
@@ -822,23 +828,23 @@ impl PalSocket for Sys {
iov_len: len,
};
let mut msg = msghdr {
msg_name: address as *mut c_void,
msg_name: address.cast::<c_void>(),
msg_namelen: if !address_len.is_null() {
unsafe { *address_len }
} else {
0
},
msg_iov: &mut iov,
msg_iov: &raw mut iov,
msg_iovlen: 1,
msg_control: ptr::null_mut(),
msg_controllen: 0,
msg_flags: 0,
};
let count = unsafe { Self::recvmsg(socket, &mut msg, flags) }?;
let count = unsafe { Self::recvmsg(socket, &raw mut msg, flags) }?;
if !address_len.is_null() {
unsafe { *address_len = msg.msg_namelen };
}
return Ok(count);
Ok(count)
}
}
@@ -846,11 +852,11 @@ impl PalSocket for Sys {
if msg.is_null() {
return Err(Errno(EINVAL));
}
let mut mhdr = unsafe { &mut *msg };
let mhdr = unsafe { &mut *msg };
let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen as usize) }
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen) }
};
let whole_iov_size: usize = iovs_slice.iter().map(|iov| iov.iov_len).sum();
@@ -867,7 +873,7 @@ impl PalSocket for Sys {
+ mem::size_of::<usize>() // payload_len
+ whole_iov_size // payload_data_buffer
+ mem::size_of::<usize>() // control_len
+ mhdr.msg_controllen as usize // ancillary_stream_buffer
+ mhdr.msg_controllen // ancillary_stream_buffer
};
msg_stream
.try_reserve_exact(expected_stream_size)
@@ -883,7 +889,7 @@ impl PalSocket for Sys {
.copy_from_slice(&(whole_iov_size).to_le_bytes());
cursor += mem::size_of::<usize>();
msg_stream[cursor..cursor + mem::size_of::<usize>()]
.copy_from_slice(&(mhdr.msg_controllen as usize).to_le_bytes());
.copy_from_slice(&mhdr.msg_controllen.to_le_bytes());
// Read the message stream.
let metadata = [SocketCall::RecvMsg as u64, flags as u64];
@@ -897,12 +903,12 @@ impl PalSocket for Sys {
mhdr.msg_flags = 0;
// Read sender name.
(unsafe { deserialize_name_from_stream(&mut mhdr, &msg_stream, &mut cursor) })?;
(unsafe { deserialize_name_from_stream(mhdr, &msg_stream, &mut cursor) })?;
// Read payload data.
let actual_payload_bytes_written_to_iov = unsafe {
deserialize_payload_from_stream(
&mut mhdr,
mhdr,
&msg_stream,
iovs_slice,
whole_iov_size,
@@ -921,7 +927,7 @@ impl PalSocket for Sys {
socket,
&msg_stream,
&mut cursor,
cmsg_space_provided_by_user as usize,
cmsg_space_provided_by_user,
flags,
)
})?;
@@ -943,7 +949,7 @@ impl PalSocket for Sys {
let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
&[]
} else {
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen as usize) }
unsafe { slice::from_raw_parts(mhdr.msg_iov, mhdr.msg_iovlen) }
};
let mut msg_stream: Vec<u8> = Vec::new();
@@ -952,7 +958,7 @@ impl PalSocket for Sys {
.try_reserve_exact(
mem::size_of::<usize>() // payload_len
+ whole_iov_size // payload_data_buffer
+ mhdr.msg_controllen as usize, // ancillary_stream_buffer
+ mhdr.msg_controllen, // ancillary_stream_buffer
)
.map_err(|_| Errno(ENOMEM))?;
@@ -960,7 +966,7 @@ impl PalSocket for Sys {
let mut actual_payload_bytes_serialized = 0;
if !mhdr.msg_iov.is_null() && mhdr.msg_iovlen > 0 {
actual_payload_bytes_serialized = unsafe {
serialize_payload_to_stream(&mut msg_stream, &iovs_slice, whole_iov_size)
serialize_payload_to_stream(&mut msg_stream, iovs_slice, whole_iov_size)
}?;
}
// Process Control Messages from msghdr and serialize them.
@@ -995,30 +1001,30 @@ impl PalSocket for Sys {
if flags != 0 {
// Convert to sendmsg
let mut iov = iovec {
iov_base: buf as *mut c_void,
iov_base: buf.cast_mut(),
iov_len: len,
};
let msg = msghdr {
msg_name: dest_addr as *mut c_void,
msg_namelen: dest_len,
msg_iov: &mut iov,
msg_iov: &raw mut iov,
msg_iovlen: 1,
msg_control: ptr::null_mut(),
msg_controllen: 0,
msg_flags: 0,
};
return unsafe { Self::sendmsg(socket, &msg, flags) };
return unsafe { Self::sendmsg(socket, &raw const msg, flags) };
}
if dest_addr == ptr::null() || dest_len == 0 {
if dest_addr.is_null() || dest_len == 0 {
Self::write(socket, unsafe {
slice::from_raw_parts(buf as *const u8, len)
slice::from_raw_parts(buf.cast::<u8>(), len)
})
} else {
let fd = FdGuard::new(unsafe {
bind_or_connect(SocketCall::Connect, socket, dest_addr, dest_len)
}?);
Self::write(fd.as_c_fd().unwrap(), unsafe {
slice::from_raw_parts(buf as *const u8, len)
slice::from_raw_parts(buf.cast::<u8>(), len)
})
}
}
@@ -1039,7 +1045,7 @@ impl PalSocket for Sys {
return Err(Errno(EINVAL));
}
let timeval = unsafe { &*(option_value as *const timeval) };
let timeval = unsafe { &*option_value.cast::<timeval>() };
let fd = FdGuard::new(redox_rt::sys::dup(socket as usize, timeout_name)?);
@@ -1048,7 +1054,7 @@ impl PalSocket for Sys {
};
let timespec = syscall::TimeSpec {
tv_sec: timeval.tv_sec as i64,
tv_sec: timeval.tv_sec,
tv_nsec,
};
@@ -1056,8 +1062,9 @@ impl PalSocket for Sys {
Ok(())
};
match level {
SOL_SOCKET => match option_name {
// TODO convert back to match when we support more levels
if level == SOL_SOCKET {
match option_name {
SO_RCVTIMEO => return set_timeout(b"read_timeout"),
SO_SNDTIMEO => return set_timeout(b"write_timeout"),
_ => {
@@ -1074,8 +1081,7 @@ impl PalSocket for Sys {
)?;
return Ok(());
}
},
_ => (),
}
}
todo_skip!(
@@ -1183,7 +1189,7 @@ impl NumFromBytes for i32 {
buffer
.get(..mem::size_of::<i32>())
.and_then(|slice| slice.try_into().ok())
.ok_or_else(|| Errno(EFAULT))?,
.ok_or(Errno(EFAULT))?,
))
}
}
@@ -1193,7 +1199,7 @@ impl NumFromBytes for usize {
buffer
.get(..mem::size_of::<usize>())
.and_then(|slice| slice.try_into().ok())
.ok_or_else(|| Errno(EFAULT))?,
.ok_or(Errno(EFAULT))?,
))
}
}
+5 -6
View File
@@ -70,16 +70,15 @@ pub extern "C" fn timer_routine(arg: *mut c_void) -> *mut c_void {
if let Some(fun) = timer_st.evp.sigev_notify_function {
fun(timer_st.evp.sigev_value);
}
} else if timer_st.evp.sigev_notify == SIGEV_SIGNAL {
if Sys::sigqueue(
} else if timer_st.evp.sigev_notify == SIGEV_SIGNAL
&& Sys::sigqueue(
timer_st.process_pid,
timer_st.evp.sigev_signo as _,
timer_st.evp.sigev_value,
)
.is_err()
{
break;
}
{
break;
}
}
@@ -107,7 +106,7 @@ fn timer_next_event(timer_st: &mut timer_internal_t) -> Result<()> {
syscall::TimeSpec::from(&timer_st.next_wake_time.it_value)
};
let bytes_written = redox_rt::sys::posix_write(timer_st.timerfd, &*buf_to_write)?;
let bytes_written = redox_rt::sys::posix_write(timer_st.timerfd, &buf_to_write)?;
if bytes_written < size_of::<timespec>() {
return Err(Errno(EIO));
}
-1
View File
@@ -173,7 +173,6 @@ pub(crate) unsafe fn create(
new_tcb.masters_ptr = current_tcb.masters_ptr;
new_tcb.masters_len = current_tcb.masters_len;
new_tcb.linker_ptr = current_tcb.linker_ptr;
new_tcb.mspace = current_tcb.mspace;
let stack_end = unsafe { stack_base.add(stack_size) };
let mut stack = stack_end.cast::<usize>();
+26 -47
View File
@@ -1,14 +1,13 @@
//! Startup code.
use alloc::{boxed::Box, vec::Vec};
use core::{intrinsics, ptr};
use alloc::vec::Vec;
use core::{intrinsics, ptr, str::FromStr};
use crate::{
ALLOCATOR,
c_str::CStr,
header::{libgen, stdio, stdlib},
ld_so::{self, linker::Linker},
platform::{self, Pal, Sys, get_auxvs, types::*},
sync::mutex::Mutex,
ld_so::{self},
platform::{self, Pal, Sys, get_auxvs, logger::RELIBC_LOG_ENV_VAR, types::*},
};
#[repr(C)]
@@ -89,26 +88,9 @@ static mut INIT_COMPLETE: bool = false;
#[unsafe(no_mangle)]
static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut();
fn alloc_init() {
unsafe {
if INIT_COMPLETE {
return;
}
}
unsafe {
if let Some(tcb) = ld_so::tcb::Tcb::current()
&& !tcb.mspace.is_null()
{
ALLOCATOR.set(tcb.mspace);
}
}
}
extern "C" fn init_array() {
// The thing is that we cannot guarantee if
// init_array runs first or if relibc_start runs first
// Still whoever gets to run first must initialize rust
// memory allocator before doing anything else.
unsafe {
if INIT_COMPLETE {
@@ -116,15 +98,14 @@ extern "C" fn init_array() {
}
}
alloc_init();
io_init();
unsafe {
if platform::environ.is_null() {
platform::environ = __relibc_init_environ;
}
}
io_init();
unsafe {
crate::pthread::init();
INIT_COMPLETE = true
@@ -203,26 +184,14 @@ pub unsafe extern "C" fn relibc_start_v1(
redox_rt::TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
}
// Set up the right allocator...
// if any memory rust based memory allocation happen before this step .. we are doomed.
alloc_init();
if let Some(tcb) = unsafe { ld_so::tcb::Tcb::current() } {
// Update TCB mspace
if tcb.mspace.is_null() {
tcb.mspace = ALLOCATOR.get();
}
// Set linker pointer if necessary
if tcb.linker_ptr.is_null() {
//TODO: get ld path
let linker = Linker::new(ld_so::linker::Config::default());
//TODO: load root object
tcb.linker_ptr = Box::into_raw(Box::new(Mutex::new(linker)));
}
let is_dynamically_linked = if let Some(tcb) = unsafe { ld_so::tcb::Tcb::current() } {
#[cfg(target_os = "redox")]
redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
}
!tcb.linker_ptr.is_null()
} else {
false
};
// Set up argc and argv
let argc = sp.argc;
@@ -249,9 +218,19 @@ pub unsafe extern "C" fn relibc_start_v1(
}
let auxvs = unsafe { get_auxvs(sp.auxv().cast()) };
unsafe { crate::platform::init(auxvs) };
init_array();
unsafe { crate::platform::logger::init() };
if !is_dynamically_linked {
unsafe { crate::platform::init(auxvs) };
init_array();
}
if let Some(env) = unsafe {
CStr::from_nullable_ptr(crate::header::stdlib::getenv(RELIBC_LOG_ENV_VAR.as_ptr()))
} && let Ok(level) = log::LevelFilter::from_str(env.to_str().unwrap_or(""))
&& let Err(_) = unsafe { crate::platform::logger::init(level) }
&& !is_dynamically_linked
{
log::error!("Logger has already been initialised");
}
// Run preinit array
{
+3 -2
View File
@@ -44,7 +44,8 @@ run-once: $(BUILD)/bins_verify/relibc-tests $(BUILD)/$(TESTBIN) support_build
$(BUILD)/bins_verify/relibc-tests: src/main.rs
mkdir -p $(BUILD)/bins_verify
RUSTFLAGS="-C target-feature=-crt-static" $(CARGO_TEST) build --release --bin relibc-tests \
--artifact-dir $(BUILD)/bins_verify --target-dir $(BUILD)/target -Z unstable-options
--artifact-dir $(BUILD)/bins_verify --target-dir $(BUILD)/target -Z unstable-options \
--target $(TARGET)
rm -rf $(BUILD)/target
$(BUILD)/Makefile: Makefile.run.mk
@@ -112,7 +113,7 @@ STATIC_FLAGS+=\
ifeq ($(IS_REDOX),0)
DYNAMIC_FLAGS+=\
-Wl,-dynamic-linker=$(SYSROOT_TARGET)/$(LD_SO_PATH) \
-Wl,-dynamic-linker=$(SYSROOT_TARGET)/lib/$(LD_SONAME) \
-Wl,-rpath=$(SYSROOT_TARGET)/lib:\$$ORIGIN \
-L $(SYSROOT)/lib \
-lc \
+1 -2
View File
@@ -5,8 +5,6 @@ FAILING_TESTS=
else
# Wrong modified time
FAILING_TESTS := futimens
# Crash, mmap issue
FAILING_TESTS += malloc/usable_size
# Not a FIFO
FAILING_TESTS += mkfifo
# Waitpid had EINTR
@@ -72,6 +70,7 @@ EXPECT_NAMES=\
locale/duplocale \
locale/newlocale \
locale/setlocale \
malloc/usable_size \
math \
regex \
semaphore/lock \
+1 -1
View File
@@ -1,2 +1,2 @@
malloc: 27 bytes
malloc_usable_size: 48 bytes
malloc_usable_size: 40 bytes
+8 -7
View File
@@ -1,9 +1,9 @@
#include <assert.h>
#include <signal.h>
#include <setjmp.h>
#include <unistd.h>
#include <stdio.h>
#include "test_helpers.h"
#include <assert.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static sigjmp_buf jmpenv;
@@ -15,6 +15,7 @@ void alarm_handler(int sig) {
int main() {
struct sigaction sa;
sa.sa_flags = 0;
sa.sa_handler = alarm_handler;
sigemptyset(&sa.sa_mask);
@@ -27,7 +28,7 @@ int main() {
}
alarm(1);
sleep(5);
sleep(5);
assert(0); // unreachable
}
}