Toolchain+Ports: Update LLVM to 14.0.1

Besides a version bump, the following changes have been made to our
toolchain infrastructure:
- LLVM/Clang is now built with -march=native if the host compiler
  supports it. An exception to this is CI, as the toolchain cache is
  shared among many different machines there.
- The LLVM tarball is not re-extracted if the hash of the applied
  patches doesn't differ.
- The patches have been split up into atomic chunks.
- Port-specific patches have been integrated into the main patches,
  which will aid in the work towards self-hosting.
- <sysroot>/usr/local/lib is now appended to the linker's search path by
  default.
- --pack-dyn-relocs=relr is appended to the linker command line by
  default, meaning ports take advantage of RELR relocations without any
  patches or additional compiler flags.

The formatting of LLVM port's package.sh has been bothering me, so I
also indented the arguments to the CMake invocation.
This commit is contained in:
Daniel Bertalan 2022-04-08 23:28:25 +02:00 committed by Brian Gianforcaro
parent 9a898df1cd
commit 01b31d9858
Notes: sideshowbarker 2024-07-17 11:34:35 +09:00
22 changed files with 664 additions and 1007 deletions

View file

@ -18,7 +18,7 @@ endif()
# Check for toolchain mismatch, user might need to rebuild toolchain
set(GCC_VERSION "11.2.0")
set(LLVM_VERSION "13.0.0")
set(LLVM_VERSION "14.0.1")
if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
set(EXPECTED_COMPILER_VERSION "${GCC_VERSION}")
else()

View file

@ -42,7 +42,7 @@ else
fi
SERENITY_ARCH="${SERENITY_ARCH:-i686}"
LLVM_VERSION="${LLVM_VERSION:-13.0.0}"
LLVM_VERSION="${LLVM_VERSION:-14.0.1}"
if [ "$SERENITY_TOOLCHAIN" = "Clang" ]; then
TOOLCHAIN_DIR="$SERENITY_SOURCE_DIR"/Toolchain/Local/clang/

View file

@ -121,7 +121,7 @@ Please make sure to keep this list up to date when adding and updating ports. :^
| [`libyaml`](libyaml/) | libyaml | 0.2.5 | https://pyyaml.org/wiki/LibYAML |
| [`libzip`](libzip/) | libzip | 1.7.3 | https://libzip.org/ |
| [`links`](links/) | Links web browser | 2.25 | http://links.twibright.com/ |
| [`llvm`](llvm/) | LLVM | 13.0.0 | https://llvm.org/ |
| [`llvm`](llvm/) | LLVM | 14.0.1 | https://llvm.org/ |
| [`lua`](lua/) | Lua | 5.3.6 | https://www.lua.org/ |
| [`luajit`](luajit/) | LuaJIT | 2.1.0-beta3 | https://luajit.org/luajit.html |
| [`luarocks`](luarocks/) | LuaRocks | 3.8.0 | https://luarocks.org/ |

View file

