Skip to content

Commit fc40117

Browse files
Userland/BuggieBox: Build a static-pie version
In this version we only need the dynamic loader to load this program, but any other library is contained in the generated binary, hence making it possible to embed it in emergency environment or containers. As an immediate result, the next commit would make it possible to only copy the dynamic loader and the static-pie version of BuggieBox into a containerized environment, in which it can happily run without any other dependencies anymore. Personally, this has been a goal I worked on for a very long time, and I finally succeeded to finish this patch by realizing (with the help of ChatGPT) that I needed to include the whole LibC archive during linking because of how weak symbols are being resolved with library archives vs library shared objects.
1 parent c4c6c4b commit fc40117

File tree

29 files changed

+302
-15
lines changed

29 files changed

+302
-15
lines changed

Meta/CMake/utils.cmake

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,17 @@ if (NOT COMMAND serenity_bin)
126126
endfunction()
127127
endif()
128128

129+
if (NOT COMMAND serenity_static_bin)
130+
function(serenity_static_bin target_name)
131+
serenity_install_sources()
132+
add_executable(${target_name} ${SOURCES})
133+
target_link_libraries(${target_name} PUBLIC GenericClangPlugin)
134+
set_target_properties(${target_name} PROPERTIES EXCLUDE_FROM_ALL TRUE)
135+
install(TARGETS ${target_name} RUNTIME DESTINATION bin OPTIONAL)
136+
serenity_generated_sources(${target_name})
137+
endfunction()
138+
endif()
139+
129140
if (NOT COMMAND serenity_test)
130141
function(serenity_test test_src sub_dir)
131142
cmake_parse_arguments(PARSE_ARGV 2 SERENITY_TEST "MAIN_ALREADY_DEFINED" "CUSTOM_MAIN" "LIBS")

Userland/BuggieBox/CMakeLists.txt

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ serenity_component(
44
TARGETS BuggieBox
55
)
66

7-
function (buggiebox_utility src)
7+
serenity_component(
8+
BuggieBoxStatic
9+
REQUIRED
10+
TARGETS BuggieBoxStatic
11+
)
12+
13+
function (buggiebox_utility buggiebox src)
814
get_filename_component(utility ${src} NAME_WE)
9-
target_sources(BuggieBox PRIVATE ${src})
15+
target_sources(${buggiebox} PRIVATE ${src})
1016
set_source_files_properties(${src} PROPERTIES COMPILE_DEFINITIONS "serenity_main=${utility}_main")
1117
endfunction()
1218

