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]] [[package]]
name = "object" name = "object"
version = "0.36.7" 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 = [ dependencies = [
"memchr", "memchr",
] ]
@@ -610,9 +610,9 @@ checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
[[package]] [[package]]
name = "spin" name = "spin"
version = "0.9.8" version = "0.9.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" checksum = "3763264f6b73151db08c50ff20d7d8a0b8796e021cdea7ceedad07b80155fa0e"
dependencies = [ dependencies = [
"lock_api", "lock_api",
] ]
@@ -625,9 +625,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.118" version = "2.0.119"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" checksum = "872831b642d1a07999a962a351ed35b955ea2cfc8f3862091e2a240a84f17297"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
+1
View File
@@ -117,6 +117,7 @@ features = ["c_api"]
[dependencies.object] [dependencies.object]
version = "0.36.7" version = "0.36.7"
git = "https://gitlab.redox-os.org/andypython/object" git = "https://gitlab.redox-os.org/andypython/object"
branch = "new"
default-features = false default-features = false
features = ["elf", "read_core"] features = ["elf", "read_core"]
+14 -13
View File
@@ -40,7 +40,7 @@ BUILTINS_VERSION=0.1.70
all: | headers libs all: | headers libs
headers: $(HEADERS_DEPS) headers: $(BUILD)/$(PROFILE)/librelibc.a $(HEADERS_DEPS)
rm -rf $(TARGET_HEADERS) rm -rf $(TARGET_HEADERS)
mkdir -p $(TARGET_HEADERS) mkdir -p $(TARGET_HEADERS)
cp -r include/* $(TARGET_HEADERS) cp -r include/* $(TARGET_HEADERS)
@@ -51,13 +51,13 @@ endif
@set -e ; \ @set -e ; \
for header in $(HEADERS_UNPARSED); do \ for header in $(HEADERS_UNPARSED); do \
if test -f "src/header/$$header/cbindgen.toml"; then \ 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=`echo "$$header" | sed 's/_/\//g'`; \
out="$(TARGET_HEADERS)/$$out.h"; \ out="$(TARGET_HEADERS)/$$out.h"; \
cat "src/header/$$header/cbindgen.toml" cbindgen.globdefs.toml \ cat "src/header/$$header/cbindgen.toml" cbindgen.globdefs.toml \
| cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out"; \ | cbindgen "src/header/$$header/mod.rs" --config=/dev/stdin --output "$$out"; \
fi \ fi \
done; echo -e "\033[0;36;49mAll headers written\033[0m"; done; printf "\033[0;36;49mAll headers written\033[0m\n";
clean: clean:
$(CARGO) clean $(CARGO) clean
@@ -79,20 +79,19 @@ libs: \
$(BUILD)/$(PROFILE)/libc.so \ $(BUILD)/$(PROFILE)/libc.so \
$(BUILD)/$(PROFILE)/crt0.o \ $(BUILD)/$(PROFILE)/crt0.o \
$(BUILD)/$(PROFILE)/crti.o \ $(BUILD)/$(PROFILE)/crti.o \
$(BUILD)/$(PROFILE)/crtn.o \ $(BUILD)/$(PROFILE)/crtn.o
$(BUILD)/$(PROFILE)/ld.so
install-libs: headers libs install-libs: headers libs
mkdir -pv "$(DESTDIR)/lib" mkdir -pv "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib" cp -v "$(BUILD)/$(PROFILE)/libc.a" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/libc.so" "$(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/libc.so.6"
ln -vnfs libc.so "$(DESTDIR)/lib/$(LD_SONAME)"
cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib" cp -v "$(BUILD)/$(PROFILE)/crt0.o" "$(DESTDIR)/lib"
ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o" ln -vnfs crt0.o "$(DESTDIR)/lib/crt1.o"
ln -vnfs crt0.o "$(DESTDIR)/lib/Scrt1.o" ln -vnfs crt0.o "$(DESTDIR)/lib/Scrt1.o"
cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib" cp -v "$(BUILD)/$(PROFILE)/crti.o" "$(DESTDIR)/lib"
cp -v "$(BUILD)/$(PROFILE)/crtn.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),) ifeq ($(USE_RUST_LIBM),)
cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a" cp -v "$(BUILD)/openlibm/libopenlibm.a" "$(DESTDIR)/lib/libm.a"
else else
@@ -135,10 +134,16 @@ test-once: sysroot/$(TARGET)
$(MAKE) -C tests run-once TESTBIN=$(TESTBIN) $(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 \ $(CC) -nostdlib \
-shared \ -shared \
-Wl,--gc-sections \ -Wl,--gc-sections \
-Wl,--dynamic-list=dynlst.txt \
-Wl,-z,pack-relative-relocs \ -Wl,-z,pack-relative-relocs \
-Wl,--sort-common \ -Wl,--sort-common \
-Wl,--whole-archive $^ -Wl,--no-whole-archive \ -Wl,--whole-archive $^ -Wl,--no-whole-archive \
@@ -146,10 +151,6 @@ $(BUILD)/$(PROFILE)/libc.so: $(BUILD)/$(PROFILE)/libc.a
$(LINKFLAGS) \ $(LINKFLAGS) \
-o $@ -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 $(BUILD)/$(PROFILE)/libc.a: $(BUILD)/$(PROFILE)/librelibc.a $(BUILD)/openlibm/libopenlibm.a
echo "create $@" > "$@.mri" echo "create $@" > "$@.mri"
for lib in $^; do\ for lib in $^; do\
@@ -219,9 +220,9 @@ $(BUILD)/openlibm: openlibm
touch $@ touch $@
ifeq ($(USE_RUST_LIBM),) 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 $(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 else
$(BUILD)/openlibm/libopenlibm.a: $(BUILD)/openlibm/libopenlibm.a:
mkdir -p "$(BUILD)/openlibm" 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 NM=aarch64-linux-gnu-nm
export OBJCOPY=aarch64-linux-gnu-objcopy export OBJCOPY=aarch64-linux-gnu-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1 LD_SONAME=ld.so.1
endif endif
ifeq ($(TARGET),aarch64-unknown-linux-relibc) ifeq ($(TARGET),aarch64-unknown-linux-relibc)
@@ -19,7 +19,7 @@ ifeq ($(TARGET),aarch64-unknown-linux-relibc)
export NM=aarch64-linux-relibc-nm export NM=aarch64-linux-relibc-nm
export OBJCOPY=aarch64-linux-relibc-objcopy export OBJCOPY=aarch64-linux-relibc-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1 LD_SONAME=ld.so.1
endif endif
@@ -30,7 +30,7 @@ ifeq ($(TARGET),aarch64-unknown-redox)
export NM=aarch64-unknown-redox-nm export NM=aarch64-unknown-redox-nm
export OBJCOPY=aarch64-unknown-redox-objcopy export OBJCOPY=aarch64-unknown-redox-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/ld.so.1 LD_SONAME=ld.so.1
endif endif
ifeq ($(TARGET),i586-unknown-redox) ifeq ($(TARGET),i586-unknown-redox)
@@ -40,7 +40,7 @@ ifeq ($(TARGET),i586-unknown-redox)
export NM=i586-unknown-redox-nm export NM=i586-unknown-redox-nm
export OBJCOPY=i586-unknown-redox-objcopy export OBJCOPY=i586-unknown-redox-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1 LD_SONAME=ld.so.1
endif endif
ifeq ($(TARGET),i686-unknown-redox) ifeq ($(TARGET),i686-unknown-redox)
@@ -50,7 +50,7 @@ ifeq ($(TARGET),i686-unknown-redox)
export NM=i686-unknown-redox-nm export NM=i686-unknown-redox-nm
export OBJCOPY=i686-unknown-redox-objcopy export OBJCOPY=i686-unknown-redox-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/libc.so.1 LD_SONAME=ld.so.1
endif endif
ifeq ($(TARGET),x86_64-unknown-linux-gnu) 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 NM=x86_64-linux-gnu-nm
export OBJCOPY=objcopy export OBJCOPY=objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1 LD_SONAME=ld64.so.1
endif endif
ifeq ($(TARGET),x86_64-unknown-linux-relibc) 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 NM=x86_64-linux-relibc-nm
export OBJCOPY=x86_64-linux-relibc-objcopy export OBJCOPY=x86_64-linux-relibc-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1 LD_SONAME=ld64.so.1
endif endif
ifeq ($(TARGET),x86_64-unknown-redox) ifeq ($(TARGET),x86_64-unknown-redox)
@@ -80,7 +80,7 @@ ifeq ($(TARGET),x86_64-unknown-redox)
export NM=x86_64-unknown-redox-nm export NM=x86_64-unknown-redox-nm
export OBJCOPY=x86_64-unknown-redox-objcopy export OBJCOPY=x86_64-unknown-redox-objcopy
export CPPFLAGS= export CPPFLAGS=
LD_SO_PATH=lib/ld64.so.1 LD_SONAME=ld64.so.1
endif endif
ifeq ($(TARGET),riscv64gc-unknown-redox) ifeq ($(TARGET),riscv64gc-unknown-redox)
@@ -90,5 +90,5 @@ ifeq ($(TARGET),riscv64gc-unknown-redox)
export NM=riscv64-unknown-redox-nm export NM=riscv64-unknown-redox-nm
export OBJCOPY=riscv64-unknown-redox-objcopy export OBJCOPY=riscv64-unknown-redox-objcopy
export CPPFLAGS=-march=rv64gc -mabi=lp64d export CPPFLAGS=-march=rv64gc -mabi=lp64d
LD_SO_PATH=lib/ld.so.1 LD_SONAME=ld.so.1
endif 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] #![no_std]
#![allow(internal_features)] #![allow(internal_features)]
#![feature(core_intrinsics)]
#![deny(unsafe_op_in_unsafe_fn)] #![deny(unsafe_op_in_unsafe_fn)]
use core::{ 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 .globl _start
_start: _start:
mv a0, sp mv a0, sp
jal relibc_ld_so_start call relibc_ld_so_start
unimp unimp
" "
); );
+1
View File
@@ -706,6 +706,7 @@ impl<'a> MmapGuard<'a> {
Ok(()) Ok(())
} }
#[expect(clippy::mut_from_ref)]
pub unsafe fn map_mut_anywhere( pub unsafe fn map_mut_anywhere(
fd: &'a FdGuardUpper, fd: &'a FdGuardUpper,
offset: usize, offset: usize,
+12
View File
@@ -953,6 +953,10 @@ impl FdTbl {
pub const CONTEXT_MAX_FILES: u32 = 65_536; pub const CONTEXT_MAX_FILES: u32 = 65_536;
pub const DEFAULT_CAPACITY: usize = usize::BITS as usize; 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 { pub const fn new() -> Self {
Self { Self {
fd: None, fd: None,
@@ -1300,6 +1304,10 @@ bitflags::bitflags! {
} }
impl PosixFdTbl { impl PosixFdTbl {
#[expect(
clippy::new_without_default,
reason = "default not expected for this type"
)]
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
table: Vec::new(), table: Vec::new(),
@@ -1628,6 +1636,10 @@ pub struct UpperFdTbl {
} }
impl UpperFdTbl { impl UpperFdTbl {
#[expect(
clippy::new_without_default,
reason = "default not expected for this type"
)]
pub const fn new() -> Self { pub const fn new() -> Self {
Self { Self {
table: Vec::new(), table: Vec::new(),
+1
View File
@@ -258,6 +258,7 @@ impl<'a, T: Kind> NulStr<'a, T> {
/// Scan the string to get its length. /// Scan the string to get its length.
#[doc(alias = "strlen")] #[doc(alias = "strlen")]
#[doc(alias = "wcslen")] #[doc(alias = "wcslen")]
#[expect(clippy::len_without_is_empty, reason = "len() signature intentional")]
pub fn len(self) -> usize { pub fn len(self) -> usize {
self.to_chars().len() 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. // Fail at compile-time if alignments differ.
let a = [0_u8; core::mem::align_of::<$export>()]; 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); let b: [u8; core::mem::align_of::<Wrapped>()] = core::mem::transmute(a);
}; };
// TODO: Turn into a macro? // 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 _: libc::$export = core::mem::transmute(export.__relibc_internal_size);
let a = [0_u8; core::mem::align_of::<$export>()]; 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); 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 { fn from(value: &'a syscall::TimeSpec) -> Self {
Self { Self {
tv_sec: value.tv_sec as _, tv_sec: value.tv_sec as _,
tv_nsec: value.tv_nsec as _, tv_nsec: value.tv_nsec.into(),
} }
} }
} }
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
impl<'a> From<&'a timespec> for syscall::TimeSpec { impl From<&timespec> for syscall::TimeSpec {
fn from(tp: &timespec) -> Self { fn from(tp: &timespec) -> Self {
Self { Self {
tv_sec: tp.tv_sec as _, tv_sec: tp.tv_sec as _,
+13 -15
View File
@@ -11,10 +11,13 @@ use core::{
sync::atomic::{AtomicUsize, Ordering}, sync::atomic::{AtomicUsize, Ordering},
}; };
use alloc::sync::Arc;
use crate::{ use crate::{
c_str::CStr, c_str::CStr,
ld_so::{ ld_so::{
linker::{DlError, ObjectHandle, Resolve, ScopeKind}, dso::DSO,
linker::{DlError, Resolve, ScopeKind},
tcb::Tcb, tcb::Tcb,
}, },
platform::types::{c_char, c_int, c_void}, 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 mut linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone(); match linker.load_library(filename, resolve, scope, noload) {
let cbs = cbs_c.borrow(); Ok(handle) => Arc::into_raw(handle).cast::<c_void>().cast_mut(),
match (cbs.load_library)(&mut linker, filename, resolve, scope, noload) {
Ok(handle) => handle.as_ptr().cast_mut(),
Err(error) => { Err(error) => {
set_last_error(error); set_last_error(error);
ptr::null_mut() 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>. /// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/dlsym.html>.
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
pub unsafe extern "C" fn dlsym(handle: *mut c_void, symbol: *const c_char) -> *mut c_void { 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() { if symbol.is_null() {
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); 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 linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone();
let cbs = cbs_c.borrow(); match linker.get_sym(handle, symbol_str) {
match (cbs.get_sym)(&linker, handle, symbol_str) {
Some(sym) => sym, Some(sym) => sym,
_ => { _ => {
ERROR.store(ERROR_NOT_SUPPORTED.as_ptr() as usize, Ordering::SeqCst); 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; return -1;
}; };
let Some(handle) = ObjectHandle::from_ptr(handle) else { if handle.is_null() {
set_last_error(DlError::InvalidHandle); set_last_error(DlError::InvalidHandle);
return -1; return -1;
}; }
let mut linker = unsafe { (*tcb.linker_ptr).lock() }; let mut linker = unsafe { (*tcb.linker_ptr).lock() };
let cbs_c = linker.cbs.clone(); let obj = unsafe { Arc::from_raw(handle.cast::<DSO>()) };
let cbs = cbs_c.borrow(); linker.unload(obj);
(cbs.unload)(&mut linker, handle);
0 0
} }
+7 -2
View File
@@ -98,11 +98,16 @@ pub unsafe fn poll_epoll(fds: &mut [pollfd], timeout: c_int, sigmask: *const sig
continue; 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 { let mut event = epoll_event {
events: 0, events: 0,
data: epoll_data { u64: i as u64 }, data: epoll_data { u64: i as u64 },
..Default::default() // needed only on redox for _pad field
}; };
for (p, ep) in event_map.iter() { 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'); let mut parts = line.split_mut(|&c| c == b'\0');
Some(passwd { Some(passwd {
pw_name: parts.next()?.as_mut_ptr().cast::<c_char>(), 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_uid: parsed(parts.next())?,
pw_gid: parsed(parts.next())?, pw_gid: parsed(parts.next())?,
pw_gecos: parts.next()?.as_mut_ptr().cast::<c_char>(), 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 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) 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 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) Ok(bytes / size)
} }
@@ -50,13 +53,13 @@ impl IoctlBuffer {
unsafe fn read<T>(&self) -> Result<T> { unsafe fn read<T>(&self) -> Result<T> {
let (ptr, size) = match *self { let (ptr, size) = match *self {
Self::Write(ptr, size) => (ptr, size), 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)); return Err(Errno(EINVAL));
} }
}; };
if size == mem::size_of::<T>() { 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) Ok(value)
} else { } else {
Err(Errno(EINVAL)) Err(Errno(EINVAL))
@@ -64,14 +67,11 @@ impl IoctlBuffer {
} }
unsafe fn write<T>(&mut self, value: T) -> Result<()> { unsafe fn write<T>(&mut self, value: T) -> Result<()> {
let (ptr, size) = match *self { let (Self::Read(ptr, size) | Self::ReadWrite(ptr, size)) = *self else {
Self::Read(ptr, size) | Self::ReadWrite(ptr, size) => (ptr, size), return Err(Errno(EINVAL));
_ => {
return Err(Errno(EINVAL));
}
}; };
if size == mem::size_of::<T>() { if size == mem::size_of::<T>() {
unsafe { ptr::write(ptr as *mut T, value) }; unsafe { ptr::write(ptr.cast::<T>(), value) };
Ok(()) Ok(())
} else { } else {
Err(Errno(EINVAL)) 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 { match request {
FIONBIO => { FIONBIO => {
let mut flags = Sys::fcntl(fd, fcntl::F_GETFL, 0)?; 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 flags & !fcntl::O_NONBLOCK
} else { } else {
flags | fcntl::O_NONBLOCK 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)?; Sys::fcntl(fd, fcntl::F_SETFL, flags as c_ulonglong)?;
} }
TCGETS => { TCGETS => {
let termios = unsafe { &mut *(out as *mut termios::termios) }; let termios = unsafe { &mut *out.cast::<termios::termios>() };
dup_read(fd, "termios", termios)?; dup_read(fd, "termios", termios)?;
} }
// TODO: give these different behaviors // 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"); todo_skip!(0, "ioctl TIOCSCTTY");
} }
TIOCGPGRP => { TIOCGPGRP => {
let pgrp = unsafe { &mut *(out as *mut pid_t) }; let pgrp = unsafe { &mut *out.cast::<pid_t>() };
dup_read(fd, "pgrp", pgrp)?; dup_read(fd, "pgrp", pgrp)?;
} }
TIOCSPGRP => { 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)?; dup_write(fd, "pgrp", pgrp)?;
} }
TIOCGWINSZ => { TIOCGWINSZ => {
let winsize = unsafe { &mut *(out as *mut winsize) }; let winsize = unsafe { &mut *out.cast::<winsize>() };
dup_read(fd, "winsize", winsize)?; dup_read(fd, "winsize", winsize)?;
} }
TIOCSWINSZ => { 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)?; dup_write(fd, "winsize", winsize)?;
} }
TIOCGPTLCK => { TIOCGPTLCK => {
let lock = unsafe { &mut *(out as *mut c_int) }; let lock = unsafe { &mut *out.cast::<c_int>() };
dup_read(fd, "ptlock", lock)?; dup_read(fd, "ptlock", lock)?;
} }
TIOCSPTLCK => { 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)?; dup_write(fd, "ptlock", lock)?;
} }
TIOCGPTN => { TIOCGPTN => {
let name = unsafe { &mut *(out as *mut c_int) }; let name = unsafe { &mut *out.cast::<c_int>() };
dup_read(fd, "ptsname", name)?; dup_read(fd, "ptsname", name)?;
} }
SIOCATMARK => { SIOCATMARK => {
+1 -1
View File
@@ -72,7 +72,7 @@ pub(crate) struct timer_internal_t {
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
impl timer_internal_t { impl timer_internal_t {
pub unsafe fn from_raw(timerid: timer_t) -> &'static mut Self { 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")] #[cfg(target_os = "redox")]
#[path = "sysconf/redox.rs"] #[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_TIMEOUTS => 202405,
_SC_TIMERS => 202405, _SC_TIMERS => 202405,
_SC_SYMLOOP_MAX => -1, _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_CONF => get_cpu_count().unwrap_or(None).unwrap_or(1),
_SC_NPROCESSORS_ONLN => 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), _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 mut buf = sys_statvfs::statvfs::default();
let res = Sys::fstatvfs(fd, Out::from_mut(&mut buf)); let res = Sys::fstatvfs(fd, Out::from_mut(&mut buf));
if let Ok(()) = Sys::close(fd) {}; // TODO handle error if let Ok(()) = Sys::close(fd) {}; // TODO handle error
let _ = res?; res?;
return Ok(buf); 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> //! * <https://www.akkadia.org/drepper/dsohowto.pdf>
use object::{ use object::{
NativeEndian, Object, StringTable, SymbolIndex, elf, NativeEndian, Object, StringTable, SymbolIndex, U32, elf,
read::elf::{ read::elf::{
Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _, Dyn as _, GnuHashTable, HashTable as SysVHashTable, ProgramHeader as _, Rel as _,
Rela as _, Sym as _, Version, VersionTable, Rela as _, Sym as _, Version, VersionTable,
@@ -42,25 +42,29 @@ pub type Relr = usize;
#[cfg(target_pointer_width = "32")] #[cfg(target_pointer_width = "32")]
mod shim { mod shim {
use object::{NativeEndian, elf::*, read::elf::ElfFile32}; use object::{NativeEndian, elf, read::elf::ElfFile32};
pub type Dyn = Dyn32<NativeEndian>; pub type Dyn = elf::Dyn32<NativeEndian>;
pub type Rel = Rel32<NativeEndian>; pub type Rel = elf::Rel32<NativeEndian>;
pub type Rela = Rela32<NativeEndian>; pub type Rela = elf::Rela32<NativeEndian>;
pub type Sym = Sym32<NativeEndian>; pub type Sym = elf::Sym32<NativeEndian>;
pub type FileHeader = FileHeader32<NativeEndian>; pub type FileHeader = elf::FileHeader32<NativeEndian>;
pub type ProgramHeader = ProgramHeader32<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>; pub type ElfFile<'a> = ElfFile32<'a, NativeEndian>;
} }
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
mod shim { mod shim {
use object::{NativeEndian, elf::*, read::elf::ElfFile64}; use object::{NativeEndian, elf, read::elf::ElfFile64};
pub type Dyn = Dyn64<NativeEndian>; pub type Dyn = elf::Dyn64<NativeEndian>;
pub type Rel = Rel64<NativeEndian>; pub type Rel = elf::Rel64<NativeEndian>;
pub type Rela = Rela64<NativeEndian>; pub type Rela = elf::Rela64<NativeEndian>;
pub type Sym = Sym64<NativeEndian>; pub type Sym = elf::Sym64<NativeEndian>;
pub type FileHeader = FileHeader64<NativeEndian>; pub type FileHeader = elf::FileHeader64<NativeEndian>;
pub type ProgramHeader = ProgramHeader64<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>; pub type ElfFile<'a> = ElfFile64<'a, NativeEndian>;
} }
@@ -176,7 +180,7 @@ impl<'data> Dynamic<'data> {
unsafe impl Send for Dynamic<'_> {} unsafe impl Send for Dynamic<'_> {}
unsafe impl Sync for Dynamic<'_> {} unsafe impl Sync for Dynamic<'_> {}
#[derive(Debug)] #[derive(Debug, Copy, Clone)]
pub(super) struct Relocation { pub(super) struct Relocation {
pub(super) offset: usize, pub(super) offset: usize,
pub(super) addend: Option<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. /// Use to represent a library as well as all the symbols that is loaded withen it.
pub struct DSO { pub struct DSO {
pub name: String, pub name: String,
pub id: usize, pub id: usize,
pub dlopened: bool, pub dlopened: bool,
pub entry_point: usize, pub entry_point: usize,
/// Loaded library in-memory data pub base: *const u8,
pub mmap: &'static [u8], pub mmap: Option<MemoryMapHandle>,
pub tls_module_id: usize, pub tls_module_id: usize,
pub tls_offset: usize, pub tls_offset: usize,
@@ -350,9 +375,56 @@ pub struct DSO {
/// Whether this DSO *and* its dependencies have been successfully loaded. /// Whether this DSO *and* its dependencies have been successfully loaded.
is_ready: AtomicBool, is_ready: AtomicBool,
/// Is this DSO for ld.so?
is_me: bool,
} }
impl DSO { 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( pub fn new(
path: &str, path: &str,
data: &[u8], data: &[u8],
@@ -385,7 +457,10 @@ impl DSO {
id, id,
dlopened, dlopened,
entry_point, entry_point,
mmap,
base: mmap.as_ptr(),
mmap: Some(mmap),
tls_module_id: if tcb_master.is_some() { tls_module_id: if tcb_master.is_some() {
tls_module_id tls_module_id
} else { } else {
@@ -397,13 +472,14 @@ impl DSO {
dynamic, dynamic,
scope: spin::Once::new(), scope: spin::Once::new(),
is_ready: AtomicBool::new(false), is_ready: AtomicBool::new(false),
is_me: false,
}; };
Ok((dso, tcb_master, elf.elf_program_headers().to_vec())) Ok((dso, tcb_master, elf.elf_program_headers().to_vec()))
} }
#[inline] #[inline]
pub fn mark_ready(&self) { pub unsafe fn mark_ready(&self) {
self.is_ready.store(true, Ordering::SeqCst); self.is_ready.store(true, Ordering::SeqCst);
} }
@@ -444,11 +520,7 @@ impl DSO {
Some(( Some((
Symbol { Symbol {
name, name,
base: if self.pie { base: if self.pie { self.base as usize } else { 0 },
self.mmap.as_ptr() as usize
} else {
0
},
value: sym.st_value(NativeEndian) as usize, value: sym.st_value(NativeEndian) as usize,
size: sym.st_size(NativeEndian) as usize, size: sym.st_size(NativeEndian) as usize,
sym_type: sym.st_type(), 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() { for f in self.dynamic.fini_array.iter().rev() {
unsafe { f() } unsafe { f() }
} }
@@ -480,7 +552,7 @@ impl DSO {
data: &'a [u8], data: &'a [u8],
base_addr: Option<usize>, base_addr: Option<usize>,
tls_offset: usize, tls_offset: usize,
) -> Result<(&'static [u8], Option<Master>, Dynamic<'static>), String> { ) -> Result<(MemoryMapHandle, Option<Master>, Dynamic<'static>), String> {
let endian = elf.endian(); let endian = elf.endian();
log::trace!("# {}", path); log::trace!("# {}", path);
// data for struct LinkMap // 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 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) let (parsed_dynamic, debug) =
.map_err(|e| e.to_string())?; Self::parse_dynamic(path, mmap.as_ptr(), is_pie_enabled(elf), dynamic.1)
.map_err(|e| e.to_string())?;
if let Some(i) = debug { if let Some(i) = debug {
// FIXME: cleanup // 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>( fn parse_dynamic<'a>(
path: &str, path: &str,
mmap: &'a [u8], mmap: *const u8,
is_pie: bool, is_pie: bool,
(_, entries): (&ProgramHeader, &[Dyn]), entries: &[Dyn],
) -> object::Result<(Dynamic<'a>, Option<usize>)> { ) -> object::Result<(Dynamic<'a>, Option<usize>)> {
let mut runpath = None; let mut runpath = None;
let mut got = None; let mut got = None;
@@ -692,28 +772,79 @@ impl DSO {
for (i, entry) in entries.iter().enumerate() { for (i, entry) in entries.iter().enumerate() {
let val = entry.d_val(NativeEndian); let val = entry.d_val(NativeEndian);
let relative_idx = val as usize - if is_pie { 0 } else { mmap.as_ptr() as usize }; let relative_idx = val as usize - if is_pie { 0 } else { mmap as usize };
let ptr = (val as usize + if is_pie { mmap.as_ptr() as usize } else { 0 }) as *const u8; let ptr = (val as usize + if is_pie { mmap as usize } else { 0 }) as *const u8;
let tag = entry.d_tag(NativeEndian) as u32; let tag = entry.d_tag(NativeEndian) as u32;
match tag { match tag {
elf::DT_DEBUG => debug = Some(i), 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 => { elf::DT_GNU_HASH => {
let value = GnuHashTable::parse(NativeEndian, &mmap[relative_idx..])?; let header = unsafe { ptr.cast::<GnuHashHeader>().as_ref() }.unwrap();
hash_table = Some(HashTable::Gnu(value)); 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 // XXX: Both GNU_HASH and HASH may be present, we give priority
// to GNU_HASH as it is significantly faster. // to GNU_HASH as it is significantly faster.
elf::DT_HASH if hash_table.is_none() => { elf::DT_HASH if hash_table.is_none() => {
let value = SysVHashTable::parse(NativeEndian, &mmap[relative_idx..])?; let header = unsafe { ptr.cast::<SysVHashHeader>().as_ref() }.unwrap();
hash_table = Some(HashTable::Sysv(value)); 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 => { elf::DT_PLTGOT => {
@@ -771,14 +902,16 @@ impl DSO {
} }
} }
let strtab_offset = strtab_offset.expect("mandatory DT_STRTAB not present"); let hash_table = hash_table.expect("either DT_GNU_HASH and/or DT_HASH mut be present");
let strtab_size = strtab_size.expect("mandatory DT_STRSZ not 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")] #[expect(clippy::unnecessary_cast, reason = "needed on i586")]
let dynstrtab = StringTable::new( let dynstrtab = StringTable::new(
mmap, unsafe { slice::from_raw_parts(mmap.byte_add(strtab_offset), strtab_size as usize) },
strtab_offset as u64, 0,
strtab_offset as u64 + strtab_size as u64, strtab_size as u64,
); );
let get_str = |entry: &Dyn| { let get_str = |entry: &Dyn| {
@@ -812,7 +945,6 @@ impl DSO {
let soname = soname.map(get_str).transpose()?; let soname = soname.map(get_str).transpose()?;
let jmprel = jmprel.unwrap_or_default(); 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 init_array = unsafe { get_array(init_array_ptr, init_array_len) };
let fini_array = unsafe { get_array(fini_array_ptr, fini_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<()> { 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 (sym, my_sym) = if reloc.sym != STN_UNDEF {
let name = self.dynamic.symbol_name(reloc.sym).unwrap(); let name = self.dynamic.symbol_name(reloc.sym).unwrap();
@@ -923,7 +1053,7 @@ impl DSO {
.unwrap_or((0, self)); .unwrap_or((0, self));
let ptr = if self.pie { let ptr = if self.pie {
(b + reloc.offset) as *mut u8 unsafe { self.base.byte_add(reloc.offset).cast_mut() }
} else { } else {
reloc.offset as *mut u8 reloc.offset as *mut u8
}; };
@@ -956,7 +1086,7 @@ impl DSO {
} }
RelocationKind::GOT => set_usize(s), RelocationKind::GOT => set_usize(s),
RelocationKind::OFFSET => set_usize((s + a).wrapping_sub(p)), 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::SYMBOLIC => set_usize(s + a),
RelocationKind::TPOFF => { RelocationKind::TPOFF => {
assert!( assert!(
@@ -974,7 +1104,8 @@ impl DSO {
} }
} }
RelocationKind::IRELATIVE => unsafe { 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()); set_usize(f());
}, },
RelocationKind::COPY => unsafe { RelocationKind::COPY => unsafe {
@@ -1007,7 +1138,6 @@ impl DSO {
return Ok(()); return Ok(());
}; };
let object_base_addr = self.mmap.as_ptr() as usize;
let jmprel = self.dynamic.jmprel; let jmprel = self.dynamic.jmprel;
let pltrelsz = self.dynamic.pltrelsz; let pltrelsz = self.dynamic.pltrelsz;
@@ -1031,14 +1161,14 @@ impl DSO {
}; };
let ptr = if self.pie { let ptr = if self.pie {
(object_base_addr + reloc.offset) as *mut usize (self.base as usize + reloc.offset) as *mut usize
} else { } else {
reloc.offset as *mut usize reloc.offset as *mut usize
}; };
match (reloc.kind, resolve) { match (reloc.kind, resolve) {
(RelocationKind::PLT, Resolve::Lazy) if self.pie => unsafe { (RelocationKind::PLT, Resolve::Lazy) if self.pie => unsafe {
*ptr += object_base_addr; *ptr += self.base as usize;
}, },
(RelocationKind::PLT, Resolve::Lazy) => { (RelocationKind::PLT, Resolve::Lazy) => {
@@ -1082,20 +1212,31 @@ impl DSO {
Ok(()) 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 global_scope = GLOBAL_SCOPE.read();
let base = self.mmap.as_ptr();
unsafe { if !self.is_me {
apply_relr(base, self.dynamic.relr); unsafe {
apply_relr(self.base, self.dynamic.relr);
}
} }
self.dynamic for reloc in self.dynamic.static_relocations() {
.static_relocations() if reloc.kind == RelocationKind::RELATIVE && self.is_me {
.try_for_each(|reloc| self.static_relocate(&global_scope, reloc))?; 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)?; self.lazy_relocate(&global_scope, resolve)?;
let ph = ph.unwrap();
// Protect pages // Protect pages
for ph in ph for ph in ph
.iter() .iter()
@@ -1120,7 +1261,7 @@ impl DSO {
unsafe { unsafe {
let ptr = if self.pie { let ptr = if self.pie {
self.mmap.as_ptr().add(vaddr) self.base.add(vaddr)
} else { } else {
vaddr as *const u8 vaddr as *const u8
}; };
@@ -1135,12 +1276,16 @@ impl DSO {
impl Drop for DSO { impl Drop for DSO {
fn drop(&mut self) { fn drop(&mut self) {
if self.is_me {
return;
}
if self.is_ready.load(Ordering::SeqCst) { if self.is_ready.load(Ordering::SeqCst) {
// `run_fini` should not be called if we are being prematurely // `run_fini` should not be called if we are being prematurely
// dropped (e.g. failed to satisfy dependencies). // 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::{ use alloc::{
collections::BTreeMap, collections::BTreeMap,
rc::Rc,
string::{String, ToString}, string::{String, ToString},
sync::{Arc, Weak}, sync::{Arc, Weak},
vec::Vec, vec::Vec,
@@ -12,13 +11,9 @@ use object::{
read::elf::{Rela as _, Sym}, read::elf::{Rela as _, Sym},
}; };
use core::{ use core::ptr;
cell::RefCell,
ptr::{self, NonNull},
};
use crate::{ use crate::{
ALLOCATOR,
c_str::{CStr, CString}, c_str::{CStr, CString},
error::Errno, error::Errno,
header::{ header::{
@@ -26,7 +21,7 @@ use crate::{
fcntl, sys_mman, fcntl, sys_mman,
unistd::F_OK, unistd::F_OK,
}, },
ld_so::dso::SymbolBinding, ld_so::dso::{Dyn, SymbolBinding},
out::Out, out::Out,
platform::{ platform::{
Pal, Sys, Pal, Sys,
@@ -43,7 +38,6 @@ use super::dso::Rela;
use super::{ use super::{
PATH_SEP, PATH_SEP,
access::accessible, access::accessible,
callbacks::LinkerCallbacks,
debug::{_dl_debug_state, _r_debug, RTLDState}, debug::{_dl_debug_state, _r_debug, RTLDState},
dso::{DSO, ProgramHeader}, dso::{DSO, ProgramHeader},
tcb::{Master, Tcb}, 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! { bitflags::bitflags! {
#[derive(Debug, Default)] #[derive(Debug, Default)]
pub struct DebugFlags: u32 { 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 { pub struct Linker {
config: Config, config: Config,
me: Me,
next_object_id: usize, next_object_id: usize,
next_tls_module_id: usize, next_tls_module_id: usize,
tls_size: usize, tls_size: usize,
objects: BTreeMap<usize, Arc<DSO>>, objects: BTreeMap<usize, Arc<DSO>>,
name_to_object_id_map: BTreeMap<String, usize>, name_to_object_id_map: BTreeMap<String, usize>,
pub cbs: Rc<RefCell<LinkerCallbacks>>,
} }
const ROOT_ID: usize = 1; const ROOT_ID: usize = 1;
impl Linker { impl Linker {
pub fn new(config: Config) -> Self { pub fn new(me: Me, config: Config) -> Self {
Self { Self {
me,
config, config,
next_object_id: ROOT_ID, next_object_id: ROOT_ID,
next_tls_module_id: 1, next_tls_module_id: 1,
tls_size: 0, tls_size: 0,
objects: BTreeMap::new(), objects: BTreeMap::new(),
name_to_object_id_map: BTreeMap::new(), name_to_object_id_map: BTreeMap::new(),
cbs: Rc::new(RefCell::new(LinkerCallbacks::new())),
} }
} }
@@ -465,7 +431,7 @@ impl Linker {
resolve: Resolve, resolve: Resolve,
scope: ScopeKind, scope: ScopeKind,
noload: bool, noload: bool,
) -> Result<ObjectHandle> { ) -> Result<Arc<DSO>> {
log::trace!( log::trace!(
"[ld.so] load_library(name={:?}, resolve={:#?}, scope={:#?}, noload={})", "[ld.so] load_library(name={:?}, resolve={:#?}, scope={:#?}, noload={})",
name, name,
@@ -500,14 +466,14 @@ impl Linker {
self.scope_debug(); self.scope_debug();
} }
Ok(ObjectHandle::new(obj.clone())) Ok(obj.clone())
} else if !noload { } else if !noload {
let parent_runpath = &self let parent_runpath = &self
.objects .objects
.get(&ROOT_ID) .get(&ROOT_ID)
.and_then(|parent| parent.runpath().cloned()); .and_then(|parent| parent.runpath().cloned());
Ok(ObjectHandle::new(self.load_object( Ok(self.load_object(
name, name,
parent_runpath, parent_runpath,
None, None,
@@ -518,29 +484,24 @@ impl Linker {
resolve resolve
}, },
scope, scope,
)?)) )?)
} else { } else {
// FIXME: LoadError? Err(DlError::NotFound)
// Err(Error::Malformed(format!(
// "object '{}' has not yet been loaded",
// name
// )))
Ok(ObjectHandle(ptr::null()))
} }
} }
None => match self.objects.get(&ROOT_ID) { None => match self.objects.get(&ROOT_ID) {
Some(obj) => Ok(ObjectHandle::new(obj.clone())), Some(obj) => Ok(obj.clone()),
None => Err(DlError::NotFound), 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; let guard;
if let Some(handle) = handle.as_ref() { if let Some(handle) = handle {
handle.as_ref().scope() handle.scope()
} else { } else {
guard = GLOBAL_SCOPE.read(); guard = GLOBAL_SCOPE.read();
&guard &guard
@@ -560,8 +521,7 @@ impl Linker {
}) })
} }
pub fn unload(&mut self, handle: ObjectHandle) { pub fn unload(&mut self, obj: Arc<DSO>) {
let obj = handle.into_inner();
if !obj.dlopened { if !obj.dlopened {
return; return;
} }
@@ -590,7 +550,7 @@ impl Linker {
if let Some(name) = self.name_to_object_id_map.get(*dep) if let Some(name) = self.name_to_object_id_map.get(*dep)
&& let Some(object_name) = self.objects.get(name) && 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); self.name_to_object_id_map.remove(&obj.name);
@@ -603,7 +563,9 @@ impl Linker {
pub fn fini(&self) { pub fn fini(&self) {
for obj in self.objects.values() { 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() { 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 { unsafe {
@@ -664,14 +626,18 @@ impl Linker {
let new_tcb_len = new_tcb.generic.tcb_len; let new_tcb_len = new_tcb.generic.tcb_len;
// Unmap just the TCB page. // 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; let new_addr = ptr::addr_of!(*new_tcb) as usize;
assert_eq!( assert_eq!(
syscall::syscall5( syscall::syscall5(
syscall::SYS_MREMAP, syscall::SYS_MREMAP,
old_tcb as *mut Tcb as usize, core::ptr::from_mut::<Tcb>(old_tcb) as usize,
syscall::PAGE_SIZE, syscall::PAGE_SIZE,
new_addr, new_addr,
syscall::PAGE_SIZE, syscall::PAGE_SIZE,
@@ -692,7 +658,11 @@ impl Linker {
new_tcb.generic.tcb_len = new_tcb_len; new_tcb.generic.tcb_len = new_tcb_len;
drop(_guard); 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"))] #[cfg(not(target_os = "redox"))]
@@ -735,7 +705,6 @@ impl Linker {
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
Some(thr_fd), Some(thr_fd),
); );
tcb.mspace = ALLOCATOR.get();
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
{ {
@@ -751,7 +720,10 @@ impl Linker {
} }
for obj in new_objects.into_iter() { 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.run_init(&obj);
self.register_object(obj); self.register_object(obj);
} }
@@ -788,7 +760,7 @@ impl Linker {
base_addr: Option<usize>, base_addr: Option<usize>,
dlopened: bool, dlopened: bool,
new_objects: &mut Vec<Arc<DSO>>, new_objects: &mut Vec<Arc<DSO>>,
objects_data: &mut Vec<Vec<ProgramHeader>>, objects_data: &mut Vec<Option<Vec<ProgramHeader>>>,
tcb_masters: &mut Vec<Master>, tcb_masters: &mut Vec<Master>,
// Scope of the object that caused this object to be loaded. // Scope of the object that caused this object to be loaded.
dependent_scope: Option<&mut Scope>, dependent_scope: Option<&mut Scope>,
@@ -821,6 +793,49 @@ impl Linker {
let debug = self.config.debug_flags.contains(DebugFlags::LOAD); 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 path = self.search_object(name, parent_runpath)?;
let file = self.read_file(&path)?; let file = self.read_file(&path)?;
let data = file.data(); let data = file.data();
@@ -846,8 +861,8 @@ impl Linker {
eprintln!( eprintln!(
"[ld.so]: loading object: {} at {:#x}:{:#x} (pie: {})", "[ld.so]: loading object: {} at {:#x}:{:#x} (pie: {})",
name, name,
obj.mmap.as_ptr() as usize, obj.mmap.as_ref().unwrap().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().size(),
obj.pie, obj.pie,
); );
} }
@@ -896,7 +911,7 @@ impl Linker {
)?; )?;
} }
objects_data.push(elf); objects_data.push(Some(elf));
new_objects.push(obj.clone()); new_objects.push(obj.clone());
scope.set_owner(Arc::downgrade(&obj)); scope.set_owner(Arc::downgrade(&obj));
@@ -1011,7 +1026,7 @@ impl Linker {
#[cfg(target_pointer_width = "64")] #[cfg(target_pointer_width = "64")]
extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) -> *mut c_void { extern "C" fn __plt_resolve_inner(obj: *const DSO, relocation_index: c_uint) -> *mut c_void {
let obj = unsafe { &*obj }; 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 jmprel = obj.dynamic.jmprel;
let rela = unsafe { &*(jmprel as *const Rela).add(relocation_index as usize) }; 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 = ':'; pub const PATH_SEP: char = ':';
mod access; mod access;
pub mod callbacks;
pub mod debug; pub mod debug;
mod dso; pub mod dso;
pub mod linker; pub mod linker;
pub mod start; pub mod start;
pub mod tcb; 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 // 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::{ use alloc::{
borrow::ToOwned, borrow::ToOwned,
@@ -9,10 +9,11 @@ use alloc::{
string::{String, ToString}, string::{String, ToString},
vec::Vec, vec::Vec,
}; };
use log::LevelFilter;
use object::{ use object::{
NativeEndian, NativeEndian,
elf::{self, PT_DYNAMIC, PT_PHDR}, elf::{self, PT_DYNAMIC, PT_PHDR},
read::elf::{Dyn as _, ProgramHeader as _}, read::elf::{Dyn as _, FileHeader as _, ProgramHeader as _},
}; };
use crate::{ use crate::{
@@ -23,12 +24,12 @@ use crate::{
}, },
ld_so::{ ld_so::{
dso::{ 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, 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, start::Stack,
sync::mutex::Mutex, sync::mutex::Mutex,
}; };
@@ -41,12 +42,6 @@ use super::{
tcb::Tcb, 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) { unsafe fn get_argv(mut ptr: *const usize) -> (Vec<String>, *const usize) {
//traverse the stack and collect argument vector //traverse the stack and collect argument vector
let mut argv = Vec::new(); 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 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_ptr = None;
let mut rela_len = None; let mut rela_len = None;
let mut relr_ptr = 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_ptr = None;
let mut rel_len = None; let mut rel_len = None;
loop { loop {
let entry = unsafe { &*i }; let entry = unsafe { &*dynamic.add(i) };
let val = entry.d_val(NativeEndian); let val = entry.d_val(NativeEndian);
let ptr = val as *const u8; let ptr = val as *const u8;
match entry.d_tag(NativeEndian) as u32 { 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>( unsafe fn get_array<'a, T>(
ptr: Option<*const T>, ptr: Option<*const T>,
len: Option<usize>, len: Option<usize>,
@@ -251,7 +248,7 @@ pub unsafe extern "C" fn relibc_ld_so_start(
) -> &'a [T] { ) -> &'a [T] {
if let Some(ptr) = ptr { if let Some(ptr) = ptr {
let len = len.expect("dynamic entry was present without it's corresponding size"); 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 { } 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( fn stage2(
@@ -306,6 +319,8 @@ fn stage2(
self_base: usize, self_base: usize,
is_manual: bool, is_manual: bool,
base_addr: Option<usize>, base_addr: Option<usize>,
my_dyns: &'static [Dyn],
my_phdrs: &'static [ProgramHeader],
) -> usize { ) -> usize {
// Setup TCB for ourselves. // Setup TCB for ourselves.
unsafe { unsafe {
@@ -392,9 +407,12 @@ fn stage2(
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); );
crate::platform::environ = crate::platform::OUR_ENVIRON.unsafe_mut().as_mut_ptr(); if let Some(env) = envs.get(RELIBC_LOG_ENV_VAR.to_str().unwrap())
&& let Ok(level) = LevelFilter::from_str(env)
crate::platform::logger::init(); && let Err(_) = crate::platform::logger::init(level)
{
log::error!("Logger has already been initialised");
}
} }
// we might need global lock for this kind of stuff // 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) { let entry = match linker.load_program(&path, base_addr) {
Ok(entry) => entry, Ok(entry) => entry,
Err(err) => { Err(err) => {
+1 -4
View File
@@ -11,7 +11,7 @@ use generic_rt::GenericTcb;
use crate::{ use crate::{
header::sys_mman, header::sys_mman,
ld_so::linker::Linker, ld_so::linker::Linker,
platform::{Dlmalloc, Pal, Sys}, platform::{Pal, Sys},
pthread::{OsTid, Pthread}, pthread::{OsTid, Pthread},
sync::{mutex::Mutex, waitval::Waitval}, sync::{mutex::Mutex, waitval::Waitval},
}; };
@@ -56,8 +56,6 @@ pub struct Tcb {
pub num_copied_masters: usize, pub num_copied_masters: usize,
/// Pointer to dynamic linker /// Pointer to dynamic linker
pub linker_ptr: *const Mutex<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 /// Underlying pthread_t struct, pthread_self() returns &self.pthread
pub pthread: Pthread, pub pthread: Pthread,
@@ -98,7 +96,6 @@ impl Tcb {
masters_len: 0, masters_len: 0,
num_copied_masters: 0, num_copied_masters: 0,
linker_ptr: ptr::null(), linker_ptr: ptr::null(),
mspace: ptr::null(),
pthread: Pthread { pthread: Pthread {
waitval: Waitval::new(), waitval: Waitval::new(),
flags: Default::default(), flags: Default::default(),
+1
View File
@@ -117,6 +117,7 @@ macro_rules! trace_expr {
// log::trace! but functions inside them will // log::trace! but functions inside them will
// not be evaluated or compiled unless enabled // not be evaluated or compiled unless enabled
#[cfg(target_os = "redox")] // currently only used in redox
macro_rules! trace_log { macro_rules! trace_log {
($($arg:tt)+) => { ($($arg:tt)+) => {
#[cfg(not(feature = "no_trace"))] #[cfg(not(feature = "no_trace"))]
+6 -20
View File
@@ -3,8 +3,7 @@ use core::{
cell::SyncUnsafeCell, cell::SyncUnsafeCell,
cmp, cmp,
mem::align_of, mem::align_of,
ptr::{self, copy_nonoverlapping, write_bytes}, ptr::{copy_nonoverlapping, write_bytes},
sync::atomic::{AtomicPtr, Ordering},
}; };
mod sys; mod sys;
@@ -17,31 +16,18 @@ pub type Dlmalloc = DlmallocCApi<sys::System>;
#[allow(clippy::declare_interior_mutable_const)] #[allow(clippy::declare_interior_mutable_const)]
pub const NEWALLOCATOR: Allocator = Allocator::new(); pub const NEWALLOCATOR: Allocator = Allocator::new();
pub struct Allocator { pub struct Allocator(SyncUnsafeCell<Mutex<Dlmalloc>>);
inner: SyncUnsafeCell<Mutex<Dlmalloc>>,
pub ptr: AtomicPtr<Mutex<Dlmalloc>>,
}
impl Allocator { impl Allocator {
#[allow(clippy::new_without_default)] #[allow(clippy::new_without_default)]
pub const fn new() -> Self { pub const fn new() -> Self {
Allocator { Self(SyncUnsafeCell::new(Mutex::new(Dlmalloc::new(
inner: SyncUnsafeCell::new(Mutex::new(Dlmalloc::new(sys::System::new()))), sys::System::new(),
ptr: AtomicPtr::new(ptr::null_mut()), ))))
}
} }
pub fn get(&self) -> *const Mutex<Dlmalloc> { pub fn get(&self) -> *const Mutex<Dlmalloc> {
let ptr = self.ptr.load(Ordering::Acquire); self.0.get()
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);
} }
} }
+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 crate::{c_str::CStr, io::prelude::*, sync::Mutex};
use alloc::string::{String, ToString}; use alloc::string::{String, ToString};
use log::{Metadata, Record}; use log::{LevelFilter, Metadata, Record, SetLoggerError};
const DEFAULT_LOG_LEVEL: log::LevelFilter = log::LevelFilter::Info; 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 mut logger = RedoxLogger::new();
let log_env = c"RELIBC_LOG_LEVEL".as_ptr();
#[cfg(feature = "no_trace")] #[cfg(feature = "no_trace")]
let mut trace_warn = false; let mut trace_warn = false;
unsafe { unsafe {
if let Some(env) = CStr::from_nullable_ptr(crate::header::stdlib::getenv(log_env)) #[cfg(feature = "no_trace")]
&& let Ok(level) = log::LevelFilter::from_str(env.to_str().unwrap_or("")) if level == log::LevelFilter::Trace {
{ trace_warn = true;
#[cfg(feature = "no_trace")]
if level == log::LevelFilter::Trace {
trace_warn = true;
}
logger = logger.with_output(OutputBuilder::stderr().with_filter(level).build());
} }
logger = logger.with_output(OutputBuilder::stderr().with_filter(level).build());
if let Some(name) = CStr::from_nullable_ptr(crate::platform::program_invocation_short_name) 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()); 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")] #[cfg(feature = "no_trace")]
if trace_warn { 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" "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? /// 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 callback = || {
let res = syscall::read(epfd as usize, unsafe { syscall::read(epfd as usize, unsafe {
slice::from_raw_parts_mut( slice::from_raw_parts_mut(
events as *mut u8, events.cast::<u8>(),
maxevents as usize * mem::size_of::<syscall::Event>(), maxevents as usize * mem::size_of::<syscall::Event>(),
) )
}); })
res
}; };
let bytes_read = if sigset.is_null() { let bytes_read = if sigset.is_null() {
@@ -126,7 +125,7 @@ impl PalEpoll for Sys {
unsafe { unsafe {
let event_ptr = events.add(i); let event_ptr = events.add(i);
let target_ptr = events.add(count); let target_ptr = events.add(count);
let event = *(event_ptr as *mut Event); let event = *event_ptr.cast::<Event>();
*target_ptr = epoll_event { *target_ptr = epoll_event {
events: event_flags_to_epoll(event.flags), events: event_flags_to_epoll(event.flags),
data: epoll_data { data: epoll_data {
+4 -4
View File
@@ -31,7 +31,7 @@ fn fexec_impl(
interp_override: new_interp_override, interp_override: new_interp_override,
} = redox_rt::proc::fexec_impl( } = redox_rt::proc::fexec_impl(
exec_file, exec_file,
&RtTcb::current().thread_fd(), RtTcb::current().thread_fd(),
redox_rt::current_proc_fd(), redox_rt::current_proc_fd(),
path, path,
args, args,
@@ -49,11 +49,11 @@ fn fexec_impl(
// null-terminated. Violating this should therefore give the "format error" ENOEXEC. // 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))?; let path_cstr = CStr::from_bytes_with_nul(&path).map_err(|_| Error::new(ENOEXEC))?;
return execve( execve(
Executable::AtPath(path_cstr), Executable::AtPath(path_cstr),
ArgEnv::Parsed { args, envs }, ArgEnv::Parsed { args, envs },
Some(new_interp_override), Some(new_interp_override),
); )
} }
pub enum ArgEnv<'a> { pub enum ArgEnv<'a> {
@@ -166,7 +166,7 @@ pub fn execve(
let mut args: Vec<&[u8]> = Vec::with_capacity(len); let mut args: Vec<&[u8]> = Vec::with_capacity(len);
if let Some(interpreter) = &interpreter_path { 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))?; .map_err(|_| Error::new(ENOENT))?;
// Push interpreter to arguments // 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)] #[unsafe(no_mangle)]
pub unsafe extern "C" fn redox_fpath(fd: c_int, buf: *mut c_void, count: size_t) -> ssize_t { 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 { 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_err(Errno::from)
.map(|l| l as ssize_t) .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 crate::{c_str::CStr, header::stdlib::getenv, platform::types::c_char};
use core::ptr;
use syscall::{EIO, ENOENT, Error, Result, flag::*}; 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; const ENV_MAX_LEN: i32 = i32::MAX;
@@ -10,8 +9,8 @@ macro_rules! env_str {
($lit:expr) => { ($lit:expr) => {
#[allow(unused_unsafe)] #[allow(unused_unsafe)]
{ {
let val_bytes = unsafe { getenv(concat!($lit, "\0").as_ptr() as *const c_char) }; let val_bytes = unsafe { getenv(concat!($lit, "\0").as_ptr().cast::<c_char>()) };
if val_bytes != ptr::null_mut() { if !val_bytes.is_null() {
if let Ok(val_str) = unsafe { CStr::from_ptr(val_bytes) }.to_str() { if let Ok(val_str) = unsafe { CStr::from_ptr(val_bytes) }.to_str() {
Some(val_str) Some(val_str)
} else { } 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), ((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); let _ = redox_rt::sys::close(usize_fd);
return Err(Error::new(EMFILE)); return Err(Error::new(EMFILE));
} }
@@ -42,7 +42,7 @@ pub fn fchmod(fd: usize, new_mode: u16) -> Result<()> {
std_fs_call_wo( std_fs_call_wo(
fd, fd,
&[], &[],
&StdFsCallMeta::new(StdFsCallKind::Fchmod, new_mode as u64, 0), &StdFsCallMeta::new(StdFsCallKind::Fchmod, u64::from(new_mode), 0),
)?; )?;
Ok(()) Ok(())
} }
@@ -77,7 +77,7 @@ pub fn getdents(fd: usize, buf: &mut [u8], opaque: u64) -> Result<usize> {
}) => (), }) => (),
other => { other => {
//println!("REAL GETDENTS {:?}", 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 (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 { if bytes_read == 0 {
return Ok(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() } { if let Some(buf) = unsafe { buf.as_mut() } {
buf.st_dev = redox_buf.st_dev as dev_t; buf.st_dev = redox_buf.st_dev as dev_t;
buf.st_ino = redox_buf.st_ino as ino_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_mode = redox_buf.st_mode as mode_t;
buf.st_uid = redox_buf.st_uid as uid_t; buf.st_uid = redox_buf.st_uid as uid_t;
buf.st_gid = redox_buf.st_gid as gid_t; buf.st_gid = redox_buf.st_gid as gid_t;
// TODO st_rdev // TODO st_rdev
buf.st_rdev = 0; buf.st_rdev = 0;
buf.st_size = redox_buf.st_size as off_t; 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_blocks = redox_buf.st_blocks as blkcnt_t;
buf.st_atim = timespec { buf.st_atim = timespec {
tv_sec: redox_buf.st_atime as time_t, 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 { let redox_buf = unsafe {
slice::from_raw_parts( slice::from_raw_parts(
times.as_ptr() as *const u8, times.as_ptr().cast::<u8>(),
times.len() * mem::size_of::<syscall::TimeSpec>(), 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<()> { pub fn clock_gettime(clock: usize, mut tp: Out<timespec>) -> Result<()> {
let mut redox_tp = syscall::TimeSpec::default(); 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()); tp.write((&redox_tp).into());
Ok(()) Ok(())
} }
@@ -228,9 +235,8 @@ pub unsafe extern "C" fn redox_open_v1(
mode: u16, mode: u16,
) -> RawResult { ) -> RawResult {
let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) }; let path = unsafe { str::from_utf8_unchecked(slice::from_raw_parts(path_base, path_len)) };
let path = match RedoxStr::new(path) { let Some(path) = RedoxStr::new(path) else {
Some(path) => path, return Error::mux(Err(Error::new(EINVAL)));
None => return Error::mux(Err(Error::new(EINVAL))),
}; };
Error::mux(openat(AT_FDCWD, path, flags as c_int, mode as mode_t)) 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 { let perms = (if stat.st_uid == uid {
stat.st_mode >> (3 * 2) stat.st_mode >> (3 * 2)
} else if stat.st_gid == gid { } else if stat.st_gid == gid {
stat.st_mode >> (3 * 1) stat.st_mode >> 3
} else { } else {
stat.st_mode stat.st_mode
}) & 0o7; }) & 0o7;
@@ -204,7 +204,7 @@ impl Pal for Sys {
unsafe { unsafe {
BRK_CUR = allocated; 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<()> { 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)?; path::chdir(path)?;
Ok(()) Ok(())
} }
@@ -243,11 +243,11 @@ impl Pal for Sys {
CLOCK_MONOTONIC => "/scheme/time/4/getres", CLOCK_MONOTONIC => "/scheme/time/4/getres",
_ => return Err(Errno(EINVAL)), _ => 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 mut redox_res = timespec::default();
let buffer = unsafe { let buffer = unsafe {
slice::from_raw_parts_mut( slice::from_raw_parts_mut(
&mut redox_res as *mut _ as *mut u8, (&raw mut redox_res).cast::<u8>(),
mem::size_of::<timespec>(), mem::size_of::<timespec>(),
) )
}; };
@@ -285,8 +285,7 @@ impl Pal for Sys {
} }
fn exit(status: c_int) -> ! { fn exit(status: c_int) -> ! {
let _ = redox_rt::sys::posix_exit(status); redox_rt::sys::posix_exit(status)
loop {}
} }
unsafe fn execve(path: CStr, argv: *const *mut c_char, envp: *const *mut c_char) -> Result<()> { 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 start = start as u64 | if is_ofd { 1 << 63 } else { 0 };
let len = len as u64; let len = len as u64;
match flock.l_type as i32 { match i32::from(flock.l_type) {
F_UNLCK => { F_UNLCK => {
let meta = StdFsCallMeta::new(StdFsCallKind::Unlock, start, len); let meta = StdFsCallMeta::new(StdFsCallKind::Unlock, start, len);
syscall::std_fs_call(fd as usize, &mut [], &meta)?; syscall::std_fs_call(fd as usize, &mut [], &meta)?;
@@ -393,7 +392,7 @@ impl Pal for Sys {
let meta = StdFsCallMeta::new( let meta = StdFsCallMeta::new(
StdFsCallKind::Lock, StdFsCallKind::Lock,
start, start,
len | if flock.l_type as i32 == F_WRLCK { len | if i32::from(flock.l_type) == F_WRLCK {
1 << 63 1 << 63
} else { } else {
0 0
@@ -429,7 +428,7 @@ impl Pal for Sys {
} }
let mut len = len as u64; 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; len |= 1 << 63;
} }
@@ -562,7 +561,7 @@ impl Pal for Sys {
#[inline] #[inline]
unsafe fn futex_wait(addr: *mut u32, val: u32, deadline: Option<&timespec>) -> Result<()> { 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()) })?; (unsafe { redox_rt::sys::sys_futex_wait(addr, val, deadline.as_ref()) })?;
Ok(()) 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 // 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)> { unsafe fn dent_reclen_offset(this_dent: &[u8], offset: usize) -> Option<(u16, u64)> {
let mut header = DirentHeader::default(); 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 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') { if this_dent.get(usize::from(header.record_len) - 1) != Some(&b'\0') {
@@ -665,7 +664,7 @@ impl Pal for Sys {
} }
if found { 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); list.index(count).write(grp.gr_gid);
} }
count += 1; count += 1;
@@ -674,7 +673,7 @@ impl Pal for Sys {
grp::endgrent(); grp::endgrent();
} }
if !list.is_empty() && (count as usize) > list.len() { if !list.is_empty() && count > list.len() {
return Err(Errno(EINVAL)); return Err(Errno(EINVAL));
} }
@@ -698,9 +697,9 @@ impl Pal for Sys {
} }
fn getpriority(which: c_int, who: id_t) -> Result<c_int> { 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) => { 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) Ok(posix_prio)
} }
Err(e) => Err(Errno(e.errno)), Err(e) => Err(Errno(e.errno)),
@@ -851,7 +850,7 @@ impl Pal for Sys {
if (flags & !(AT_SYMLINK_FOLLOW)) != 0 { if (flags & !(AT_SYMLINK_FOLLOW)) != 0 {
return Err(Errno(EINVAL)); 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. // By default, we don't follow the symlink if there is one.
// We only follow it if AT_SYMLINK_FOLLOW is passed in flags. // 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() }; redox_rmtp = unsafe { (&*rmtp).into() };
} }
match redox_rt::sys::posix_nanosleep(&redox_rqtp, &mut redox_rmtp) { match redox_rt::sys::posix_nanosleep(&redox_rqtp, &mut redox_rmtp) {
Ok(_) => Ok(()), Ok(()) => Ok(()),
Err(Error { errno: EINTR }) => { Err(Error { errno: EINTR }) => {
unsafe { unsafe {
if !rmtp.is_null() { if !rmtp.is_null() {
@@ -1040,7 +1039,7 @@ impl Pal for Sys {
let total_offset = offset.checked_add(length).ok_or(Errno(EFBIG))?; let total_offset = offset.checked_add(length).ok_or(Errno(EFBIG))?;
let mut stat: stat = unsafe { mem::zeroed() }; 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; let st_size = stat.st_size as u64;
// The difference between total_offset and the file size is the number of bytes to // 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 // 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]) let redox_path = str::from_utf8(&buf[..count])
.ok() .ok()
.and_then(|x| redox_path::RedoxPath::from_absolute(x)) .and_then(redox_path::RedoxPath::from_absolute)
.ok_or(Errno(EINVAL))?; .ok_or(Errno(EINVAL))?;
let (scheme, reference) = redox_path.as_parts().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 clamped_prio = prio.clamp(-20, 19);
let kernel_prio = (20 + clamped_prio) as u32; let kernel_prio = (20 + clamped_prio) as u32;
match redox_rt::sys::posix_setpriority(which, who as u32, kernel_prio) { match redox_rt::sys::posix_setpriority(which, who, kernel_prio) {
Ok(_) => Ok(()), Ok(()) => Ok(()),
Err(e) => Err(Errno(e.errno)), 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")?; 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", CLOCK_MONOTONIC => "/scheme/time/4",
_ => return Err(Errno(EINVAL)), _ => 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 { let eventfd = FdGuard::new(Error::demux(unsafe {
event::redox_event_queue_create_v1(0) 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(); let mut memory_pointer: *mut timer_internal_t = ptr::null_mut();
unsafe { unsafe {
let result = posix_memalign( let result = posix_memalign(
(&mut memory_pointer as *mut *mut timer_internal_t).cast(), (&raw mut memory_pointer).cast(),
align_of::<timer_internal_t>(), align_of::<timer_internal_t>(),
size_of::<timer_internal_t>(), size_of::<timer_internal_t>(),
); );
@@ -1653,36 +1652,44 @@ impl Pal for Sys {
Ok(()) Ok(())
} }
#[expect(clippy::not_unsafe_ptr_arg_deref)]
fn timer_delete(timerid: timer_t) -> Result<()> { fn timer_delete(timerid: timer_t) -> Result<()> {
let timers = &mut TIMERS.lock().0; let timers = &mut TIMERS.lock().0;
let removed = timers.remove(&timerid); let removed = timers.remove(&timerid);
if !removed { if !removed {
return Err(Errno(EINVAL)); 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 timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let _ = redox_rt::sys::close(timer_st.timerfd); let _ = redox_rt::sys::close(timer_st.timerfd);
let _ = redox_rt::sys::close(timer_st.eventfd); let _ = redox_rt::sys::close(timer_st.eventfd);
if !timer_st.thread.is_null() { if !timer_st.thread.is_null() {
let _ = unsafe { pthread_cancel(timer_st.thread) }; 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) }; unsafe { free(timerid) };
Ok(()) Ok(())
} }
#[expect(clippy::not_unsafe_ptr_arg_deref)]
fn timer_gettime(timerid: timer_t, mut value: Out<itimerspec>) -> Result<()> { fn timer_gettime(timerid: timer_t, mut value: Out<itimerspec>) -> Result<()> {
let timers = &mut TIMERS.lock().0; let timers = &mut TIMERS.lock().0;
if !timers.contains(&timerid) { if !timers.contains(&timerid) {
return Err(Errno(EINVAL)); 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 timer_st = unsafe { timer_internal_t::from_raw(timerid) };
let mut now = timespec::default(); let mut now = timespec::default();
Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?; Self::clock_gettime(timer_st.clockid, Out::from_mut(&mut now))?;
if timer_st.evp.sigev_notify == SIGEV_NONE { if timer_st.evp.sigev_notify == SIGEV_NONE
if timespec::subtract(&timer_st.next_wake_time.it_value, &now).is_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); // error here means the timer is disarmed
} let _ = timer_update_wake_time(timer_st);
} }
let remaining = &timer_st.next_wake_time.it_value; let remaining = &timer_st.next_wake_time.it_value;
value.write(if remaining.is_zero() { value.write(if remaining.is_zero() {
@@ -1698,6 +1705,7 @@ impl Pal for Sys {
Ok(()) Ok(())
} }
#[expect(clippy::not_unsafe_ptr_arg_deref)]
fn timer_settime( fn timer_settime(
timerid: timer_t, timerid: timer_t,
flags: c_int, flags: c_int,
@@ -1712,6 +1720,8 @@ impl Pal for Sys {
if !timers.contains(&timerid) { if !timers.contains(&timerid) {
return Err(Errno(EINVAL)); 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 timer_st = unsafe { timer_internal_t::from_raw(timerid) };
if value.it_value.is_zero() { if value.it_value.is_zero() {
@@ -1747,10 +1757,10 @@ impl Pal for Sys {
let mut tid = pthread_t::default(); let mut tid = pthread_t::default();
let result = unsafe { let result = unsafe {
pthread_create( pthread_create(
&mut tid as *mut _, &raw mut tid,
ptr::null(), ptr::null(),
timer_routine, timer_routine,
timerid as *mut c_void, timerid.cast::<c_void>(),
) )
}; };
if result != 0 { if result != 0 {
@@ -1804,21 +1814,19 @@ impl Pal for Sys {
} }
match gethostname(nodename.as_slice_mut().cast_slice_to::<u8>()) { match gethostname(nodename.as_slice_mut().cast_slice_to::<u8>()) {
Ok(_) => (), Ok(()) => (),
Err(_) => return Err(Errno(EIO)), Err(_) => return Err(Errno(EIO)),
} }
let file_path = c"/scheme/sys/uname".into(); let file_path = c"/scheme/sys/uname".into();
let mut file = match File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) { let Ok(mut file) = File::open(file_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC) else {
Ok(ok) => ok, return Err(Errno(EIO));
Err(_) => return Err(Errno(EIO)),
}; };
let mut lines = BufReader::new(&mut file).lines(); let mut lines = BufReader::new(&mut file).lines();
let mut read_line = |mut dst: Out<[u8]>| { let mut read_line = |mut dst: Out<[u8]>| {
let mut line = match lines.next() { let Some(Ok(mut line)) = lines.next() else {
Some(Ok(l)) => l, return Err(Errno(EIO));
None | Some(Err(_)) => return Err(Errno(EIO)),
}; };
line.push('\0'); line.push('\0');
let line_slice: &[u8] = line.as_bytes(); let line_slice: &[u8] = line.as_bytes();
@@ -1864,6 +1872,7 @@ impl Pal for Sys {
Ok(()) 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> { fn waitpid(pid: pid_t, stat_loc: Option<Out<'_, c_int>>, options: c_int) -> Result<pid_t> {
let res = None; let res = None;
let mut status = 0; let mut status = 0;
@@ -1962,7 +1971,7 @@ impl Sys {
len: off_t, len: off_t,
) -> Result<(off_t, off_t)> { ) -> Result<(off_t, off_t)> {
// let file_off = Self::lseek(fd, 0, SEEK_SET)?; // let file_off = Self::lseek(fd, 0, SEEK_SET)?;
match whence as i32 { match i32::from(whence) {
SEEK_SET => { SEEK_SET => {
let (start, len) = if len < 0 { let (start, len) = if len < 0 {
(start + len, -len) (start + len, -len)
+23 -14
View File
@@ -29,7 +29,7 @@ pub fn chdir(path: RedoxStr<'_>) -> Result<()> {
let (redox, fd) = match path { let (redox, fd) = match path {
RedoxStr::Absolute(path) => { RedoxStr::Absolute(path) => {
let path = path.to_standard_canon(); 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) (path.into_owned(), fd)
} }
RedoxStr::Relative(redox_reference) => { RedoxStr::Relative(redox_reference) => {
@@ -112,7 +112,7 @@ pub struct Cwd<'a> {
static CWD: RwLock<Option<Cwd<'_>>> = RwLock::new(None); static CWD: RwLock<Option<Cwd<'_>>> = RwLock::new(None);
pub fn to_cwd_path(path: &str) -> Result<CwdPath> { 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<()> { 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> { pub fn clone_cwd() -> Option<CwdPath> {
let _siglock = tmp_disable_signals(); 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> { 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 // Read symlink content
fn read_link_content<'a, 'b>( fn read_link_content<'b>(
dirfd: Option<&FdGuard>, dirfd: Option<&FdGuard>,
path: &'a str, path: &str,
is_relative: bool, is_relative: bool,
) -> Result<RedoxStr<'b>> { ) -> Result<RedoxStr<'b>> {
let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY; let resolve_flags = O_CLOEXEC | O_SYMLINK | O_RDONLY;
@@ -156,7 +156,7 @@ fn read_link_content<'a, 'b>(
log::trace!( log::trace!(
"read_link_content ({:?} {:?} {}): {:?}", "read_link_content ({:?} {:?} {}): {:?}",
dirfd, dirfd,
&path, path,
is_relative, is_relative,
fd 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 dirname = current_path_string.dirname();
let cow: Cow<'_, str> = current_path_string.into(); let cow: Cow<'_, str> = current_path_string.into();
let initial_res = open_absolute(&cow, flags); 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 { match initial_res {
Ok(fd) => return Ok(fd), Ok(fd) => return Ok(fd),
Err(e) if e == Error::new(EXDEV) => { Err(e) if e == Error::new(EXDEV) => {
@@ -309,12 +309,21 @@ pub struct FileLock(c_int);
impl FileLock { impl FileLock {
pub fn lock(fd: c_int, op: c_int) -> Result<Self> { pub fn lock(fd: c_int, op: c_int) -> Result<Self> {
if op & sys_file::LOCK_SH | sys_file::LOCK_EX == 0 { const LOCK_SH_NB: c_int = sys_file::LOCK_SH | sys_file::LOCK_NB;
return Err(Error::new(EINVAL)); 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<()> { pub fn unlock(self) -> Result<()> {
@@ -384,14 +393,14 @@ fn at_flags_to_open_flags(at_flags: c_int) -> c_int {
/// # Arguments /// # Arguments
/// * `dirfd` is a directory descriptor to which `path` is resolved. /// * `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` /// * `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. /// * `at_flags` constrains how `path` is resolved.
/// * `oflags` are flags that are passed to open. /// * `oflags` are flags that are passed to open.
/// ///
/// # Constants /// # Constants
/// `at_flags`: /// `at_flags`:
/// * AT_EMPTY_PATH returns the path at `dirfd` itself if `path` is empty. If `path` is not /// * 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`: /// `dirfd`:
/// `AT_FDCWD` is a special constant for `dirfd` that resolves `path` under the current working /// `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() { if STATE.unsafe_ref().is_none() {
STATE.unsafe_set(Some(State::new())); 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 &*state_ptr
} }
} }
@@ -193,7 +193,7 @@ unsafe fn inner_ptrace(
Ok(0) Ok(0)
} }
sys_ptrace::PTRACE_GETREGS => { 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(); let mut redox_regs = syscall::IntRegisters::default();
(&mut &session.regs).read(&mut redox_regs)?; (&mut &session.regs).read(&mut redox_regs)?;
*c_regs = user_regs_struct { *c_regs = user_regs_struct {
@@ -228,7 +228,7 @@ unsafe fn inner_ptrace(
Ok(0) Ok(0)
} }
sys_ptrace::PTRACE_SETREGS => { 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 { let redox_regs = syscall::IntRegisters {
r15: c_regs.r15 as _, r15: c_regs.r15 as _,
r14: c_regs.r14 as _, r14: c_regs.r14 as _,
+24 -4
View File
@@ -115,7 +115,14 @@ impl PalSignal for Sys {
SigactionKind::Handled { SigactionKind::Handled {
handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_int != 0 { handler: if c_act.sa_flags & crate::header::signal::SA_SIGINFO as c_int != 0 {
SignalHandler { 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 { } else {
SignalHandler { SignalHandler {
@@ -138,20 +145,33 @@ impl PalSignal for Sys {
if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) { if let (Some(c_oact), Some(old_action)) = (c_oact, old_action) {
*c_oact = match old_action.kind { *c_oact = match old_action.kind {
SigactionKind::Ignore => sigaction { 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_flags: 0,
sa_restorer: None, sa_restorer: None,
sa_mask: 0, sa_mask: 0,
}, },
SigactionKind::Default => sigaction { 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_flags: 0,
sa_restorer: None, sa_restorer: None,
sa_mask: 0, sa_mask: 0,
}, },
SigactionKind::Handled { handler } => sigaction { SigactionKind::Handled { handler } => sigaction {
sa_handler: if old_action.flags.contains(SigactionFlags::SIGINFO) { 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 { } else {
unsafe { handler.handler } 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 core::{cmp, mem, ptr, slice, str};
use redox_path::RedoxStr; use redox_path::RedoxStr;
use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall}; use redox_protocols::protocol::{FsCall, O_CLOEXEC, SocketCall};
@@ -42,16 +42,16 @@ unsafe fn bind_or_connect(
return Err(Errno(EINVAL)); 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 => { AF_INET => {
if (address_len as usize) != mem::size_of::<sockaddr_in>() { if (address_len as usize) != mem::size_of::<sockaddr_in>() {
return Err(Errno(EINVAL)); return Err(Errno(EINVAL));
} }
let data = unsafe { &*(address as *const sockaddr_in) }; let data = unsafe { &*address.cast::<sockaddr_in>() };
let addr = unsafe { let addr = unsafe {
slice::from_raw_parts( 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), mem::size_of_val(&data.sin_addr.s_addr),
) )
}; };
@@ -78,7 +78,7 @@ unsafe fn bind_or_connect(
} }
SocketCall::Connect => { SocketCall::Connect => {
// When a connect is made using AF_UNSPEC TCP and UDP need to disconnect from the default peer // When a connect is made using AF_UNSPEC TCP and UDP need to disconnect from the default peer
format!("disconnect") "disconnect".to_string()
} }
_ => unreachable!(), _ => 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) { 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; data.sun_family = AF_UNIX as c_ushort;
let path = unsafe { 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()); 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 // Make address be followed by a NUL-byte
colon[0] = b'\0'; 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(); let mut addr = in_addr::default();
assert_eq!( 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, 1,
"inet_aton might be broken, failed to parse netstack address" "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)); let len = cmp::min(unsafe { *address_len } as usize, mem::size_of_val(&ret));
unsafe { 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; *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_usize: Vec<usize> = c_fds.iter().map(|&fd| fd as usize).collect();
let fds_slice = unsafe { let fds_slice = unsafe {
slice::from_raw_parts( slice::from_raw_parts(
fds_usize.as_ptr() as *const u8, fds_usize.as_ptr().cast::<u8>(),
fds_usize.len() * mem::size_of::<usize>(), 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. // Serialize to ancillary_data_stream.
@@ -300,7 +300,7 @@ unsafe fn serialize_ancillary_data_to_stream(
(SOL_SOCKET, SCM_CREDENTIALS) => { (SOL_SOCKET, SCM_CREDENTIALS) => {
// Our intermediate format: data_len is 0, no data payload // Our intermediate format: data_len is 0, no data payload
let data_for_stream_len = 0usize; 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)); return Err(Errno(EOPNOTSUPP));
@@ -330,8 +330,8 @@ unsafe fn deserialize_name_from_stream(
(unsafe { (unsafe {
inner_get_name_inner( inner_get_name_inner(
false, false,
mhdr.msg_name as *mut sockaddr, mhdr.msg_name.cast::<sockaddr>(),
&mut mhdr.msg_namelen, &raw mut mhdr.msg_namelen,
name_buffer, name_buffer,
) )
})?; })?;
@@ -380,7 +380,7 @@ unsafe fn deserialize_payload_from_stream(
let bytes_to_write = cmp::min(iov.iov_len, source_bytes_remaining); let bytes_to_write = cmp::min(iov.iov_len, source_bytes_remaining);
if bytes_to_write > 0 { if bytes_to_write > 0 {
let dest_slice: &mut [u8] = 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 let source_sub_slice = &payload_data_from_stream
[source_bytes_consumed..source_bytes_consumed + bytes_to_write]; [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>() { if cmsg_data_len_in_stream != mem::size_of::<usize>() {
return Err(Errno(EINVAL)); 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 mut fds_usize = vec![0usize; fd_count];
let fds_bytes = unsafe { let fds_bytes = unsafe {
slice::from_raw_parts_mut( 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>(), fds_usize.len() * mem::size_of::<usize>(),
) )
}; };
@@ -478,7 +478,7 @@ unsafe fn deserialize_ancillary_data_from_stream(
return Err(Errno(EINVAL)); 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_offset = mem::size_of::<pid_t>();
let uid = read_num::<uid_t>(&cmsg_data_from_stream[uid_offset..])?; let uid = read_num::<uid_t>(&cmsg_data_from_stream[uid_offset..])?;
let gid_offset = uid_offset + mem::size_of::<uid_t>(); 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 }; let cred = ucred { pid, uid, gid };
temp_posix_cmsg_data_buf.extend_from_slice(unsafe { temp_posix_cmsg_data_buf.extend_from_slice(unsafe {
slice::from_raw_parts( slice::from_raw_parts((&raw const cred).cast::<u8>(), mem::size_of::<ucred>())
&cred as *const ucred as *const u8,
mem::size_of::<ucred>(),
)
}); });
temp_posix_cmsg_data_buf.len() temp_posix_cmsg_data_buf.len()
} }
@@ -513,7 +510,7 @@ unsafe fn deserialize_ancillary_data_from_stream(
unsafe { unsafe {
ptr::copy_nonoverlapping( ptr::copy_nonoverlapping(
temp_posix_cmsg_data_buf.as_ptr(), 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, actual_posix_cmsg_data_len,
) )
}; };
@@ -539,22 +536,23 @@ impl PalSocket for Sys {
address_len: *mut socklen_t, address_len: *mut socklen_t,
) -> Result<c_int> { ) -> Result<c_int> {
let stream = redox_rt::sys::dup(socket as usize, b"listen")?; let stream = redox_rt::sys::dup(socket as usize, b"listen")?;
if address != ptr::null_mut() && address_len != ptr::null_mut() { if !address.is_null()
if let Err(err) = unsafe { Self::getpeername(stream as c_int, address, address_len) } { && !address_len.is_null()
let _ = redox_rt::sys::close(stream); && let Err(err) = unsafe { Self::getpeername(stream as c_int, address, address_len) }
return Err(err); {
} let _ = redox_rt::sys::close(stream);
return Err(err);
} }
Ok(stream as c_int) Ok(stream as c_int)
} }
unsafe fn bind(socket: c_int, address: *const sockaddr, address_len: socklen_t) -> Result<()> { 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 => { AF_INET => {
(unsafe { bind_or_connect_into(SocketCall::Bind, socket, address, address_len) })?; (unsafe { bind_or_connect_into(SocketCall::Bind, socket, address, address_len) })?;
} }
AF_UNIX => { 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 // NOTE: It's UB to access data in given address that exceeds
// the given address length. // the given address length.
@@ -569,11 +567,15 @@ impl PalSocket for Sys {
// The maximum length of the address // The maximum length of the address
maxlen, maxlen,
// The first NUL byte, if any // 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 = 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))?; let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
log::trace!("bind(): path: {:?}", path); log::trace!("bind(): path: {:?}", path);
@@ -635,12 +637,12 @@ impl PalSocket for Sys {
address: *const sockaddr, address: *const sockaddr,
address_len: socklen_t, address_len: socklen_t,
) -> Result<c_int> { ) -> Result<c_int> {
match unsafe { (*address).sa_family } as c_int { match c_int::from(unsafe { (*address).sa_family }) {
AF_INET => unsafe { AF_INET => unsafe {
bind_or_connect_into(SocketCall::Connect, socket, address, address_len) bind_or_connect_into(SocketCall::Connect, socket, address, address_len)
}, },
AF_UNIX => { 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 // NOTE: It's UB to access data in given address that exceeds
// the given address length. // the given address length.
@@ -655,11 +657,15 @@ impl PalSocket for Sys {
// The maximum length of the address // The maximum length of the address
maxlen, maxlen,
// The first NUL byte, if any // 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 = 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))?; let path = str::from_utf8(addr).map_err(|_| Errno(EINVAL))?;
log::trace!("bind(): path: {:?}", path); log::trace!("bind(): path: {:?}", path);
@@ -743,11 +749,12 @@ impl PalSocket for Sys {
return Err(Errno(EINVAL)); return Err(Errno(EINVAL));
} }
Ok(unsafe { &mut *(option_value as *mut c_int) }) Ok(unsafe { &mut *option_value.cast::<c_int>() })
}; };
match level { // TODO convert back to match when we support more levels
SOL_SOCKET => match option_name { if level == SOL_SOCKET {
match option_name {
SO_DOMAIN => { SO_DOMAIN => {
let option = option_c_int()?; let option = option_c_int()?;
*option = socket_domain_type(socket)?.0; *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 metadata = [SocketCall::GetSockOpt as u64, option_name as u64];
let payload = 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(); let call_flags = CallFlags::empty();
unsafe { unsafe {
*option_len_ptr = redox_rt::sys::sys_call_ro( *option_len_ptr = redox_rt::sys::sys_call_ro(
@@ -782,8 +789,7 @@ impl PalSocket for Sys {
} }
return Ok(()); return Ok(());
} }
}, }
_ => (),
} }
todo_skip!( todo_skip!(
@@ -813,7 +819,7 @@ impl PalSocket for Sys {
) -> Result<usize> { ) -> Result<usize> {
if address.is_null() && flags == 0 { if address.is_null() && flags == 0 {
Self::read(socket, unsafe { Self::read(socket, unsafe {
slice::from_raw_parts_mut(buf as *mut u8, len) slice::from_raw_parts_mut(buf.cast::<u8>(), len)
}) })
} else { } else {
// Convert to recvmsg // Convert to recvmsg
@@ -822,23 +828,23 @@ impl PalSocket for Sys {
iov_len: len, iov_len: len,
}; };
let mut msg = msghdr { let mut msg = msghdr {
msg_name: address as *mut c_void, msg_name: address.cast::<c_void>(),
msg_namelen: if !address_len.is_null() { msg_namelen: if !address_len.is_null() {
unsafe { *address_len } unsafe { *address_len }
} else { } else {
0 0
}, },
msg_iov: &mut iov, msg_iov: &raw mut iov,
msg_iovlen: 1, msg_iovlen: 1,
msg_control: ptr::null_mut(), msg_control: ptr::null_mut(),
msg_controllen: 0, msg_controllen: 0,
msg_flags: 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() { if !address_len.is_null() {
unsafe { *address_len = msg.msg_namelen }; unsafe { *address_len = msg.msg_namelen };
} }
return Ok(count); Ok(count)
} }
} }
@@ -846,11 +852,11 @@ impl PalSocket for Sys {
if msg.is_null() { if msg.is_null() {
return Err(Errno(EINVAL)); 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 { let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
&[] &[]
} else { } 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(); 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 + mem::size_of::<usize>() // payload_len
+ whole_iov_size // payload_data_buffer + whole_iov_size // payload_data_buffer
+ mem::size_of::<usize>() // control_len + mem::size_of::<usize>() // control_len
+ mhdr.msg_controllen as usize // ancillary_stream_buffer + mhdr.msg_controllen // ancillary_stream_buffer
}; };
msg_stream msg_stream
.try_reserve_exact(expected_stream_size) .try_reserve_exact(expected_stream_size)
@@ -883,7 +889,7 @@ impl PalSocket for Sys {
.copy_from_slice(&(whole_iov_size).to_le_bytes()); .copy_from_slice(&(whole_iov_size).to_le_bytes());
cursor += mem::size_of::<usize>(); cursor += mem::size_of::<usize>();
msg_stream[cursor..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. // Read the message stream.
let metadata = [SocketCall::RecvMsg as u64, flags as u64]; let metadata = [SocketCall::RecvMsg as u64, flags as u64];
@@ -897,12 +903,12 @@ impl PalSocket for Sys {
mhdr.msg_flags = 0; mhdr.msg_flags = 0;
// Read sender name. // 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. // Read payload data.
let actual_payload_bytes_written_to_iov = unsafe { let actual_payload_bytes_written_to_iov = unsafe {
deserialize_payload_from_stream( deserialize_payload_from_stream(
&mut mhdr, mhdr,
&msg_stream, &msg_stream,
iovs_slice, iovs_slice,
whole_iov_size, whole_iov_size,
@@ -921,7 +927,7 @@ impl PalSocket for Sys {
socket, socket,
&msg_stream, &msg_stream,
&mut cursor, &mut cursor,
cmsg_space_provided_by_user as usize, cmsg_space_provided_by_user,
flags, flags,
) )
})?; })?;
@@ -943,7 +949,7 @@ impl PalSocket for Sys {
let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 { let iovs_slice: &[iovec] = if mhdr.msg_iov.is_null() || mhdr.msg_iovlen == 0 {
&[] &[]
} else { } 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(); let mut msg_stream: Vec<u8> = Vec::new();
@@ -952,7 +958,7 @@ impl PalSocket for Sys {
.try_reserve_exact( .try_reserve_exact(
mem::size_of::<usize>() // payload_len mem::size_of::<usize>() // payload_len
+ whole_iov_size // payload_data_buffer + whole_iov_size // payload_data_buffer
+ mhdr.msg_controllen as usize, // ancillary_stream_buffer + mhdr.msg_controllen, // ancillary_stream_buffer
) )
.map_err(|_| Errno(ENOMEM))?; .map_err(|_| Errno(ENOMEM))?;
@@ -960,7 +966,7 @@ impl PalSocket for Sys {
let mut actual_payload_bytes_serialized = 0; let mut actual_payload_bytes_serialized = 0;
if !mhdr.msg_iov.is_null() && mhdr.msg_iovlen > 0 { if !mhdr.msg_iov.is_null() && mhdr.msg_iovlen > 0 {
actual_payload_bytes_serialized = unsafe { 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. // Process Control Messages from msghdr and serialize them.
@@ -995,30 +1001,30 @@ impl PalSocket for Sys {
if flags != 0 { if flags != 0 {
// Convert to sendmsg // Convert to sendmsg
let mut iov = iovec { let mut iov = iovec {
iov_base: buf as *mut c_void, iov_base: buf.cast_mut(),
iov_len: len, iov_len: len,
}; };
let msg = msghdr { let msg = msghdr {
msg_name: dest_addr as *mut c_void, msg_name: dest_addr as *mut c_void,
msg_namelen: dest_len, msg_namelen: dest_len,
msg_iov: &mut iov, msg_iov: &raw mut iov,
msg_iovlen: 1, msg_iovlen: 1,
msg_control: ptr::null_mut(), msg_control: ptr::null_mut(),
msg_controllen: 0, msg_controllen: 0,
msg_flags: 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 { Self::write(socket, unsafe {
slice::from_raw_parts(buf as *const u8, len) slice::from_raw_parts(buf.cast::<u8>(), len)
}) })
} else { } else {
let fd = FdGuard::new(unsafe { let fd = FdGuard::new(unsafe {
bind_or_connect(SocketCall::Connect, socket, dest_addr, dest_len) bind_or_connect(SocketCall::Connect, socket, dest_addr, dest_len)
}?); }?);
Self::write(fd.as_c_fd().unwrap(), unsafe { 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)); 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)?); 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 { let timespec = syscall::TimeSpec {
tv_sec: timeval.tv_sec as i64, tv_sec: timeval.tv_sec,
tv_nsec, tv_nsec,
}; };
@@ -1056,8 +1062,9 @@ impl PalSocket for Sys {
Ok(()) Ok(())
}; };
match level { // TODO convert back to match when we support more levels
SOL_SOCKET => match option_name { if level == SOL_SOCKET {
match option_name {
SO_RCVTIMEO => return set_timeout(b"read_timeout"), SO_RCVTIMEO => return set_timeout(b"read_timeout"),
SO_SNDTIMEO => return set_timeout(b"write_timeout"), SO_SNDTIMEO => return set_timeout(b"write_timeout"),
_ => { _ => {
@@ -1074,8 +1081,7 @@ impl PalSocket for Sys {
)?; )?;
return Ok(()); return Ok(());
} }
}, }
_ => (),
} }
todo_skip!( todo_skip!(
@@ -1183,7 +1189,7 @@ impl NumFromBytes for i32 {
buffer buffer
.get(..mem::size_of::<i32>()) .get(..mem::size_of::<i32>())
.and_then(|slice| slice.try_into().ok()) .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 buffer
.get(..mem::size_of::<usize>()) .get(..mem::size_of::<usize>())
.and_then(|slice| slice.try_into().ok()) .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 { if let Some(fun) = timer_st.evp.sigev_notify_function {
fun(timer_st.evp.sigev_value); fun(timer_st.evp.sigev_value);
} }
} else if timer_st.evp.sigev_notify == SIGEV_SIGNAL { } else if timer_st.evp.sigev_notify == SIGEV_SIGNAL
if Sys::sigqueue( && Sys::sigqueue(
timer_st.process_pid, timer_st.process_pid,
timer_st.evp.sigev_signo as _, timer_st.evp.sigev_signo as _,
timer_st.evp.sigev_value, timer_st.evp.sigev_value,
) )
.is_err() .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) 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>() { if bytes_written < size_of::<timespec>() {
return Err(Errno(EIO)); 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_ptr = current_tcb.masters_ptr;
new_tcb.masters_len = current_tcb.masters_len; new_tcb.masters_len = current_tcb.masters_len;
new_tcb.linker_ptr = current_tcb.linker_ptr; new_tcb.linker_ptr = current_tcb.linker_ptr;
new_tcb.mspace = current_tcb.mspace;
let stack_end = unsafe { stack_base.add(stack_size) }; let stack_end = unsafe { stack_base.add(stack_size) };
let mut stack = stack_end.cast::<usize>(); let mut stack = stack_end.cast::<usize>();
+26 -47
View File
@@ -1,14 +1,13 @@
//! Startup code. //! Startup code.
use alloc::{boxed::Box, vec::Vec}; use alloc::vec::Vec;
use core::{intrinsics, ptr}; use core::{intrinsics, ptr, str::FromStr};
use crate::{ use crate::{
ALLOCATOR, c_str::CStr,
header::{libgen, stdio, stdlib}, header::{libgen, stdio, stdlib},
ld_so::{self, linker::Linker}, ld_so::{self},
platform::{self, Pal, Sys, get_auxvs, types::*}, platform::{self, Pal, Sys, get_auxvs, logger::RELIBC_LOG_ENV_VAR, types::*},
sync::mutex::Mutex,
}; };
#[repr(C)] #[repr(C)]
@@ -89,26 +88,9 @@ static mut INIT_COMPLETE: bool = false;
#[unsafe(no_mangle)] #[unsafe(no_mangle)]
static mut __relibc_init_environ: *mut *mut c_char = ptr::null_mut(); 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() { extern "C" fn init_array() {
// The thing is that we cannot guarantee if // The thing is that we cannot guarantee if
// init_array runs first or if relibc_start runs first // 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 { unsafe {
if INIT_COMPLETE { if INIT_COMPLETE {
@@ -116,15 +98,14 @@ extern "C" fn init_array() {
} }
} }
alloc_init();
io_init();
unsafe { unsafe {
if platform::environ.is_null() { if platform::environ.is_null() {
platform::environ = __relibc_init_environ; platform::environ = __relibc_init_environ;
} }
} }
io_init();
unsafe { unsafe {
crate::pthread::init(); crate::pthread::init();
INIT_COMPLETE = true 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); redox_rt::TLS_ACTIVATED.store(true, core::sync::atomic::Ordering::Relaxed);
} }
// Set up the right allocator... let is_dynamically_linked = if let Some(tcb) = unsafe { ld_so::tcb::Tcb::current() } {
// 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)));
}
#[cfg(target_os = "redox")] #[cfg(target_os = "redox")]
redox_rt::signal::setup_sighandler(&tcb.os_specific, true); redox_rt::signal::setup_sighandler(&tcb.os_specific, true);
}
!tcb.linker_ptr.is_null()
} else {
false
};
// Set up argc and argv // Set up argc and argv
let argc = sp.argc; let argc = sp.argc;
@@ -249,9 +218,19 @@ pub unsafe extern "C" fn relibc_start_v1(
} }
let auxvs = unsafe { get_auxvs(sp.auxv().cast()) }; let auxvs = unsafe { get_auxvs(sp.auxv().cast()) };
unsafe { crate::platform::init(auxvs) }; if !is_dynamically_linked {
init_array(); unsafe { crate::platform::init(auxvs) };
unsafe { crate::platform::logger::init() }; 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 // 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 $(BUILD)/bins_verify/relibc-tests: src/main.rs
mkdir -p $(BUILD)/bins_verify mkdir -p $(BUILD)/bins_verify
RUSTFLAGS="-C target-feature=-crt-static" $(CARGO_TEST) build --release --bin relibc-tests \ 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 rm -rf $(BUILD)/target
$(BUILD)/Makefile: Makefile.run.mk $(BUILD)/Makefile: Makefile.run.mk
@@ -112,7 +113,7 @@ STATIC_FLAGS+=\
ifeq ($(IS_REDOX),0) ifeq ($(IS_REDOX),0)
DYNAMIC_FLAGS+=\ DYNAMIC_FLAGS+=\
-Wl,-dynamic-linker=$(SYSROOT_TARGET)/$(LD_SO_PATH) \ -Wl,-dynamic-linker=$(SYSROOT_TARGET)/lib/$(LD_SONAME) \
-Wl,-rpath=$(SYSROOT_TARGET)/lib:\$$ORIGIN \ -Wl,-rpath=$(SYSROOT_TARGET)/lib:\$$ORIGIN \
-L $(SYSROOT)/lib \ -L $(SYSROOT)/lib \
-lc \ -lc \
+1 -2
View File
@@ -5,8 +5,6 @@ FAILING_TESTS=
else else
# Wrong modified time # Wrong modified time
FAILING_TESTS := futimens FAILING_TESTS := futimens
# Crash, mmap issue
FAILING_TESTS += malloc/usable_size
# Not a FIFO # Not a FIFO
FAILING_TESTS += mkfifo FAILING_TESTS += mkfifo
# Waitpid had EINTR # Waitpid had EINTR
@@ -72,6 +70,7 @@ EXPECT_NAMES=\
locale/duplocale \ locale/duplocale \
locale/newlocale \ locale/newlocale \
locale/setlocale \ locale/setlocale \
malloc/usable_size \
math \ math \
regex \ regex \
semaphore/lock \ semaphore/lock \
+1 -1
View File
@@ -1,2 +1,2 @@
malloc: 27 bytes 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 "test_helpers.h"
#include <assert.h>
#include <setjmp.h>
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
static sigjmp_buf jmpenv; static sigjmp_buf jmpenv;
@@ -15,6 +15,7 @@ void alarm_handler(int sig) {
int main() { int main() {
struct sigaction sa; struct sigaction sa;
sa.sa_flags = 0;
sa.sa_handler = alarm_handler; sa.sa_handler = alarm_handler;
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
@@ -27,7 +28,7 @@ int main() {
} }
alarm(1); alarm(1);
sleep(5); sleep(5);
assert(0); // unreachable assert(0); // unreachable
} }