@ -1,54 +1,52 @@
#!/usr/bin/env -S bash ../.port_include.sh
port=llvm
useconfigure=true
version=13.0.0
workdir=llvm-project-llvmorg-${version}
version=14.0.1
workdir=llvm-project-${version}.src
configopts=("-DCMAKE_TOOLCHAIN_FILE=${SERENITY_BUILD_DIR}/CMakeToolchain.txt")
files="https://github.com/llvm/llvm-project/archive/refs/tags/llvmorg-${version}.zip llvm.zip 333a4e053fb543d9efb8dc68126d9e7a948ecb246985f2804a0ecbc5ccdb9d08"
files="https://github.com/llvm/llvm-project/releases/download/llvmorg-${version}/llvm-project-${version}.src.tar.xz llvm-project-${version}.src.tar.xz 1a3c2e57916c5a70153aaf0a0e6f1230d6368b9e0f4d04dcb9e039a31b1cd4e6"
auth_type=sha256
depends=("ncurses" "zlib")
pre_patch() {
host_env
mkdir -p llvm-host
cmake ${workdir}/llvm \
-B llvm-host \
-DLLVM_ENABLE_PROJECTS=clang
make -C llvm-host -j $(nproc) llvm-tblgen clang-tblgen
target_env
}
configure() {
# The cross compilers will be picked up from the CMake toolchain file.
# CC/CXX must point to the host compiler to let it build host tools (tblgen).
host_env
if [ "$SERENITY_TOOLCHAIN" = "Clang" ]; then
stdlib=""
unwindlib=""
exclude_atomic_builtin="OFF"
else
stdlib="libstdc++"
unwindlib="libgcc"
# Atomic builtins can't be cross-compiled with GCC. Use the libatomic port
# if the program you're building has references to symbols like __atomic_load.
exclude_atomic_builtin="ON"
fi
mkdir -p llvm-build
cmake ${workdir}/llvm \
-G Ninja \
-B llvm-build "${configopts[@]}" \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_FIND_ROOT_PATH="$SERENITY_BUILD_DIR"/Root \
-DCLANG_DEFAULT_CXX_STDLIB=$stdlib \
-DCLANG_DEFAULT_UNWINDLIB=$unwindlib \
-DCLANG_TABLEGEN=$(pwd)/llvm-host/bin/clang-tblgen \
-DCOMPILER_RT_BUILD_CRT=ON \
-DCOMPILER_RT_BUILD_ORC=OFF \
-DCOMPILER_RT_EXCLUDE_ATOMIC_BUILTIN=OFF \
-DCOMPILER_RT_OS_DIR=serenity \
-DHAVE_LIBRT=OFF \
-DLLVM_DEFAULT_TARGET_TRIPLE=$SERENITY_ARCH-pc-serenity \
-DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt" \
-DLLVM_HAVE_LIBXAR=OFF \
-DLLVM_INCLUDE_BENCHMARKS=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INSTALL_TOOLCHAIN_ONLY=ON \
-DLLVM_PTHREAD_LIB=pthread \
-DLLVM_TABLEGEN=$(pwd)/llvm-host/bin/llvm-tblgen \
-DLLVM_TARGETS_TO_BUILD=X86
-G Ninja \
-B llvm-build "${configopts[@]}" \
-DCMAKE_BUILD_TYPE=MinSizeRel \
-DCMAKE_FIND_ROOT_PATH="$SERENITY_BUILD_DIR"/Root \
-DCROSS_TOOLCHAIN_FLAGS_NATIVE="-DCMAKE_C_COMPILER=$CC;-DCMAKE_CXX_COMPILER=$CXX" \
-DCLANG_DEFAULT_CXX_STDLIB=$stdlib \
-DCLANG_DEFAULT_UNWINDLIB=$unwindlib \
-DCOMPILER_RT_BUILD_CRT=ON \
-DCOMPILER_RT_BUILD_ORC=OFF \
-DCOMPILER_RT_EXCLUDE_ATOMIC_BUILTIN=$exclude_atomic_builtin \
-DCOMPILER_RT_OS_DIR=serenity \
-DHAVE_LIBRT=OFF \
-DLLVM_DEFAULT_TARGET_TRIPLE=$SERENITY_ARCH-pc-serenity \
-DLLVM_ENABLE_PROJECTS="clang;lld;compiler-rt" \
-DLLVM_HAVE_LIBXAR=OFF \
-DLLVM_INCLUDE_BENCHMARKS=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INSTALL_TOOLCHAIN_ONLY=ON \
-DLLVM_PTHREAD_LIB=pthread \
-DLLVM_TARGETS_TO_BUILD=X86
}
build() {

1
Ports/llvm/patches Symbolic link
View file

@ -0,0 +1 @@
../../Toolchain/Patches/llvm

View file

@ -1,45 +0,0 @@
# Patches for LLVM on SerenityOS
## `insert-ifdef-serenity.patch`
This patch adds several defines in order to omit things not supported by SerenityOS.
### Status
- [ ] Local?
- [ ] Should be merged to upstream?
- [X] Resolves issue(s) with our side of things
- [x] Hack
## `remove-version-script.patch`
Instructs the linker to not build LLVM shared libraries (`libclang.so`, `libLTO.so`, etc.) with
symbol versioning, which our dynamic linker does not support.
### Status
- [ ] Local?
- [x] Should be merged to upstream?
- [X] Resolves issue(s) with our side of things
- [ ] Hack
## `toolchain.patch`
Adds support for the `$arch-pc-serenity` target to the Clang front end. This makes the compiler
look for libraries and headers in the right places, and enables some security mitigations, like
stack-smashing protection and building position-independent executables by default.
### Status
- [ ] Local?
- [x] Should be merged to upstream?
- [ ] Resolves issue(s) with our side of things
- [ ] Hack
## `llvm-backport-objcopy-update-section.patch`
Backports support for `llvm-objcopy --update-section` used by our toolchain from reviews.llvm.org/D112116.
### Status
- [ ] Local?
- [ ] Should be merged to upstream?
- [ ] Resolves issues(s) with our side of things
- [ ] Hack

View file

@ -1,113 +0,0 @@
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index c37b3a546..e51badb34 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -109,7 +109,7 @@ typedef uint_t uint;
#endif
#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__) || \
- defined(__MVS__)
+ defined(__MVS__) || defined(__serenity__)
#define STATVFS_F_FLAG(vfs) (vfs).f_flag
#else
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
@@ -531,7 +531,7 @@ static bool is_local_impl(struct STATVFS &Vfs) {
// vmount entry not found; "remote" is the conservative answer.
return false;
-#elif defined(__MVS__)
+#elif defined(__MVS__) || defined(__serenity__)
// The file system can have an arbitrary structure on z/OS; must go with the
// conservative answer.
return false;
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index be59bb023..ff8931308 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -335,7 +335,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
namespace llvm {
namespace sys {
-#ifndef _AIX
+#if !defined(_AIX) && !defined(__serenity__)
using ::wait4;
#else
static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage);
@@ -344,7 +344,7 @@ static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage);
} // namespace sys
} // namespace llvm
-#ifdef _AIX
+#if defined(_AIX) || defined(__serenity__)
#ifndef _ALL_SOURCE
extern "C" pid_t (wait4)(pid_t pid, int *status, int options,
struct rusage *usage);
@@ -357,7 +357,7 @@ pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options,
// AIX wait4 does not work well with WNOHANG.
if (!(options & WNOHANG))
- return ::wait4(pid, status, options, usage);
+ return ::waitpid(pid, status, options);
// For WNOHANG, we use waitid (which supports WNOWAIT) until the child process
// has terminated.
@@ -374,7 +374,7 @@ pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options,
// The child has already terminated, so a blocking wait on it is okay in the
// absence of indiscriminate `wait` calls from the current process (which
// would cause the call here to fail with ECHILD).
- return ::wait4(pid, status, options & ~WNOHANG, usage);
+ return ::waitpid(pid, status, options & ~WNOHANG);
}
#endif
@@ -534,10 +534,10 @@ llvm::sys::writeFileWithEncoding(StringRef FileName, StringRef Contents,
bool llvm::sys::commandLineFitsWithinSystemLimits(StringRef Program,
ArrayRef<StringRef> Args) {
- static long ArgMax = sysconf(_SC_ARG_MAX);
+ static long ArgMax = 4096;
// POSIX requires that _POSIX_ARG_MAX is 4096, which is the lowest possible
// value for ARG_MAX on a POSIX compliant system.
- static long ArgMin = _POSIX_ARG_MAX;
+ static long ArgMin = 4096;
// This the same baseline used by xargs.
long EffectiveArgMax = 128 * 1024;
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
index 7f197a50c..03bf029db 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink-executor/llvm-jitlink-executor.cpp
@@ -50,7 +50,7 @@ void printErrorAndExit(Twine ErrMsg) {
}
int openListener(std::string Host, std::string PortStr) {
-#ifndef LLVM_ON_UNIX
+#if !defined(LLVM_ON_UNIX) || defined(__serenity__)
// FIXME: Add TCP support for Windows.
printErrorAndExit("listen option not supported");
return 0;
diff --git a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
index 8bd384ec7..a28e938ec 100644
--- a/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
+++ b/llvm/tools/llvm-jitlink/llvm-jitlink.cpp
@@ -770,7 +770,7 @@ static Expected<int> connectTCPSocket(std::string Host, std::string PortStr) {
Expected<std::unique_ptr<ExecutorProcessControl>>
LLVMJITLinkRemoteExecutorProcessControl::ConnectToExecutor() {
-#ifndef LLVM_ON_UNIX
+#if !defined(LLVM_ON_UNIX) || defined(__serenity__)
// FIXME: Add TCP support for Windows.
return make_error<StringError>("-" + OutOfProcessExecutorConnect.ArgStr +
" not supported on non-unix platforms",
diff -ruN llvm-orig/llvm-project-llvmorg-12.0.0/llvm/include/llvm/Support/SwapByteOrder.h llvm-project-llvmorg-12.0.0/llvm/include/llvm/Support/SwapByteOrder.h
--- llvm-orig/llvm-project-llvmorg-12.0.0/llvm/include/llvm/Support/SwapByteOrder.h 2021-04-06 19:38:18.000000000 +0300
+++ llvm-project-llvmorg-12.0.0/llvm/include/llvm/Support/SwapByteOrder.h 2021-06-09 16:00:20.111549941 +0300
@@ -22,7 +22,7 @@
#endif
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
- defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+ defined(__Fuchsia__) || defined(__EMSCRIPTEN__) || defined(__serenity__)
#include <endian.h>
#elif defined(_AIX)
#include <sys/machine.h>

View file

@ -1 +0,0 @@
../../../Toolchain/Patches/llvm-backport-objcopy-update-section.patch

View file

@ -1,35 +0,0 @@
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index bf88dca0a..dfac32b16 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -80,7 +80,7 @@ if(MSVC)
set(LLVM_EXPORTED_SYMBOL_FILE)
endif()
-if (UNIX AND NOT APPLE)
+if (UNIX AND NOT APPLE AND NOT SERENITYOS)
set(LLVM_EXPORTED_SYMBOL_FILE)
set(USE_VERSION_SCRIPT ${LLVM_HAVE_LINK_VERSION_SCRIPT})
endif()
diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt
index 76b9a25cb..808838926 100644
--- a/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -33,7 +33,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
add_llvm_library(LLVM SHARED DISABLE_LLVM_LINK_LLVM_DYLIB SONAME ${INSTALL_WITH_TOOLCHAIN} ${SOURCES})
list(REMOVE_DUPLICATES LIB_NAMES)
- if(("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") OR (MINGW) OR (HAIKU)
+ if(("${CMAKE_SYSTEM_NAME}" STREQUAL "Linux") OR (MINGW) OR (HAIKU) OR (SERENITYOS)
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "FreeBSD")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "GNU")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
@@ -46,7 +46,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
# GNU ld doesn't resolve symbols in the version script.
set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
- if (NOT LLVM_LINKER_IS_SOLARISLD AND NOT MINGW)
+ if (NOT LLVM_LINKER_IS_SOLARISLD AND NOT MINGW AND NOT SERENITYOS)
# Solaris ld does not accept global: *; so there is no way to version *all* global symbols
set(LIB_NAMES -Wl,--version-script,${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map ${LIB_NAMES})
endif()

View file

@ -1 +0,0 @@
../../../Toolchain/Patches/llvm.patch

View file

@ -70,8 +70,8 @@ echo PREFIX is "$PREFIX"
mkdir -p "$DIR/Tarballs"
LLVM_VERSION="13.0.0"
LLVM_MD5SUM="bfc5191cbe87954952d25c6884596ccb"
LLVM_VERSION="14.0.1"
LLVM_MD5SUM="47a50c31659488a6ae562475b41d2c32"
LLVM_NAME="llvm-project-$LLVM_VERSION.src"
LLVM_PKG="$LLVM_NAME.tar.xz"
LLVM_URL="https://github.com/llvm/llvm-project/releases/download/llvmorg-$LLVM_VERSION/$LLVM_PKG"
@ -142,6 +142,25 @@ else
buildstep dependencies echo "LLD not found. Using the default linker."
fi
buildstep setup echo "Determining if LLVM should be built with -march=native..."
if [ "$ci" = "1" ]; then
# The toolchain cache is shared among all runners, which might have different CPUs.
buildstep setup echo "On a CI runner. Using the default compiler settings."
elif [ -z "${CFLAGS+x}" ] && [ -z "${CXXFLAGS+x}" ]; then
if ${CXX:-c++} -o /dev/null -march=native -xc - >/dev/null 2>/dev/null << 'PROGRAM'
int main() {}
PROGRAM
then
export CFLAGS="-march=native"
export CXXFLAGS="-march=native"
buildstep setup echo "Using -march=native for compiling LLVM."
else
buildstep setup echo "-march=native is not supported by the compiler. Using the default settings."
fi
else
buildstep setup echo "Using user-provided CFLAGS/CXXFLAGS."
fi
# === CHECK CACHE AND REUSE ===
pushd "$DIR"
@ -195,28 +214,35 @@ pushd "$DIR/Tarballs"
echo "Skipped downloading LLVM"
fi
if [ -d "$LLVM_NAME" ]; then
# Drop the previously patched extracted dir
rm -rf "${LLVM_NAME}"
# Also drop the build dir
rm -rf "$DIR/Build/clang"
fi
echo "Extracting LLVM..."
tar -xJf "$LLVM_PKG"
patch_md5="$($MD5SUM "$DIR"/Patches/llvm/*.patch)"
pushd "$LLVM_NAME"
if [ "$dev" = "1" ]; then
git init > /dev/null
git add . > /dev/null
git commit -am "BASE" > /dev/null
git am "$DIR"/Patches/llvm-backport-objcopy-update-section.patch > /dev/null
git apply "$DIR"/Patches/llvm.patch > /dev/null
else
patch -p1 < "$DIR/Patches/llvm.patch" > /dev/null
patch -p1 < "$DIR/Patches/llvm-backport-objcopy-update-section.patch" > /dev/null
if [ ! -d "$LLVM_NAME" ] || [ "$(cat $LLVM_NAME/.patch.applied)" != "$patch_md5" ]; then
if [ -d "$LLVM_NAME" ]; then
# Drop the previously patched extracted dir
rm -rf "${LLVM_NAME}"
fi
$MD5SUM "$DIR/Patches/llvm.patch" "$DIR/Patches/llvm-backport-objcopy-update-section.patch" > .patch.applied
popd
rm -rf "$DIR/Build/clang"
echo "Extracting LLVM..."
tar -xJf "$LLVM_PKG"
pushd "$LLVM_NAME"
if [ "$dev" = "1" ]; then
git init > /dev/null
git add . > /dev/null
git commit -am "BASE" > /dev/null
git am "$DIR"/Patches/llvm/*.patch > /dev/null
else
for patch in "$DIR"/Patches/llvm/*.patch; do
patch -p1 < "$patch" > /dev/null
done
fi
echo "$patch_md5" > .patch.applied
popd
else
echo "Using existing LLVM source directory"
fi
popd
# === COPY HEADERS ===
@ -273,7 +299,7 @@ pushd "$DIR/Build/clang"
${ci:+"-DLLVM_CCACHE_MAXSIZE=$LLVM_CCACHE_MAXSIZE"}
buildstep_ninja "llvm/build" ninja -j "$MAKEJOBS"
buildstep "llvm/install" ninja install/strip
buildstep_ninja "llvm/install" ninja install/strip
popd
for arch in $ARCHS; do
@ -288,8 +314,8 @@ pushd "$DIR/Build/clang"
-DCMAKE_INSTALL_PREFIX="$PREFIX" \
-C "$DIR/CMake/LLVMRuntimesConfig.cmake"
buildstep "runtimes/$arch/build" ninja -j "$MAKEJOBS"
buildstep "runtimes/$arch/install" ninja install
buildstep_ninja "runtimes/$arch/build" ninja -j "$MAKEJOBS"
buildstep_ninja "runtimes/$arch/install" ninja install
popd
done
popd

View file

@ -30,6 +30,7 @@ foreach(target i686-pc-serenity;x86_64-pc-serenity;aarch64-pc-serenity)
set(RUNTIMES_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_SYSROOT ${SERENITY_${target}_SYSROOT} CACHE PATH "")
# Prevent configure checks from trying to link to the not-yet-built startup files & libunwind.
set(RUNTIMES_${target}_CMAKE_C_FLAGS ${compiler_flags} CACHE STRING "")
set(RUNTIMES_${target}_CMAKE_CXX_FLAGS ${compiler_flags} CACHE STRING "")
set(RUNTIMES_${target}_COMPILER_RT_BUILD_CRT ON CACHE BOOL "")
@ -44,6 +45,9 @@ foreach(target i686-pc-serenity;x86_64-pc-serenity;aarch64-pc-serenity)
set(BUILTINS_${target}_CMAKE_BUILD_TYPE Release CACHE STRING "")
set(BUILTINS_${target}_CMAKE_SYSROOT ${SERENITY_${target}_SYSROOT} CACHE PATH "")
# Explicitly set these so that host CFLAGS/CXXFLAGS don't get passed to the cross compiler.
set(BUILTINS_${target}_CMAKE_C_FLAGS "" CACHE STRING "")
set(BUILTINS_${target}_CMAKE_CXX_FLAGS "" CACHE STRING "")
set(BUILTINS_${target}_COMPILER_RT_EXCLUDE_ATOMIC_BUILTIN OFF CACHE BOOL "")
set(BUILTINS_${target}_CMAKE_SYSTEM_NAME SerenityOS CACHE STRING "")
set(BUILTINS_${target}_CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} CACHE STRING "")

View file

@ -1,440 +0,0 @@
From 140a4569a033b133fc2dc1787ae83d505e03b982 Mon Sep 17 00:00:00 2001
From: Leonard Chan <leonardchan@google.com>
Date: Wed, 20 Oct 2021 13:03:49 -0700
Subject: [PATCH] Add --update-section
This is another attempt at D59351 which attempted to add --update-section, but
with some heuristics for adjusting segment/section offsets/sizes in the event
the data copied into the section is larger than the original size of the section.
We are opting to not support this case. GNU's objcopy was able to do this because
the linker and objcopy are tightly coupled enough that segment reformatting was
simpler. This is not the case with llvm-objcopy and lld where they like to be separated.
This will attempt to copy data into the section without changing any other
properties of the parent segment (if the section is part of one).
Differential Revision: https://reviews.llvm.org/D112116
---
.../llvm-objcopy/ELF/update-section.test | 176 ++++++++++++++++++
llvm/tools/llvm-objcopy/CommonConfig.h | 1 +
llvm/tools/llvm-objcopy/ConfigManager.cpp | 11 ++
llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp | 48 +++--
llvm/tools/llvm-objcopy/ELF/Object.cpp | 42 +++++
llvm/tools/llvm-objcopy/ELF/Object.h | 14 ++
llvm/tools/llvm-objcopy/ObjcopyOpts.td | 4 +
7 files changed, 281 insertions(+), 15 deletions(-)
create mode 100644 llvm/test/tools/llvm-objcopy/ELF/update-section.test
diff --git a/llvm/test/tools/llvm-objcopy/ELF/update-section.test b/llvm/test/tools/llvm-objcopy/ELF/update-section.test
new file mode 100644
index 000000000..644225557
--- /dev/null
+++ b/llvm/test/tools/llvm-objcopy/ELF/update-section.test
@@ -0,0 +1,176 @@
+# RUN: yaml2obj %s -o %t
+
+# RUN: echo -n 11112222 > %t.same
+# RUN: echo -n 00000000 > %t.zeros
+# RUN: echo -n 11 > %t.short
+# RUN: echo -n 11113333 > %t.updated
+# RUN: echo -n 111122223 > %t.larger
+
+## Update the segment section with a regular chunk of data the same size as the section.
+# RUN: llvm-objcopy --update-section=.in_segment=%t.same %t %t.same.o
+# RUN: llvm-readobj --section-headers --section-data --program-headers %t.same.o | \
+# RUN: FileCheck %s --check-prefix=NORMAL
+
+## Show that if we overwrite a given section (.in_segment) with new data, then rewrite it
+## back (from the second `--update-section`), then it should be the exact same as the
+## original file.
+# RUN: llvm-objcopy %t %t.copy.o
+# RUN: llvm-objcopy --update-section=.in_segment=%t.same --update-section=.in_segment=%t.zeros %t %t.original.o
+# RUN: cmp %t.copy.o %t.original.o
+
+## Update segment section with a smaller chunk of data. This will also update the
+## section size to the length of the new data written. This does not affect the offset
+## of any subsequent sections in the same segment as this.
+# RUN: llvm-objcopy --update-section=.in_segment=%t.short %t %t.short.o
+# RUN: llvm-readobj --section-headers --section-data --program-headers %t.short.o | \
+# RUN: FileCheck %s --check-prefix=SHORT
+
+## Ensure the data that was in a shortened section within a segment is still retained.
+## For cases where there are gaps in segments not covered by sections, the existing
+## contents are preserved.
+# RUN: od -t x1 -j 0x78 -N 16 %t.short.o | FileCheck %s --check-prefix=PRESERVED
+
+## Add a new section via --add-section, then update it.
+# RUN: llvm-objcopy --add-section=.added=%t.zeros --update-section=.added=%t.updated \
+# RUN: %t %t.updated.o
+# RUN: llvm-readobj --section-headers --section-data --program-headers %t.updated.o | \
+# RUN: FileCheck %s --check-prefix=ADD-UPDATE
+
+## Adding should always be first regardless of flag order.
+# RUN: llvm-objcopy --update-section=.added=%t.updated --add-section=.added=%t.updated \
+# RUN: %t %t.updated.o
+# RUN: llvm-readobj --section-headers --section-data --program-headers %t.updated.o | \
+# RUN: FileCheck %s --check-prefix=ADD-UPDATE
+
+## We can't update sections which don't exist.
+# RUN: not llvm-objcopy --update-section=.nosection=%t.same %t %t-err1 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR-NO-SECTION
+
+## We can't update certain types of sections.
+# RUN: not llvm-objcopy --update-section=.nobits_type=%t.same %t %t-err2 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR-NOBITS-TYPE
+# RUN: not llvm-objcopy --update-section=.null_type=%t.same %t %t-err2 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR-NULL-TYPE
+
+## Fail on trying to insert data larger than the existing section.
+# RUN: not llvm-objcopy --update-section=.in_segment=%t.larger %t %t-err3 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR-LARGER
+
+## But we can insert larger data if the section is NOT part of a segment.
+# RUN: llvm-objcopy --update-section=.not_in_segment=%t.larger %t %t.larger.o
+# RUN: llvm-readobj --section-headers --section-data --program-headers %t.larger.o | \
+# RUN: FileCheck %s --check-prefix=LONG
+
+## We should still fail on inserting larger data, even if it is superceded by a
+## valid --update-section flag.
+# RUN: not llvm-objcopy --update-section=.in_segment=%t.larger --update-section=.in_segment=%t.same %t %t-err3 2>&1 | \
+# RUN: FileCheck %s --check-prefix=ERR-LARGER
+
+## Test option parsing failures.
+# RUN: not llvm-objcopy --update-section %t %t.out 2>&1 | FileCheck %s --check-prefix=MISSING-EQ
+# RUN: not llvm-objcopy --update-section=.in_segment= %t %t.out 2>&1 | FileCheck %s --check-prefix=MISSING-FILE
+
+!ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .in_segment
+ Type: SHT_PROGBITS
+ Content: "3030303030303030"
+ - Name: .unmodified_in_segment
+ Type: SHT_PROGBITS
+ Content: "3130303030303030"
+ - Name: .nobits_type
+ Type: SHT_NOBITS
+ - Name: .not_in_segment
+ Type: SHT_PROGBITS
+ - Name: .null_type
+ Type: SHT_NULL
+ProgramHeaders:
+ - Type: PT_LOAD
+ VAddr: 0x1000
+ FirstSec: .in_segment
+## The unmodified section is for ensuring that it remains untouched (ie. its
+## offset is the same) even when the section before it is shrunk.
+ LastSec: .unmodified_in_segment
+
+# NORMAL: Name: .in_segment
+# NORMAL: Offset:
+# NORMAL-SAME: {{ }}0x78{{$}}
+# NORMAL: Size:
+# NORMAL-SAME: {{ }}8{{$}}
+# NORMAL: SectionData (
+# NORMAL-NEXT: |11112222|
+# NORMAL-NEXT: )
+# NORMAL: Name: .unmodified_in_segment
+# NORMAL: Offset:
+# NORMAL-SAME: {{ }}0x80{{$}}
+# NORMAL: Size:
+# NORMAL-SAME: {{ }}8{{$}}
+# NORMAL: SectionData (
+# NORMAL-NEXT: |10000000|
+# NORMAL-NEXT: )
+# NORMAL: ProgramHeaders [
+# NORMAL-NEXT: ProgramHeader {
+# NORMAL-NEXT: Type: PT_LOAD (0x1)
+# NORMAL: FileSize:
+# NORMAL-SAME: {{ }}16{{$}}
+# NORMAL: MemSize:
+# NORMAL-SAME: {{ }}16{{$}}
+# NORMAL: }
+# NORMAL-NEXT: ]
+
+# SHORT: Name: .in_segment
+# SHORT: Offset:
+# SHORT-SAME: {{ }}0x78{{$}}
+# SHORT: Size:
+# SHORT-SAME: {{ }}2{{$}}
+# SHORT: SectionData (
+# SHORT-NEXT: |11|
+# SHORT-NEXT: )
+# SHORT: Name: .unmodified_in_segment
+# SHORT: Offset:
+# SHORT-SAME: {{ }}0x80{{$}}
+# SHORT: Size:
+# SHORT-SAME: {{ }}8{{$}}
+# SHORT: SectionData (
+# SHORT-NEXT: |10000000|
+# SHORT-NEXT: )
+# SHORT: ProgramHeaders [
+# SHORT-NEXT: ProgramHeader {
+# SHORT-NEXT: Type: PT_LOAD (0x1)
+# SHORT: FileSize:
+# SHORT-SAME: {{ }}16{{$}}
+# SHORT: MemSize:
+# SHORT-SAME: {{ }}16{{$}}
+# SHORT: }
+# SHORT-NEXT: ]
+
+## The first 8 bytes are the modified section. The last 8 bytes are the
+## unmodified section.
+# PRESERVED: 31 31 30 30 30 30 30 30 31 30 30 30 30 30 30 30
+
+# LONG: Name: .not_in_segment
+# LONG: Size:
+# LONG-SAME: {{ }}9{{$}}
+# LONG: SectionData (
+# LONG-NEXT: |111122223|
+# LONT-NEXT: )
+
+# ADD-UPDATE: Name: .added
+# ADD-UPDATE: Size:
+# ADD-UPDATE-SAME: {{ }}8{{$}}
+# ADD-UPDATE: SectionData (
+# ADD-UPDATE-NEXT: |11113333|
+# ADD-UPDATE: )
+
+# ERR-NO-SECTION: error: {{.*}}section '.nosection' not found
+# ERR-NOBITS-TYPE: error: {{.*}}section '.nobits_type' can't be updated because it does not have contents
+# ERR-NULL-TYPE: error: {{.*}}section '.null_type' can't be updated because it does not have contents
+# ERR-LARGER: error: {{.*}}cannot fit data of size 9 into section '.in_segment' with size 8 that is part of a segment
+
+# MISSING-EQ: error: bad format for --update-section: missing '='
+# MISSING-FILE: error: bad format for --update-section: missing file name
diff --git a/llvm/tools/llvm-objcopy/CommonConfig.h b/llvm/tools/llvm-objcopy/CommonConfig.h
index 131ce5c59..b7a7a5ec7 100644
--- a/llvm/tools/llvm-objcopy/CommonConfig.h
+++ b/llvm/tools/llvm-objcopy/CommonConfig.h
@@ -210,6 +210,7 @@ struct CommonConfig {
// Repeated options
std::vector<StringRef> AddSection;
std::vector<StringRef> DumpSection;
+ std::vector<StringRef> UpdateSection;
std::vector<StringRef> RPathToAdd;
std::vector<StringRef> RPathToPrepend;
DenseMap<StringRef, StringRef> RPathsToUpdate;
diff --git a/llvm/tools/llvm-objcopy/ConfigManager.cpp b/llvm/tools/llvm-objcopy/ConfigManager.cpp
index 9f7d06b99..2840f90cb 100644
--- a/llvm/tools/llvm-objcopy/ConfigManager.cpp
+++ b/llvm/tools/llvm-objcopy/ConfigManager.cpp
@@ -887,6 +887,17 @@ objcopy::parseObjcopyOptions(ArrayRef<const char *> RawArgsArr,
"bad format for --add-section: missing file name");
Config.AddSection.push_back(ArgValue);
}
+ for (auto Arg : InputArgs.filtered(OBJCOPY_update_section)) {
+ StringRef ArgValue(Arg->getValue());
+ if (!ArgValue.contains('='))
+ return createStringError(errc::invalid_argument,
+ "bad format for --update-section: missing '='");
+ if (ArgValue.split("=").second.empty())
+ return createStringError(
+ errc::invalid_argument,
+ "bad format for --update-section: missing file name");
+ Config.UpdateSection.push_back(ArgValue);
+ }
for (auto *Arg : InputArgs.filtered(OBJCOPY_dump_section)) {
StringRef Value(Arg->getValue());
if (Value.split('=').second.empty())
diff --git a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
index 986eeca62..b9c6abdc1 100644
--- a/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/ELFObjcopy.cpp
@@ -554,6 +554,22 @@ static void addSymbol(Object &Obj, const NewSymbolInfo &SymInfo,
Sec ? (uint16_t)SYMBOL_SIMPLE_INDEX : (uint16_t)SHN_ABS, 0);
}
+static Error
+handleUserSection(StringRef Flag,
+ function_ref<Error(StringRef, ArrayRef<uint8_t>)> F) {
+ std::pair<StringRef, StringRef> SecPair = Flag.split("=");
+ StringRef SecName = SecPair.first;
+ StringRef File = SecPair.second;
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr = MemoryBuffer::getFile(File);
+ if (!BufOrErr)
+ return createFileError(File, errorCodeToError(BufOrErr.getError()));
+ std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
+ ArrayRef<uint8_t> Data(
+ reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
+ Buf->getBufferSize());
+ return F(SecName, Data);
+}
+
// This function handles the high level operations of GNU objcopy including
// handling command line options. It's important to outline certain properties
// we expect to hold of the command line operations. Any operation that "keeps"
@@ -664,21 +680,23 @@ static Error handleArgs(const CommonConfig &Config, const ELFConfig &ELFConfig,
Sec.Type = SHT_NOBITS;
for (const auto &Flag : Config.AddSection) {
- std::pair<StringRef, StringRef> SecPair = Flag.split("=");
- StringRef SecName = SecPair.first;
- StringRef File = SecPair.second;
- ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
- MemoryBuffer::getFile(File);
- if (!BufOrErr)
- return createFileError(File, errorCodeToError(BufOrErr.getError()));
- std::unique_ptr<MemoryBuffer> Buf = std::move(*BufOrErr);
- ArrayRef<uint8_t> Data(
- reinterpret_cast<const uint8_t *>(Buf->getBufferStart()),
- Buf->getBufferSize());
- OwnedDataSection &NewSection =
- Obj.addSection<OwnedDataSection>(SecName, Data);
- if (SecName.startswith(".note") && SecName != ".note.GNU-stack")
- NewSection.Type = SHT_NOTE;
+ auto AddSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
+ OwnedDataSection &NewSection =
+ Obj.addSection<OwnedDataSection>(Name, Data);
+ if (Name.startswith(".note") && Name != ".note.GNU-stack")
+ NewSection.Type = SHT_NOTE;
+ return Error::success();
+ };
+ if (Error E = handleUserSection(Flag, AddSection))
+ return E;
+ }
+
+ for (StringRef Flag : Config.UpdateSection) {
+ auto UpdateSection = [&](StringRef Name, ArrayRef<uint8_t> Data) {
+ return Obj.updateSection(Name, Data);
+ };
+ if (Error E = handleUserSection(Flag, UpdateSection))
+ return E;
}
if (!Config.AddGnuDebugLink.empty())
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.cpp b/llvm/tools/llvm-objcopy/ELF/Object.cpp
index ba91d08e5..c8a27f7a6 100644
--- a/llvm/tools/llvm-objcopy/ELF/Object.cpp
+++ b/llvm/tools/llvm-objcopy/ELF/Object.cpp
@@ -2093,6 +2093,17 @@ template <class ELFT> void ELFWriter<ELFT>::writeSegmentData() {
Size);
}
+ for (auto it : Obj.getUpdatedSections()) {
+ SectionBase *Sec = it.first;
+ ArrayRef<uint8_t> Data = it.second;
+
+ auto *Parent = Sec->ParentSegment;
+ assert(Parent && "This section should've been part of a segment.");
+ uint64_t Offset =
+ Sec->OriginalOffset - Parent->OriginalOffset + Parent->Offset;
+ llvm::copy(Data, Buf->getBufferStart() + Offset);
+ }
+
// Iterate over removed sections and overwrite their old data with zeroes.
for (auto &Sec : Obj.removedSections()) {
Segment *Parent = Sec.ParentSegment;
@@ -2110,6 +2121,37 @@ ELFWriter<ELFT>::ELFWriter(Object &Obj, raw_ostream &Buf, bool WSH,
: Writer(Obj, Buf), WriteSectionHeaders(WSH && Obj.HadShdrs),
OnlyKeepDebug(OnlyKeepDebug) {}
+Error Object::updateSection(StringRef Name, ArrayRef<uint8_t> Data) {
+ auto It = llvm::find_if(Sections,
+ [&](const SecPtr &Sec) { return Sec->Name == Name; });
+ if (It == Sections.end())
+ return createStringError(errc::invalid_argument, "section '%s' not found",
+ Name.str().c_str());
+
+ auto *OldSec = It->get();
+ if (!OldSec->hasContents())
+ return createStringError(
+ errc::invalid_argument,
+ "section '%s' can't be updated because it does not have contents",
+ Name.str().c_str());
+
+ if (Data.size() > OldSec->Size && OldSec->ParentSegment)
+ return createStringError(errc::invalid_argument,
+ "cannot fit data of size %zu into section '%s' "
+ "with size %zu that is part of a segment",
+ Data.size(), Name.str().c_str(), OldSec->Size);
+
+ if (!OldSec->ParentSegment) {
+ *It = std::make_unique<OwnedDataSection>(*OldSec, Data);
+ } else {
+ // The segment writer will be in charge of updating these contents.
+ OldSec->Size = Data.size();
+ UpdatedSections[OldSec] = Data;
+ }
+
+ return Error::success();
+}
+
Error Object::removeSections(
bool AllowBrokenLinks, std::function<bool(const SectionBase &)> ToRemove) {
diff --git a/llvm/tools/llvm-objcopy/ELF/Object.h b/llvm/tools/llvm-objcopy/ELF/Object.h
index 6fd26afa3..060a92159 100644
--- a/llvm/tools/llvm-objcopy/ELF/Object.h
+++ b/llvm/tools/llvm-objcopy/ELF/Object.h
@@ -429,6 +429,7 @@ public:
virtual void markSymbols();
virtual void
replaceSectionReferences(const DenseMap<SectionBase *, SectionBase *> &);
+ virtual bool hasContents() const { return false; }
// Notify the section that it is subject to removal.
virtual void onRemove();
};
@@ -493,6 +494,9 @@ public:
function_ref<bool(const SectionBase *)> ToRemove) override;
Error initialize(SectionTableRef SecTable) override;
void finalize() override;
+ bool hasContents() const override {
+ return Type != ELF::SHT_NOBITS && Type != ELF::SHT_NULL;
+ }
};
class OwnedDataSection : public SectionBase {
@@ -518,9 +522,15 @@ public:
OriginalOffset = SecOff;
}
+ OwnedDataSection(SectionBase &S, ArrayRef<uint8_t> Data)
+ : SectionBase(S), Data(std::begin(Data), std::end(Data)) {
+ Size = Data.size();
+ }
+
void appendHexData(StringRef HexData);
Error accept(SectionVisitor &Sec) const override;
Error accept(MutableSectionVisitor &Visitor) override;
+ bool hasContents() const override { return true; }
};
class CompressedSection : public SectionBase {
@@ -1016,6 +1026,7 @@ private:
std::vector<SecPtr> Sections;
std::vector<SegPtr> Segments;
std::vector<SecPtr> RemovedSections;
+ DenseMap<SectionBase *, std::vector<uint8_t>> UpdatedSections;
static bool sectionIsAlloc(const SectionBase &Sec) {
return Sec.Flags & ELF::SHF_ALLOC;
@@ -1066,6 +1077,9 @@ public:
return make_filter_range(make_pointee_range(Sections), sectionIsAlloc);
}
+ const auto &getUpdatedSections() const { return UpdatedSections; }
+ Error updateSection(StringRef Name, ArrayRef<uint8_t> Data);
+
SectionBase *findSection(StringRef Name) {
auto SecIt =
find_if(Sections, [&](const SecPtr &Sec) { return Sec->Name == Name; });
diff --git a/llvm/tools/llvm-objcopy/ObjcopyOpts.td b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
index 63abbe4c2..ccd7ff292 100644
--- a/llvm/tools/llvm-objcopy/ObjcopyOpts.td
+++ b/llvm/tools/llvm-objcopy/ObjcopyOpts.td
@@ -214,3 +214,7 @@ defm add_symbol
"compatibility: debug, constructor, warning, indirect, synthetic, "
"unique-object, before.">,
MetaVarName<"name=[section:]value[,flags]">;
+
+defm update_section
+ : Eq<"update-section", "Add section <name> with contents from a file <file>.">,
+ MetaVarName<"name=file">;
--
2.34.1

View file

@ -0,0 +1,81 @@
From 9ff3d5362c71dfa9b6aba1dd65a33bb6d8971164 Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 09:54:22 +0200
Subject: [PATCH 1/8] [Support] Add support for building LLVM on SerenityOS
Adds SerenityOS `#ifdef`s for platform-specific code.
We stub out wait4, as SerenityOS doesn't support querying a child
process's resource usage information.
---
llvm/include/llvm/Support/SwapByteOrder.h | 2 +-
llvm/lib/Support/Unix/Path.inc | 5 ++++-
llvm/lib/Support/Unix/Program.inc | 9 ++++++++-
3 files changed, 13 insertions(+), 3 deletions(-)
diff --git a/llvm/include/llvm/Support/SwapByteOrder.h b/llvm/include/llvm/Support/SwapByteOrder.h
index e8612ba66..f0109f4b3 100644
--- a/llvm/include/llvm/Support/SwapByteOrder.h
+++ b/llvm/include/llvm/Support/SwapByteOrder.h
@@ -22,7 +22,7 @@
#endif
#if defined(__linux__) || defined(__GNU__) || defined(__HAIKU__) || \
- defined(__Fuchsia__) || defined(__EMSCRIPTEN__)
+ defined(__Fuchsia__) || defined(__EMSCRIPTEN__) || defined(__serenity__)
#include <endian.h>
#elif defined(_AIX)
#include <sys/machine.h>
diff --git a/llvm/lib/Support/Unix/Path.inc b/llvm/lib/Support/Unix/Path.inc
index 788460d65..566628935 100644
--- a/llvm/lib/Support/Unix/Path.inc
+++ b/llvm/lib/Support/Unix/Path.inc
@@ -112,7 +112,7 @@ typedef uint_t uint;
#endif
#if defined(__NetBSD__) || defined(__DragonFly__) || defined(__GNU__) || \
- defined(__MVS__)
+ defined(__MVS__) || defined(__serenity__)
#define STATVFS_F_FLAG(vfs) (vfs).f_flag
#else
#define STATVFS_F_FLAG(vfs) (vfs).f_flags
@@ -512,6 +512,9 @@ static bool is_local_impl(struct STATVFS &Vfs) {
#elif defined(__HAIKU__)
// Haiku doesn't expose this information.
return false;
+#elif defined(__serenity__)
+ // Serenity doesn't yet support remote filesystem mounts.
+ return false;
#elif defined(__sun)
// statvfs::f_basetype contains a null-terminated FSType name of the mounted target
StringRef fstype(Vfs.f_basetype);
diff --git a/llvm/lib/Support/Unix/Program.inc b/llvm/lib/Support/Unix/Program.inc
index 089342030..3ffe064e5 100644
--- a/llvm/lib/Support/Unix/Program.inc
+++ b/llvm/lib/Support/Unix/Program.inc
@@ -336,7 +336,7 @@ static bool Execute(ProcessInfo &PI, StringRef Program,
namespace llvm {
namespace sys {
-#ifndef _AIX
+#if !defined(_AIX) && !defined(__serenity__)
using ::wait4;
#else
static pid_t (wait4)(pid_t pid, int *status, int options, struct rusage *usage);
@@ -379,6 +379,13 @@ pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options,
}
#endif
+#ifdef __serenity__
+pid_t (llvm::sys::wait4)(pid_t pid, int *status, int options,
+ struct rusage*) {
+ return ::waitpid(pid, status, options);
+}
+#endif
+
ProcessInfo llvm::sys::Wait(const ProcessInfo &PI, unsigned SecondsToWait,
bool WaitUntilTerminates, std::string *ErrMsg,
Optional<ProcessStatistics> *ProcStat) {
--
2.35.3

View file

@ -0,0 +1,59 @@
From 0cf66d1dbcd3b7c0e2ddd65177066955c41352b7 Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 09:51:24 +0200
Subject: [PATCH 2/8] [Triple] Add triple for SerenityOS
---
llvm/include/llvm/ADT/Triple.h | 8 +++++++-
llvm/lib/Support/Triple.cpp | 2 ++
2 files changed, 9 insertions(+), 1 deletion(-)
diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h
index 42277c013..b0378dd3a 100644
--- a/llvm/include/llvm/ADT/Triple.h
+++ b/llvm/include/llvm/ADT/Triple.h
@@ -205,7 +205,8 @@ public:
Hurd, // GNU/Hurd
WASI, // Experimental WebAssembly OS
Emscripten,
- LastOSType = Emscripten
+ Serenity,
+ LastOSType = Serenity
};
enum EnvironmentType {
UnknownEnvironment,
@@ -612,6 +613,11 @@ public:
return getOS() == Triple::AIX;
}
+ /// Tests whether the OS is SerenityOS
+ bool isOSSerenity() const {
+ return getOS() == Triple::Serenity;
+ }
+
/// Tests whether the OS uses the ELF binary format.
bool isOSBinFormatELF() const {
return getObjectFormat() == Triple::ELF;
diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp
index a9afcc9db..aef8c7549 100644
--- a/llvm/lib/Support/Triple.cpp
+++ b/llvm/lib/Support/Triple.cpp
@@ -224,6 +224,7 @@ StringRef Triple::getOSTypeName(OSType Kind) {
case PS4: return "ps4";
case RTEMS: return "rtems";
case Solaris: return "solaris";
+ case Serenity: return "serenity";
case TvOS: return "tvos";
case WASI: return "wasi";
case WatchOS: return "watchos";
@@ -548,6 +549,7 @@ static Triple::OSType parseOS(StringRef OSName) {
.StartsWith("hurd", Triple::Hurd)
.StartsWith("wasi", Triple::WASI)
.StartsWith("emscripten", Triple::Emscripten)
+ .StartsWith("serenity", Triple::Serenity)
.Default(Triple::UnknownOS);
}
--
2.35.3

View file

@ -1,5 +1,27 @@
From 70cbf6e9ed46f0d39f43ac4a43b9bd2cc10da6c3 Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 10:09:50 +0200
Subject: [PATCH 3/8] [Driver] Add support for SerenityOS
Adds support for the `$arch-pc-serenity` target to the Clang front end.
This makes the compiler look for libraries and headers in the right
places, and enables some security mitigations like stack-smashing
protection and position-independent code by default.
---
clang/lib/Basic/Targets.cpp | 6 +
clang/lib/Basic/Targets/OSTargets.h | 18 ++
clang/lib/Driver/CMakeLists.txt | 1 +
clang/lib/Driver/Driver.cpp | 4 +
clang/lib/Driver/ToolChain.cpp | 2 +
clang/lib/Driver/ToolChains/Arch/X86.cpp | 1 +
clang/lib/Driver/ToolChains/Serenity.cpp | 340 +++++++++++++++++++++++
clang/lib/Driver/ToolChains/Serenity.h | 99 +++++++
8 files changed, 471 insertions(+)
create mode 100644 clang/lib/Driver/ToolChains/Serenity.cpp
create mode 100644 clang/lib/Driver/ToolChains/Serenity.h
diff --git a/clang/lib/Basic/Targets.cpp b/clang/lib/Basic/Targets.cpp
index ba91d0439..42265d547 100644
index 994a491cd..066c8140b 100644
--- a/clang/lib/Basic/Targets.cpp
+++ b/clang/lib/Basic/Targets.cpp
@@ -149,6 +149,8 @@ TargetInfo *AllocateTarget(const llvm::Triple &Triple,
@ -30,10 +52,10 @@ index ba91d0439..42265d547 100644
return new X86_64TargetInfo(Triple, Opts);
}
diff --git a/clang/lib/Basic/Targets/OSTargets.h b/clang/lib/Basic/Targets/OSTargets.h
index 3fe39ed64..51e7a6cca 100644
index 3c1830d5f..b0bae0535 100644
--- a/clang/lib/Basic/Targets/OSTargets.h
+++ b/clang/lib/Basic/Targets/OSTargets.h
@@ -966,6 +966,24 @@ public:
@@ -977,6 +977,24 @@ public:
}
};
@ -59,30 +81,30 @@ index 3fe39ed64..51e7a6cca 100644
} // namespace clang
#endif // LLVM_CLANG_LIB_BASIC_TARGETS_OSTARGETS_H
diff --git a/clang/lib/Driver/CMakeLists.txt b/clang/lib/Driver/CMakeLists.txt
index 08be9f011..69038ff00 100644
index 78e8fd185..3b70257a9 100644
--- a/clang/lib/Driver/CMakeLists.txt
+++ b/clang/lib/Driver/CMakeLists.txt
@@ -67,6 +67,7 @@ add_clang_library(clangDriver
@@ -70,6 +70,7 @@ add_clang_library(clangDriver
ToolChains/OpenBSD.cpp
ToolChains/PS4CPU.cpp
ToolChains/RISCVToolchain.cpp
+ ToolChains/Serenity.cpp
ToolChains/Solaris.cpp
ToolChains/SPIRV.cpp
ToolChains/TCE.cpp
ToolChains/VEToolchain.cpp
diff --git a/clang/lib/Driver/Driver.cpp b/clang/lib/Driver/Driver.cpp
index 94a7553e2..c6b3210f6 100644
index 3bfddeefc..a75e0ee14 100644
--- a/clang/lib/Driver/Driver.cpp
+++ b/clang/lib/Driver/Driver.cpp
@@ -41,6 +41,7 @@
@@ -43,6 +43,7 @@
#include "ToolChains/PPCLinux.h"
#include "ToolChains/PS4CPU.h"
#include "ToolChains/RISCVToolchain.h"
+#include "ToolChains/Serenity.h"
#include "ToolChains/SPIRV.h"
#include "ToolChains/Solaris.h"
#include "ToolChains/TCE.h"
#include "ToolChains/VEToolchain.h"
@@ -5299,6 +5300,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
@@ -5564,6 +5565,9 @@ const ToolChain &Driver::getToolChain(const ArgList &Args,
case llvm::Triple::Fuchsia:
TC = std::make_unique<toolchains::Fuchsia>(*this, Target, Args);
break;
@ -93,10 +115,10 @@ index 94a7553e2..c6b3210f6 100644
TC = std::make_unique<toolchains::Solaris>(*this, Target, Args);
break;
diff --git a/clang/lib/Driver/ToolChain.cpp b/clang/lib/Driver/ToolChain.cpp
index 6c1b88141..c77ff78be 100644
index d657d21bf..eea53e6ac 100644
--- a/clang/lib/Driver/ToolChain.cpp
+++ b/clang/lib/Driver/ToolChain.cpp
@@ -404,6 +404,8 @@ StringRef ToolChain::getOSLibName() const {
@@ -413,6 +413,8 @@ StringRef ToolChain::getOSLibName() const {
return "sunos";
case llvm::Triple::AIX:
return "aix";
@ -106,10 +128,10 @@ index 6c1b88141..c77ff78be 100644
return getOS();
}
diff --git a/clang/lib/Driver/ToolChains/Arch/X86.cpp b/clang/lib/Driver/ToolChains/Arch/X86.cpp
index 12749c7ec..91f744a26 100644
index bfa008f96..b7f1780fd 100644
--- a/clang/lib/Driver/ToolChains/Arch/X86.cpp
+++ b/clang/lib/Driver/ToolChains/Arch/X86.cpp
@@ -100,6 +100,7 @@ std::string x86::getX86TargetCPU(const ArgList &Args,
@@ -107,6 +107,7 @@ std::string x86::getX86TargetCPU(const Driver &D, const ArgList &Args,
case llvm::Triple::OpenBSD:
return "i586";
case llvm::Triple::FreeBSD:
@ -117,31 +139,12 @@ index 12749c7ec..91f744a26 100644
return "i686";
default:
// Fallback to p4.
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 58ae08a38..8e9a3fee6 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5695,7 +5695,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
options::OPT_fno_visibility_inlines_hidden_static_local_var);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
- Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
+ if (Triple.isOSSerenity()) {
+ StringRef tls_model =
+ Args.getLastArgValue(options::OPT_ftlsmodel_EQ, "initial-exec");
+ CmdArgs.push_back(Args.MakeArgString("-ftls-model=" + tls_model));
+ } else {
+ Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
+ }
if (Args.hasFlag(options::OPT_fno_operator_names,
options::OPT_foperator_names, false))
diff --git a/clang/lib/Driver/ToolChains/Serenity.cpp b/clang/lib/Driver/ToolChains/Serenity.cpp
new file mode 100644
index 000000000..4d653d86f
index 000000000..955422438
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Serenity.cpp
@@ -0,0 +1,327 @@
@@ -0,0 +1,340 @@
+//===---- Serenity.cpp - SerenityOS ToolChain Implementation ----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
@ -173,7 +176,7 @@ index 000000000..4d653d86f
+ return false;
+ Arg *Last = Args.getLastArg(options::OPT_pie, options::OPT_no_pie,
+ options::OPT_nopie);
+ return Last ? Last->getOption().matches(options::OPT_pie) : TC.isPIEDefault();
+ return Last ? Last->getOption().matches(options::OPT_pie) : true;
+}
+
+void tools::serenity::Linker::ConstructJob(Compilation &C, const JobAction &JA,
@ -224,6 +227,19 @@ index 000000000..4d653d86f
+ CmdArgs.push_back(Output.getFilename());
+ }
+
+ const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
+ auto linkerIs = [Exec](const char* name) {
+ return llvm::sys::path::filename(Exec).equals_insensitive(name) ||
+ llvm::sys::path::stem(Exec).equals_insensitive(name);
+ };
+
+ if (linkerIs("ld.lld") || linkerIs("ld.mold")) {
+ CmdArgs.push_back("--pack-dyn-relocs=relr");
+ } else {
+ CmdArgs.push_back("-z");
+ CmdArgs.push_back("pack-relative-relocs");
+ }
+
+ if (!Args.hasArg(options::OPT_nostdlib, options::OPT_nostartfiles)) {
+ CmdArgs.push_back(Args.MakeArgString(
+ TC.GetFilePath((IsShared) ? "crt0_shared.o" : "crt0.o")));
@ -270,7 +286,7 @@ index 000000000..4d653d86f
+
+ // We supply our own sanitizer runtimes
+ // FIXME: What if we want to use Clang-supplied ones as well?
+ const SanitizerArgs &Sanitize = TC.getSanitizerArgs();
+ const SanitizerArgs &Sanitize = TC.getSanitizerArgs(Args);
+ if (Sanitize.needsUbsanRt())
+ CmdArgs.push_back("-lubsan");
+ }
@ -316,7 +332,6 @@ index 000000000..4d653d86f
+
+ Args.AddAllArgs(CmdArgs, options::OPT_T);
+
+ const char *Exec = Args.MakeArgString(TC.GetLinkerPath());
+ C.addCommand(std::make_unique<Command>(JA, *this,
+ ResponseFileSupport::AtFileCurCP(),
+ Exec, CmdArgs, Inputs, Output));
@ -328,6 +343,7 @@ index 000000000..4d653d86f
+ getProgramPaths().push_back(getDriver().getInstalledDir());
+ if (getDriver().getInstalledDir() != getDriver().Dir)
+ getProgramPaths().push_back(getDriver().Dir);
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/local/lib");
+ getFilePaths().push_back(getDriver().SysRoot + "/usr/lib");
+}
+
@ -471,7 +487,7 @@ index 000000000..4d653d86f
+}
diff --git a/clang/lib/Driver/ToolChains/Serenity.h b/clang/lib/Driver/ToolChains/Serenity.h
new file mode 100644
index 000000000..50b0dbe62
index 000000000..d414f8366
--- /dev/null
+++ b/clang/lib/Driver/ToolChains/Serenity.h
@@ -0,0 +1,99 @@
@ -547,7 +563,7 @@ index 000000000..50b0dbe62
+ bool IsIntegratedAssemblerDefault() const override { return true; }
+
+ bool isPICDefault() const override { return true; }
+ bool isPIEDefault() const override { return true; }
+ bool isPIEDefault(const llvm::opt::ArgList&) const override { return false; }
+ bool isPICDefaultForced() const override { return false; }
+
+ bool IsMathErrnoDefault() const override { return false; }
@ -574,273 +590,6 @@ index 000000000..50b0dbe62
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_DRIVER_TOOLCHAINS_SERENITY_H
diff --git a/clang/lib/Frontend/InitHeaderSearch.cpp b/clang/lib/Frontend/InitHeaderSearch.cpp
index ba9f96384..4aecfeee2 100644
--- a/clang/lib/Frontend/InitHeaderSearch.cpp
+++ b/clang/lib/Frontend/InitHeaderSearch.cpp
@@ -233,6 +233,7 @@ void InitHeaderSearch::AddDefaultCIncludePaths(const llvm::Triple &triple,
case llvm::Triple::PS4:
case llvm::Triple::ELFIAMCU:
case llvm::Triple::Fuchsia:
+ case llvm::Triple::Serenity:
break;
case llvm::Triple::Win32:
if (triple.getEnvironment() != llvm::Triple::Cygnus)
@@ -432,6 +433,7 @@ void InitHeaderSearch::AddDefaultIncludePaths(const LangOptions &Lang,
case llvm::Triple::Solaris:
case llvm::Triple::WASI:
case llvm::Triple::AIX:
+ case llvm::Triple::Serenity:
return;
case llvm::Triple::Win32:
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index 39b9120f0..1a49ac3e5 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -684,7 +684,7 @@ endif()
# TODO: Add builtins support.
-if (CRT_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux" AND NOT LLVM_USE_SANITIZER)
+if (CRT_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux|SerenityOS" AND NOT LLVM_USE_SANITIZER)
set(COMPILER_RT_HAS_CRT TRUE)
else()
set(COMPILER_RT_HAS_CRT FALSE)
diff --git a/libcxx/cmake/Modules/HandleOutOfTreeLLVM.cmake b/libcxx/cmake/Modules/HandleOutOfTreeLLVM.cmake
index ad2820b32..deaa2c380 100644
--- a/libcxx/cmake/Modules/HandleOutOfTreeLLVM.cmake
+++ b/libcxx/cmake/Modules/HandleOutOfTreeLLVM.cmake
@@ -14,6 +14,8 @@ set(LLVM_INCLUDE_DIR ${LLVM_PATH}/include CACHE PATH "Path to llvm/include")
set(LLVM_PATH ${LLVM_PATH} CACHE PATH "Path to LLVM source tree")
set(LLVM_MAIN_SRC_DIR ${LLVM_PATH})
set(LLVM_CMAKE_PATH "${LLVM_PATH}/cmake/modules")
+set(LLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+set(LLVM_LIBRARY_OUTPUT_INTDIR "${CMAKE_CURRENT_BINARY_DIR}/lib")
if (EXISTS "${LLVM_CMAKE_PATH}")
list(APPEND CMAKE_MODULE_PATH "${LLVM_CMAKE_PATH}")
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 97e33f315..179bd2a67 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -1148,6 +1148,7 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
defined(__sun__) || \
defined(__MVS__) || \
defined(_AIX) || \
+ defined(__serenity__) || \
(defined(__MINGW32__) && __has_include(<pthread.h>))
# define _LIBCPP_HAS_THREAD_API_PTHREAD
# elif defined(__Fuchsia__)
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index ad742997d..c75dcb458 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -31,7 +31,7 @@
#elif defined(__sun__)
# include <xlocale.h>
# include <__support/solaris/xlocale.h>
-#elif defined(_NEWLIB_VERSION)
+#elif defined(_NEWLIB_VERSION) || defined(__serenity__)
# include <__support/newlib/xlocale.h>
#elif defined(__OpenBSD__)
# include <__support/openbsd/xlocale.h>
@@ -490,7 +490,7 @@ public:
static const mask xdigit = _ISXDIGIT;
static const mask blank = _ISBLANK;
static const mask __regex_word = 0x80;
-#elif defined(_NEWLIB_VERSION)
+#elif defined(_NEWLIB_VERSION) || defined(__serenity__)
// Same type as Newlib's _ctype_ array in newlib/libc/include/ctype.h.
typedef char mask;
static const mask space = _S;
diff --git a/libcxx/include/__support/newlib/xlocale.h b/libcxx/include/__support/newlib/xlocale.h
index b75f9263a..f5ffb9003 100644
--- a/libcxx/include/__support/newlib/xlocale.h
+++ b/libcxx/include/__support/newlib/xlocale.h
@@ -9,7 +9,7 @@
#ifndef _LIBCPP_SUPPORT_NEWLIB_XLOCALE_H
#define _LIBCPP_SUPPORT_NEWLIB_XLOCALE_H
-#if defined(_NEWLIB_VERSION)
+#if defined(_NEWLIB_VERSION) || defined(__serenity__)
#include <cstdlib>
#include <clocale>
@@ -22,6 +22,6 @@
#include <__support/xlocale/__strtonum_fallback.h>
#endif
-#endif // _NEWLIB_VERSION
+#endif // _NEWLIB_VERSION || __serenity__
#endif
diff --git a/libcxx/include/initializer_list b/libcxx/include/initializer_list
index ea1f23467..45631ac2f 100644
--- a/libcxx/include/initializer_list
+++ b/libcxx/include/initializer_list
@@ -43,7 +43,9 @@ template<class E> const E* end(initializer_list<E> il) noexcept; // constexpr in
*/
#include <__config>
+#if !defined(__serenity__) || !defined(KERNEL)
#include <cstddef>
+#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
diff --git a/libcxx/include/locale b/libcxx/include/locale
index 8e584005d..f29f3453e 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -206,7 +206,7 @@ template <class charT> class messages_byname;
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
// Most unix variants have catopen. These are the specific ones that don't.
-# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION)
+# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__serenity__)
# define _LIBCPP_HAS_CATOPEN 1
# include <nl_types.h>
# endif
diff --git a/libcxx/include/new b/libcxx/include/new
index aefc08c16..7ee71d16b 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -310,7 +310,7 @@ inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate_unsized(void* __ptr, s
// Returns the allocated memory, or `nullptr` on failure.
inline _LIBCPP_INLINE_VISIBILITY
void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) {
-#if defined(_LIBCPP_MSVCRT_LIKE)
+#if defined(_LIBCPP_MSVCRT_LIKE) || (defined(__serenity__) && !defined(KERNEL))
return ::_aligned_malloc(__size, __alignment);
#else
void* __result = nullptr;
@@ -322,7 +322,7 @@ void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) {
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_aligned_free(void* __ptr) {
-#if defined(_LIBCPP_MSVCRT_LIKE)
+#if defined(_LIBCPP_MSVCRT_LIKE) || (defined(__serenity__) && !defined(KERNEL))
::_aligned_free(__ptr);
#else
::free(__ptr);
diff --git a/libcxx/src/include/config_elast.h b/libcxx/src/include/config_elast.h
index 7880c733f..87b25cf42 100644
--- a/libcxx/src/include/config_elast.h
+++ b/libcxx/src/include/config_elast.h
@@ -33,6 +33,8 @@
#define _LIBCPP_ELAST 4095
#elif defined(__APPLE__)
// No _LIBCPP_ELAST needed on Apple
+#elif defined(__serenity__)
+// No _LIBCPP_ELAST needed on SerenityOS
#elif defined(__sun__)
#define _LIBCPP_ELAST ESTALE
#elif defined(__MVS__)
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index d5ab8fb3b..5039c1987 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -1145,6 +1145,8 @@ ctype<char>::classic_table() noexcept
return __pctype_func();
#elif defined(__EMSCRIPTEN__)
return *__ctype_b_loc();
+#elif defined(__serenity__)
+ return _ctype_;
#elif defined(_NEWLIB_VERSION)
// Newlib has a 257-entry table in ctype_.c, where (char)0 starts at [1].
return _ctype_ + 1;
diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake
index 0c3419390..7673b9183 100644
--- a/llvm/cmake/modules/HandleLLVMOptions.cmake
+++ b/llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -228,7 +228,7 @@ endif()
# Pass -Wl,-z,defs. This makes sure all symbols are defined. Otherwise a DSO
# build might work on ELF but fail on MachO/COFF.
-if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|FreeBSD|OpenBSD|DragonFly|AIX|SunOS|OS390" OR
+if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|FreeBSD|OpenBSD|DragonFly|AIX|SunOS|OS390|SerenityOS" OR
WIN32 OR CYGWIN) AND
NOT LLVM_USE_SANITIZER)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")
diff --git a/llvm/include/llvm/ADT/Triple.h b/llvm/include/llvm/ADT/Triple.h
index 76f351405..b81556c55 100644
--- a/llvm/include/llvm/ADT/Triple.h
+++ b/llvm/include/llvm/ADT/Triple.h
@@ -199,7 +199,8 @@ public:
Hurd, // GNU/Hurd
WASI, // Experimental WebAssembly OS
Emscripten,
- LastOSType = Emscripten
+ Serenity,
+ LastOSType = Serenity
};
enum EnvironmentType {
UnknownEnvironment,
@@ -628,6 +629,11 @@ public:
return getOS() == Triple::AIX;
}
+ /// Tests whether the OS is SerenityOS
+ bool isOSSerenity() const {
+ return getOS() == Triple::Serenity;
+ }
+
/// Tests whether the OS uses the ELF binary format.
bool isOSBinFormatELF() const {
return getObjectFormat() == Triple::ELF;
diff --git a/llvm/lib/Support/Triple.cpp b/llvm/lib/Support/Triple.cpp
index 883115463..22b39d8f5 100644
--- a/llvm/lib/Support/Triple.cpp
+++ b/llvm/lib/Support/Triple.cpp
@@ -218,6 +218,7 @@ StringRef Triple::getOSTypeName(OSType Kind) {
case PS4: return "ps4";
case RTEMS: return "rtems";
case Solaris: return "solaris";
+ case Serenity: return "serenity";
case TvOS: return "tvos";
case WASI: return "wasi";
case WatchOS: return "watchos";
@@ -538,6 +539,7 @@ static Triple::OSType parseOS(StringRef OSName) {
.StartsWith("hurd", Triple::Hurd)
.StartsWith("wasi", Triple::WASI)
.StartsWith("emscripten", Triple::Emscripten)
+ .StartsWith("serenity", Triple::Serenity)
.Default(Triple::UnknownOS);
}
diff --git a/runtimes/CMakeLists.txt b/runtimes/CMakeLists.txt
index 1ffce323d..552521192 100644
--- a/runtimes/CMakeLists.txt
+++ b/runtimes/CMakeLists.txt
@@ -58,17 +58,28 @@ if(compiler_rt_path)
endif()
endif()
+# If building standalone by pointing CMake at this runtimes directory,
+# LLVM_BINARY_DIR isn't set, find_package(LLVM) will fail and these
+# intermediate paths are unset.
+if (LLVM_BINARY_DIR STREQUAL "")
+ set(LLVM_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
+endif()
+if (NOT LLVM_FOUND)
+ set(LLVM_TOOLS_BINARY_DIR ${LLVM_BINARY_DIR}/bin)
+ set(LLVM_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/lib)
+endif()
+
# Setting these variables will allow the sub-build to put their outputs into
# the library and bin directories of the top-level build.
set(LLVM_LIBRARY_OUTPUT_INTDIR ${LLVM_LIBRARY_DIR})
set(LLVM_RUNTIME_OUTPUT_INTDIR ${LLVM_TOOLS_BINARY_DIR})
# This variable makes sure that e.g. llvm-lit is found.
-set(LLVM_MAIN_SRC_DIR ${LLVM_BUILD_MAIN_SRC_DIR})
+set(LLVM_MAIN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../llvm)
set(LLVM_CMAKE_PATH ${LLVM_MAIN_SRC_DIR}/cmake/modules)
# This variable is used by individual runtimes to locate LLVM files.
-set(LLVM_PATH ${LLVM_BUILD_MAIN_SRC_DIR})
+set(LLVM_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../llvm)
if(APPLE)
set(LLVM_ENABLE_LIBCXX ON CACHE BOOL "")
--
2.35.3

View file

@ -0,0 +1,36 @@
From 50e7b15efa5f7e2ff57e998879fee28fff4a5305 Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 10:12:54 +0200
Subject: [PATCH 4/8] [Driver] Default to -ftls-model=initial-exec on
SerenityOS
This is a hack to make Clang use the initial-exec TLS model instead of
the default local-exec when building code for Serenity.
This patch should be removed when we implement proper TLS support.
---
clang/lib/Driver/ToolChains/Clang.cpp | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index f2f18e901..39d6c18fe 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -5872,7 +5872,13 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_inlines_hidden_static_local_var,
options::OPT_fno_visibility_inlines_hidden_static_local_var);
Args.AddLastArg(CmdArgs, options::OPT_fvisibility_global_new_delete_hidden);
- Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
+ if (Triple.isOSSerenity()) {
+ StringRef tls_model =
+ Args.getLastArgValue(options::OPT_ftlsmodel_EQ, "initial-exec");
+ CmdArgs.push_back(Args.MakeArgString("-ftls-model=" + tls_model));
+ } else {
+ Args.AddLastArg(CmdArgs, options::OPT_ftlsmodel_EQ);
+ }
if (Args.hasFlag(options::OPT_fnew_infallible,
options::OPT_fno_new_infallible, false))
--
2.35.3

View file

@ -0,0 +1,153 @@
From fae5030852da34db641d636ad4c599e56b92ccdf Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 10:17:13 +0200
Subject: [PATCH 5/8] [libc++] Add support for SerenityOS
This commit teaches libc++ about what features are available in our
LibC, namely:
* We do not have locale support, so no-op shims should be used in place
of the C locale API.
* The number of errno constants defined by us is given by the value of
the `ELAST` macro.
* Multithreading is implemented though the pthread library.
* Aligned memory allocation is provided by the MSVCRT-like
`_aligned_{malloc,free}` functions.
Adds a hack for a header not found error when including
`<initializer_list>` inside the SerenityOS kernel.
Makes libc++ use its builtin character type table instead of the one
provided by LibC as it is incomplete.
---
libcxx/include/__config | 6 ++++--
libcxx/include/__locale | 2 +-
libcxx/include/__support/newlib/xlocale.h | 4 ++--
libcxx/include/initializer_list | 2 ++
libcxx/include/locale | 2 +-
libcxx/include/new | 4 ++--
libcxx/src/include/config_elast.h | 2 ++
7 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 458d0c1b8..69f627294 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -1146,7 +1146,8 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
defined(__APPLE__) || \
defined(__sun__) || \
defined(__MVS__) || \
- defined(_AIX)
+ defined(_AIX) || \
+ defined(__serenity__)
# define _LIBCPP_HAS_THREAD_API_PTHREAD
# elif defined(__Fuchsia__)
// TODO(44575): Switch to C11 thread API when possible.
@@ -1225,7 +1226,8 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container(
#if defined(__BIONIC__) || defined(__NuttX__) || \
defined(__Fuchsia__) || defined(__wasi__) || \
- defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__)
+ defined(_LIBCPP_HAS_MUSL_LIBC) || defined(__OpenBSD__) || \
+ defined(__serenity__)
#define _LIBCPP_PROVIDES_DEFAULT_RUNE_TABLE
#endif
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index 51f35eece..4bc91ecb5 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -30,7 +30,7 @@
#elif defined(__sun__)
# include <xlocale.h>
# include <__support/solaris/xlocale.h>
-#elif defined(_NEWLIB_VERSION)
+#elif defined(_NEWLIB_VERSION) || defined(__serenity__)
# include <__support/newlib/xlocale.h>
#elif defined(__OpenBSD__)
# include <__support/openbsd/xlocale.h>
diff --git a/libcxx/include/__support/newlib/xlocale.h b/libcxx/include/__support/newlib/xlocale.h
index b75f9263a..f5ffb9003 100644
--- a/libcxx/include/__support/newlib/xlocale.h
+++ b/libcxx/include/__support/newlib/xlocale.h
@@ -9,7 +9,7 @@
#ifndef _LIBCPP_SUPPORT_NEWLIB_XLOCALE_H
#define _LIBCPP_SUPPORT_NEWLIB_XLOCALE_H
-#if defined(_NEWLIB_VERSION)
+#if defined(_NEWLIB_VERSION) || defined(__serenity__)
#include <cstdlib>
#include <clocale>
@@ -22,6 +22,6 @@
#include <__support/xlocale/__strtonum_fallback.h>
#endif
-#endif // _NEWLIB_VERSION
+#endif // _NEWLIB_VERSION || __serenity__
#endif
diff --git a/libcxx/include/initializer_list b/libcxx/include/initializer_list
index fefaf8cf8..c388bc246 100644
--- a/libcxx/include/initializer_list
+++ b/libcxx/include/initializer_list
@@ -43,7 +43,9 @@ template<class E> const E* end(initializer_list<E> il) noexcept; // constexpr in
*/
#include <__config>
+#if !defined(__serenity__) || !defined(KERNEL)
#include <cstddef>
+#endif
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
diff --git a/libcxx/include/locale b/libcxx/include/locale
index 7c2d2361f..229ca7258 100644
--- a/libcxx/include/locale
+++ b/libcxx/include/locale
@@ -206,7 +206,7 @@ template <class charT> class messages_byname;
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
// Most unix variants have catopen. These are the specific ones that don't.
-# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION)
+# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__serenity__)
# define _LIBCPP_HAS_CATOPEN 1
# include <nl_types.h>
# endif
diff --git a/libcxx/include/new b/libcxx/include/new
index be0d972f4..d212bae46 100644
--- a/libcxx/include/new
+++ b/libcxx/include/new
@@ -320,7 +320,7 @@ inline _LIBCPP_INLINE_VISIBILITY void __libcpp_deallocate_unsized(void* __ptr, s
// Returns the allocated memory, or `nullptr` on failure.
inline _LIBCPP_INLINE_VISIBILITY
void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) {
-#if defined(_LIBCPP_MSVCRT_LIKE)
+#if defined(_LIBCPP_MSVCRT_LIKE) || (defined(__serenity__) && !defined(KERNEL))
return ::_aligned_malloc(__size, __alignment);
#else
void* __result = nullptr;
@@ -332,7 +332,7 @@ void* __libcpp_aligned_alloc(std::size_t __alignment, std::size_t __size) {
inline _LIBCPP_INLINE_VISIBILITY
void __libcpp_aligned_free(void* __ptr) {
-#if defined(_LIBCPP_MSVCRT_LIKE)
+#if defined(_LIBCPP_MSVCRT_LIKE) || (defined(__serenity__) && !defined(KERNEL))
::_aligned_free(__ptr);
#else
::free(__ptr);
diff --git a/libcxx/src/include/config_elast.h b/libcxx/src/include/config_elast.h
index 0ed53a3b2..7fffd937e 100644
--- a/libcxx/src/include/config_elast.h
+++ b/libcxx/src/include/config_elast.h
@@ -33,6 +33,8 @@
#define _LIBCPP_ELAST 4095
#elif defined(__APPLE__)
// No _LIBCPP_ELAST needed on Apple
+#elif defined(__serenity__)
+// No _LIBCPP_ELAST needed on SerenityOS
#elif defined(__sun__)
#define _LIBCPP_ELAST ESTALE
#elif defined(__MVS__)
--
2.35.3

View file

@ -0,0 +1,25 @@
From 1cf9ec98aa817c13b94b42e4df80804a6757aa8a Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 10:20:46 +0200
Subject: [PATCH 6/8] [compiler-rt] Build crtbegin.o/crtend.o for SerenityOS
---
compiler-rt/cmake/config-ix.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake
index fc62d5ecc..7a47b7f71 100644
--- a/compiler-rt/cmake/config-ix.cmake
+++ b/compiler-rt/cmake/config-ix.cmake
@@ -696,7 +696,7 @@ endif()
# TODO: Add builtins support.
-if (CRT_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux" AND NOT LLVM_USE_SANITIZER)
+if (CRT_SUPPORTED_ARCH AND OS_NAME MATCHES "Linux|SerenityOS" AND NOT LLVM_USE_SANITIZER)
set(COMPILER_RT_HAS_CRT TRUE)
else()
set(COMPILER_RT_HAS_CRT FALSE)
--
2.35.3

View file

@ -0,0 +1,28 @@
From ac91fd973bdf23b24645336a470d5dfb31811aa6 Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Thu, 14 Apr 2022 10:21:19 +0200
Subject: [PATCH 7/8] [cmake] Allow undefined symbols on SerenityOS
Allow undefined symbols in LLVM libraries, which is needed because only
stubs are available for SerenityOS libraries when libc++ and libunwind
are built.
---
llvm/cmake/modules/HandleLLVMOptions.cmake | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/cmake/modules/HandleLLVMOptions.cmake b/llvm/cmake/modules/HandleLLVMOptions.cmake
index fcaa8f20b..c27209146 100644
--- a/llvm/cmake/modules/HandleLLVMOptions.cmake
+++ b/llvm/cmake/modules/HandleLLVMOptions.cmake
@@ -227,7 +227,7 @@ endif()
# Pass -Wl,-z,defs. This makes sure all symbols are defined. Otherwise a DSO
# build might work on ELF but fail on MachO/COFF.
-if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|FreeBSD|OpenBSD|DragonFly|AIX|SunOS|OS390" OR
+if(NOT (CMAKE_SYSTEM_NAME MATCHES "Darwin|FreeBSD|OpenBSD|DragonFly|AIX|SunOS|OS390|SerenityOS" OR
WIN32 OR CYGWIN) AND
NOT LLVM_USE_SANITIZER)
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,-z,defs")
--
2.35.3

View file

@ -0,0 +1,54 @@
From eb1dbc59eaebdefd9735b738ca30478ce1788dca Mon Sep 17 00:00:00 2001
From: Daniel Bertalan <dani@danielbertalan.dev>
Date: Mon, 18 Apr 2022 22:32:29 +0200
Subject: [PATCH 8/8] [cmake] Support building shared libLLVM and libClang for
SerenityOS
This patch tells CMake that the --whole-archive linker option should be
used for specifying the archives whose members will constitute these
shared libraries.
Symbol versioning is disabled, as the SerenityOS loader doesn't support
it, and the ELF sections that store version data would just waste space.
---
clang/tools/libclang/CMakeLists.txt | 2 +-
llvm/tools/llvm-shlib/CMakeLists.txt | 3 ++-
2 files changed, 3 insertions(+), 2 deletions(-)
diff --git a/clang/tools/libclang/CMakeLists.txt b/clang/tools/libclang/CMakeLists.txt
index 4e0647971..2e4aeeab3 100644
--- a/clang/tools/libclang/CMakeLists.txt
+++ b/clang/tools/libclang/CMakeLists.txt
@@ -80,7 +80,7 @@ if(MSVC)
set(LLVM_EXPORTED_SYMBOL_FILE)
endif()
-if (UNIX AND NOT APPLE)
+if (UNIX AND NOT APPLE AND (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "SerenityOS"))
set(LLVM_EXPORTED_SYMBOL_FILE)
set(USE_VERSION_SCRIPT ${LLVM_HAVE_LINK_VERSION_SCRIPT})
endif()
diff --git a/llvm/tools/llvm-shlib/CMakeLists.txt b/llvm/tools/llvm-shlib/CMakeLists.txt
index 8e2b78f1b..909018753 100644
--- a/llvm/tools/llvm-shlib/CMakeLists.txt
+++ b/llvm/tools/llvm-shlib/CMakeLists.txt
@@ -39,6 +39,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "OpenBSD")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "Fuchsia")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "DragonFly")
+ OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "SerenityOS")
OR ("${CMAKE_SYSTEM_NAME}" STREQUAL "SunOS")) # FIXME: It should be "GNU ld for elf"
configure_file(
${CMAKE_CURRENT_SOURCE_DIR}/simple_version_script.map.in
@@ -46,7 +47,7 @@ if(LLVM_BUILD_LLVM_DYLIB)
# GNU ld doesn't resolve symbols in the version script.
set(LIB_NAMES -Wl,--whole-archive ${LIB_NAMES} -Wl,--no-whole-archive)
- if (NOT LLVM_LINKER_IS_SOLARISLD AND NOT MINGW)
+ if (NOT LLVM_LINKER_IS_SOLARISLD AND NOT MINGW AND (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "SerenityOS"))
# Solaris ld does not accept global: *; so there is no way to version *all* global symbols
set(LIB_NAMES -Wl,--version-script,${LLVM_LIBRARY_DIR}/tools/llvm-shlib/simple_version_script.map ${LIB_NAMES})
endif()
--
2.35.3

View file

@ -0,0 +1,78 @@
# Patches for llvm on SerenityOS
## `0001-Support-Add-support-for-building-LLVM-on-SerenityOS.patch`
Add support for building LLVM on SerenityOS
Adds SerenityOS `#ifdef`s for platform-specific code.
We stub out wait4, as SerenityOS doesn't support querying a child
process's resource usage information.
## `0002-Triple-Add-triple-for-SerenityOS.patch`
Add triple for SerenityOS
## `0003-Driver-Add-support-for-SerenityOS.patch`
Add support for SerenityOS
Adds support for the `$arch-pc-serenity` target to the Clang front end.
This makes the compiler look for libraries and headers in the right
places, and enables some security mitigations like stack-smashing
protection and position-independent code by default.
## `0004-Driver-Default-to-ftls-model-initial-exec-on-Serenit.patch`
Default to -ftls-model=initial-exec on SerenityOS
This is a hack to make Clang use the initial-exec TLS model instead of
the default local-exec when building code for Serenity.
This patch should be removed when we implement proper TLS support.
## `0005-libc-Add-support-for-SerenityOS.patch`
Add support for SerenityOS
This commit teaches libc++ about what features are available in our
LibC, namely:
* We do not have locale support, so no-op shims should be used in place
of the C locale API.
* The number of errno constants defined by us is given by the value of
the `ELAST` macro.
* Multithreading is implemented though the pthread library.
* Aligned memory allocation is provided by the MSVCRT-like
`_aligned_{malloc,free}` functions.
Adds a hack for a header not found error when including
`<initializer_list>` inside the SerenityOS kernel.
Makes libc++ use its builtin character type table instead of the one
provided by LibC as it is incomplete.
## `0006-compiler-rt-Build-crtbegin.o-crtend.o-for-SerenityOS.patch`
Build crtbegin.o/crtend.o for SerenityOS
## `0007-cmake-Allow-undefined-symbols-on-SerenityOS.patch`
Allow undefined symbols on SerenityOS
Allow undefined symbols in LLVM libraries, which is needed because only
stubs are available for SerenityOS libraries when libc++ and libunwind
are built.
## `0008-cmake-Support-building-shared-libLLVM-and-libClang-f.patch`
Support building shared libLLVM and libClang for SerenityOS
This patch tells CMake that the --whole-archive linker option should be
used for specifying the archives whose members will constitute these
shared libraries.
Symbol versioning is disabled, as the SerenityOS loader doesn't support
it, and the ELF sections that store version data would just waste space.