@@ -18,8 +24,8 @@ set(utility_srcs
1824
../Utilities/cp.cpp
1925
../Utilities/df.cpp
2026
../Utilities/env.cpp
21-
../Utilities/file.cpp
2227
../Utilities/find.cpp
28+
../Utilities/file.cpp
2329
../Utilities/id.cpp
2430
../Utilities/init.cpp
2531
../Utilities/less.cpp
@@ -44,9 +50,28 @@ serenity_bin(BuggieBox)
4450
target_sources(BuggieBox PRIVATE main.cpp)
4551
target_link_libraries(BuggieBox PRIVATE LibMain LibShellMinimal LibArchive LibCompress LibCore LibCrypto LibELF LibFileSystem LibGfx LibLine LibRegex LibAudio LibURL)
4652

53+
serenity_static_bin(BuggieBoxStatic)
54+
target_sources(BuggieBoxStatic PRIVATE main.cpp)
55+
target_link_libraries(BuggieBoxStatic PRIVATE StaticPIE_CompileOptions LibStaticPIE)
56+
57+
# If we don't include the whole archive, the linker might miss some weak symbols to override such as pthread_cond_broadcast.
58+
target_link_libraries(BuggieBoxStatic PRIVATE
59+
$<LINK_LIBRARY:WHOLE_ARCHIVE,BuggieBox_LibC>
60+
)
61+
62+
target_link_libraries(BuggieBoxStatic PRIVATE BuggieBox_LibMain
63+
BuggieBox_LibSystem BuggieBox_LibShellMinimal BuggieBox_LibCoreMinimal BuggieBox_LibCoreBasic
64+
BuggieBox_LibELF BuggieBox_LibArchive BuggieBox_LibAudio BuggieBox_LibGfx)
65+
66+
67+
foreach(file IN LISTS utility_srcs)
68+
buggiebox_utility(BuggieBox ${file})
69+
endforeach()
70+
4771
foreach(file IN LISTS utility_srcs)
48-
buggiebox_utility(${file})
72+
buggiebox_utility(BuggieBoxStatic ${file})
4973
endforeach()
5074

5175
target_sources(BuggieBox PRIVATE ../Shell/main.cpp)
76+
target_sources(BuggieBoxStatic PRIVATE ../Shell/main.cpp)
5277
set_source_files_properties( ../Shell/main.cpp PROPERTIES COMPILE_DEFINITIONS "serenity_main=sh_main")

Userland/BuggieBox/main.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
#include <AK/LexicalPath.h>
99
#include <LibMain/Main.h>
10-
#include <LibShell/Shell.h>
1110

1211
#define ENUMERATE_UTILITIES(E, ALIAS) \
1312
ALIAS(b2sum, checksum) \
@@ -126,7 +125,7 @@ static ErrorOr<int> buggiebox_main(Main::Arguments arguments)
126125
ErrorOr<int> serenity_main(Main::Arguments arguments)
127126
{
128127
LexicalPath runbase { arguments.strings[0] };
129-
if (runbase.basename() == "BuggieBox"sv) {
128+
if (runbase.basename() == "BuggieBox"sv || runbase.basename() == "BuggieBoxStatic"sv) {
130129
Main::Arguments utility_arguments = arguments;
131130
utility_arguments.argc--;
132131
utility_arguments.argv++;

Userland/DynamicLoader/CMakeLists.txt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,10 @@ set(SOURCES
33
misc.cpp
44
)
55

6+
# ===== LibPIERuntime for Static PIE programs =====
7+
add_library(LibPIERuntime STATIC misc.cpp)
8+
target_link_libraries(LibPIERuntime PRIVATE StaticPIE_CompileOptions)
9+
610
add_library(DynamicLoader_CompileOptions INTERFACE)
711
target_compile_definitions(DynamicLoader_CompileOptions INTERFACE NO_TLS _DYNAMIC_LOADER)
812
target_compile_options(DynamicLoader_CompileOptions INTERFACE -fno-rtti -fpie -ffunction-sections -fdata-sections)

Userland/Libraries/CMakeLists.txt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,3 +76,17 @@ add_subdirectory(LibWeb)
7676
add_subdirectory(LibWebSocket)
7777
add_subdirectory(LibWebView)
7878
add_subdirectory(LibXML)
79+
80+
add_library(StaticPIE_CompileOptions INTERFACE)
81+
target_compile_options(StaticPIE_CompileOptions INTERFACE -ffunction-sections -fdata-sections)
82+
target_compile_definitions(StaticPIE_CompileOptions INTERFACE NO_LIBC)
83+
target_compile_options(StaticPIE_CompileOptions INTERFACE)
84+
target_link_options(StaticPIE_CompileOptions INTERFACE -nolibc -pthread -nostartfiles -static-libgcc -static-libstdc++ -Wl,--gc-sections)
85+
add_dependencies(StaticPIE_CompileOptions install_libc_headers)
86+
87+
add_library(LibStaticPIE)
88+
target_link_libraries(LibStaticPIE
89+
PUBLIC StaticPIE_CompileOptions
90+
)
91+
target_sources(LibStaticPIE PRIVATE ./LibC/crt0_standalone.cpp)
92+
target_sources(LibStaticPIE PRIVATE ../DynamicLoader/misc.cpp)

Userland/Libraries/LibArchive/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,10 @@ set(SOURCES
66

77
serenity_lib(LibArchive archive)
88
target_link_libraries(LibArchive PRIVATE LibCompress LibCore LibCrypto)
9+
10+
# ===== LibArchive for BuggieBox =====
11+
add_library(BuggieBox_LibArchive STATIC ${SOURCES})
12+
target_link_libraries(BuggieBox_LibArchive
13+
PUBLIC StaticPIE_CompileOptions
14+
PRIVATE BuggieBox_LibCompress BuggieBox_LibCore BuggieBox_LibCrypto
15+
)

Userland/Libraries/LibAudio/CMakeLists.txt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ endif()
3737
serenity_lib(LibAudio audio)
3838
target_link_libraries(LibAudio PRIVATE LibCore LibRIFF LibIPC LibThreading LibUnicode LibCrypto)
3939

40+
if (SERENITYOS)
41+
add_library(BuggieBox_LibAudio STATIC ${SOURCES})
42+
target_link_libraries(BuggieBox_LibAudio
43+
PUBLIC StaticPIE_CompileOptions
44+
PRIVATE BuggieBox_LibCore BuggieBox_LibRIFF BuggieBox_LibIPC BuggieBox_LibThreading BuggieBox_LibUnicode BuggieBox_LibCrypto
45+
)
46+
endif()
47+
4048
if (HAVE_PULSEAUDIO)
4149
target_link_libraries(LibAudio PRIVATE pulse)
4250
target_compile_definitions(LibAudio PRIVATE HAVE_PULSEAUDIO=1)

Userland/Libraries/LibC/CMakeLists.txt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,3 +131,10 @@ target_link_libraries(DynamicLoader_LibC
131131
PUBLIC DynamicLoader_CompileOptions
132132
PRIVATE DynamicLoader_LibSystem
133133
)
134+
135+
# ===== LibC for BuggieBox =====
136+
add_library(BuggieBox_LibC STATIC ${SOURCES})
137+
target_link_libraries(BuggieBox_LibC
138+
PUBLIC StaticPIE_CompileOptions
139+
PRIVATE BuggieBox_LibSystem
140+
)
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3+
*
4+
* SPDX-License-Identifier: BSD-2-Clause
5+
*/
6+
7+
#include <AK/Types.h>
8+
#include <assert.h>
9+
#include <stdio.h>
10+
#include <stdlib.h>
11+
#include <sys/internals.h>
12+
#include <unistd.h>
13+
14+
extern "C" {
15+
16+
int main(int, char**, char**);
17+
18+
// Tell the compiler that this may be called from somewhere else.
19+
int _entry(int argc, char** argv) __attribute__((used));
20+
void _start(int, char**, char**) __attribute__((used));
21+
22+
NAKED void _start(int, char**, char**)
23+
{
24+
#if ARCH(AARCH64)
25+
asm(
26+
"mov x29, 0\n"
27+
"mov x30, 0\n"
28+
"bl _entry\n");
29+
#elif ARCH(RISCV64)
30+
asm(
31+
"li fp, 0\n"
32+
"li ra, 0\n"
33+
"tail _entry@plt\n");
34+
#elif ARCH(X86_64)
35+
asm(
36+
"push $0\n"
37+
"jmp _entry@plt\n");
38+
#else
39+
# error "Unknown architecture"
40+
#endif
41+
}
42+
43+
int _entry(int argc, char** argv)
44+
{
45+
// In the original crt0.cpp, we didn't need this line, but we don't
46+
// run with libc as **defined** dependency (i.e. shared object),
47+
// therefore the expected initialization of the dynamic libc.so that
48+
// should done by the DynamicLinker is never actually done,
49+
// specifically at DynamicLinker::initialize_libc method.
50+
// Thus, let's initialize our own "copy" of libc in this binary so
51+
// everything could work as expected.
52+
__libc_init();
53+
54+
__begin_atexit_locking();
55+
56+
int status = main(argc, argv, environ);
57+
58+
exit(status);
59+
60+
return 20150614;
61+
}
62+
}

Userland/Libraries/LibC/libcinit.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,17 @@ bool __stdio_is_initialized = false;
2525
void* __auxiliary_vector = reinterpret_cast<void*>(explode_byte(0xe1));
2626

2727
#ifndef _DYNAMIC_LOADER
28+
# ifdef NO_LIBC
29+
// NOTE: For static-PIE programs that don't depend on libc, but are not dynamic loader
30+
// we need to wait for crt0_standalone.cpp to actually call __libc_init() to ensure
31+
// we actually have a proper environment set here.
32+
// For the time being, just declare it as an empty array.
33+
char* __static_environ[] = { nullptr };
34+
char** environ = __static_environ;
35+
# else
2836
char** environ = reinterpret_cast<char**>(explode_byte(0xe2));
37+
# endif
38+
2939
uintptr_t __stack_chk_guard;
3040
#endif
3141

0 commit comments

Comments
 (0)