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:
Generated
+5
-5
@@ -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",
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|
||||||
|
|||||||
@@ -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,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
@@ -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,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
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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
@@ -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
|
||||||
"
|
"
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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(),
|
||||||
|
|||||||
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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<×pec> for syscall::TimeSpec {
|
||||||
fn from(tp: ×pec) -> Self {
|
fn from(tp: ×pec) -> Self {
|
||||||
Self {
|
Self {
|
||||||
tv_sec: tp.tv_sec as _,
|
tv_sec: tp.tv_sec as _,
|
||||||
|
|||||||
+13
-15
@@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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() {
|
||||||
|
|||||||
@@ -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>(),
|
||||||
|
|||||||
@@ -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 => {
|
||||||
|
|||||||
@@ -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>() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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"]
|
||||||
|
|||||||
@@ -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)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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(),
|
||||||
|
|||||||
@@ -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"))]
|
||||||
|
|||||||
@@ -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
@@ -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?
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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
@@ -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<×pec>) -> Result<()> {
|
unsafe fn futex_wait(addr: *mut u32, val: u32, deadline: Option<×pec>) -> 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
@@ -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
|
||||||
|
|||||||
@@ -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 _,
|
||||||
|
|||||||
@@ -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 }
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -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))?,
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
@@ -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
@@ -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 \
|
||||||
|
|||||||
@@ -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,2 +1,2 @@
|
|||||||
malloc: 27 bytes
|
malloc: 27 bytes
|
||||||
malloc_usable_size: 48 bytes
|
malloc_usable_size: 40 bytes
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user