Skip to content

Commit e034f37

Browse files
i#3161: Add pure-static-client-DR-app support (#7177)
Adds support for statically linking a client and DR into a pure-static application. The code support for this involves expecting to not find symbols via dlsym and to instead directly invoke dr_client_main(). A weak copy of dr_client_main() is added to avoid problems with static DR used in standalone mode. Since even static client libraries today pull in the shared DR library, getting CMake to build a pure static binary with a client occupies the bulk of the changes here: + A new cmake routine configure_DynamoRIO_static_client() is added which links with dynamorio_static instead of dynamorio. + Static libz libraries are identified in an admittedly hacky manner. + A new client library variant "_drstatic" is added (alongside today's base shared library and "_static" variant) for all the ext/ libraries. This is identical to "_static" except it uses configure_DynamoRIO_static_client(). A drmemtrace_drstatic variant is also added, which also links with static libz. + The drmemtrace weak dr_client_main no longer works with the new dynamorio_static weak symbol so it is instead made strong and removed completely when DRMEMTRACE_NO_MAIN is defined; a drmemtrace_nomain variant is created with this set. A new test tool.drcacheoff.purestatic is added which verifies that a static client and DR linked into a pure-static binary all work together. It is difficult to get it to link on Ubuntu20, when cross-compiling, and in other setups due to the need for a static libpthread and other requirements, so the test is limited to Ubuntu22 64-bit where it is added to the test list there and confirmed to be built and run: ``` 8/11 Test #414: code_api|tool.drcacheoff.purestatic ... Passed 2.04 sec ``` Fixes #3161
1 parent 839a2c3 commit e034f37

File tree

21 files changed

+314
-84
lines changed

21 files changed

+314
-84
lines changed

CMakeLists.txt

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# **********************************************************
2-
# Copyright (c) 2010-2024 Google, Inc. All rights reserved.
2+
# Copyright (c) 2010-2025 Google, Inc. All rights reserved.
33
# Copyright (c) 2009-2010 VMware, Inc. All rights reserved.
44
# Copyright (c) 2018 Arm Limited All rights reserved.
55
# **********************************************************
@@ -1868,6 +1868,13 @@ if (WIN32 AND NOT DISABLE_ZLIB)
18681868
set(ZLIB_FOUND OFF)
18691869
else ()
18701870
find_package(ZLIB)
1871+
# FindZLIB doesn't give us any library split so we manually
1872+
# convert to static.
1873+
set(ZLIB_STATIC_LIBRARIES "")
1874+
foreach (lib ${ZLIB_LIBRARIES})
1875+
string(REGEX REPLACE "\\.so$" ".a" newlib "${lib}")
1876+
list(APPEND ZLIB_STATIC_LIBRARIES ${newlib})
1877+
endforeach ()
18711878
endif ()
18721879
# On Ubuntu 14.10, 32-bit builds fail to link with -lsnappy, just ignore.
18731880
if (UNIX AND X64)

api/docs/release.dox

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* ******************************************************************************
2-
* Copyright (c) 2010-2024 Google, Inc. All rights reserved.
2+
* Copyright (c) 2010-2025 Google, Inc. All rights reserved.
33
* Copyright (c) 2011 Massachusetts Institute of Technology All rights reserved.
44
* Copyright (c) 2008-2010 VMware, Inc. All rights reserved.
55
* ******************************************************************************/
@@ -129,15 +129,18 @@ changes:
129129
- No compatibility changes yet.
130130

131131
Further non-compatibility-affecting changes include:
132-
- No changes yet.
132+
- Added support for statically linking clients and the DynamoRIO library into
133+
a pure-static application via a new configure_DynamoRIO_static_client() CMake
134+
function and new "_drstatic" static library CMake targets for the provided
135+
extension libraries.
133136

134137
**************************************************
135138
<hr>
136139

137140
The changes between version 11.2.0 and 11.1.0 include the following compatibility
138141
changes:
139-
- Added #dynamorio::drmemtrace::TRACE_ENTRY_VERSION_RETIRED_INSTRUCTIONS_ONLY to increase the
140-
trace version for drmemtraces with uncompleted instructions removed.
142+
- Added #dynamorio::drmemtrace::TRACE_ENTRY_VERSION_RETIRED_INSTRUCTIONS_ONLY to
143+
increase the trace version for drmemtraces with uncompleted instructions removed.
141144

142145
Further non-compatibility-affecting changes include:
143146
- Added instr_get_operation_size() and instr_set_operation_size() APIs for

clients/drcachesim/CMakeLists.txt

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# **********************************************************
2-
# Copyright (c) 2015-2024 Google, Inc. All rights reserved.
2+
# Copyright (c) 2015-2025 Google, Inc. All rights reserved.
33
# **********************************************************
44

55
# Redistribution and use in source and binary forms, with or without
@@ -98,6 +98,7 @@ if (ZLIB_FOUND)
9898
"until then, disabling zip output and fast seeking")
9999
set(zip_reader "")
100100
set(zlib_libs ${ZLIB_LIBRARIES})
101+
set(zlib_static_libs ${ZLIB_STATIC_LIBRARIES})
101102
set(ZIP_FOUND OFF)
102103
else ()
103104
file(GLOB minizip_srcs "${minizip_dir}/*.c")
@@ -117,6 +118,7 @@ if (ZLIB_FOUND)
117118
install_exported_target(minizip ${INSTALL_CLIENTS_LIB})
118119
set(zip_reader reader/zipfile_file_reader.cpp)
119120
set(zlib_libs ${ZLIB_LIBRARIES} minizip)
121+
set(zlib_static_libs ${ZLIB_STATIC_LIBRARIES} minizip)
120122
endif ()
121123
else ()
122124
# XXX: We could ship with a zlib for Windows, or build the third_party/zlib.
@@ -473,9 +475,13 @@ if (NOT AARCH64 AND NOT APPLE)
473475
endif ()
474476
target_link_libraries(scheduler_launcher ${zlib_libs})
475477

476-
macro(add_drmemtrace name type)
478+
macro(add_drmemtrace name type static_DR no_main)
477479
if (${type} STREQUAL "STATIC")
478-
set(ext_sfx "_static")
480+
if (${static_DR})
481+
set(ext_sfx "_drstatic")
482+
else ()
483+
set(ext_sfx "_static")
484+
endif ()
479485
else ()
480486
set(ext_sfx "")
481487
endif ()
@@ -519,7 +525,14 @@ macro(add_drmemtrace name type)
519525
endif()
520526

521527
add_library(${name} ${type} ${drmemtrace_srcs})
522-
configure_DynamoRIO_client(${name})
528+
if (${no_main})
529+
append_property_list(TARGET ${name} COMPILE_DEFINITIONS "DRMEMTRACE_NO_MAIN")
530+
endif ()
531+
if (${static_DR})
532+
configure_DynamoRIO_static_client(${name})
533+
else ()
534+
configure_DynamoRIO_client(${name})
535+
endif()
523536
use_DynamoRIO_extension(${name} drmgr${ext_sfx})
524537
use_DynamoRIO_extension(${name} drsyms${ext_sfx})
525538
use_DynamoRIO_extension(${name} drwrap${ext_sfx})
@@ -536,7 +549,11 @@ macro(add_drmemtrace name type)
536549
if (libsnappy)
537550
target_link_libraries(${name} snappy)
538551
endif ()
539-
target_link_libraries(${name} ${zlib_libs})
552+
if (${static_DR})
553+
target_link_libraries(${name} ${zlib_static_libs})
554+
else ()
555+
target_link_libraries(${name} ${zlib_libs})
556+
endif ()
540557
if (liblz4)
541558
target_link_libraries(${name} lz4)
542559
endif ()
@@ -547,8 +564,13 @@ macro(add_drmemtrace name type)
547564
install_target(${name} ${INSTALL_CLIENTS_LIB})
548565
endmacro()
549566

550-
add_drmemtrace(drmemtrace SHARED)
551-
add_drmemtrace(drmemtrace_static STATIC)
567+
add_drmemtrace(drmemtrace SHARED OFF OFF)
568+
# This static library links with the DR shared library and has dr_client_main:
569+
add_drmemtrace(drmemtrace_static STATIC OFF OFF)
570+
# This static library links with the DR shared library and has no dr_client_main:
571+
add_drmemtrace(drmemtrace_nomain STATIC OFF ON)
572+
# This static library links with the DR static library and has dr_client_main:
573+
add_drmemtrace(drmemtrace_drstatic STATIC ON OFF)
552574
append_property_list(TARGET drmemtrace_static COMPILE_DEFINITIONS "DRMEMTRACE_STATIC")
553575
# We export drmemtrace.h to the same place as the analysis tool headers
554576
# for simplicity, rather than sticking it into ext/include or sthg.
@@ -1083,7 +1105,7 @@ if (BUILD_TESTS)
10831105
if (LINUX) # Uses mremap.
10841106
add_executable(tool.drcacheoff.burst_maps tests/burst_maps.cpp)
10851107
configure_DynamoRIO_static(tool.drcacheoff.burst_maps)
1086-
use_DynamoRIO_static_client(tool.drcacheoff.burst_maps drmemtrace_static)
1108+
use_DynamoRIO_static_client(tool.drcacheoff.burst_maps drmemtrace_nomain)
10871109
target_link_libraries(tool.drcacheoff.burst_maps test_helpers)
10881110
add_win32_flags(tool.drcacheoff.burst_maps)
10891111
endif ()
@@ -1130,10 +1152,25 @@ if (BUILD_TESTS)
11301152
append_property_list(TARGET tool.drcacheoff.burst_client
11311153
COMPILE_DEFINITIONS "TEST_APP_DR_CLIENT_MAIN")
11321154
configure_DynamoRIO_static(tool.drcacheoff.burst_client)
1133-
use_DynamoRIO_static_client(tool.drcacheoff.burst_client drmemtrace_static)
1155+
use_DynamoRIO_static_client(tool.drcacheoff.burst_client drmemtrace_nomain)
11341156
target_link_libraries(tool.drcacheoff.burst_client test_helpers)
11351157
# A nop, keep it for the future Windows support.
11361158
add_win32_flags(tool.drcacheoff.burst_client)
1159+
1160+
# Test a pure-static-link app.
1161+
# We ignore "warning: Using 'dlopen' in statically linked applications requires
1162+
# at runtime the shared libraries from the glibc version used for linking".
1163+
# XXX: We can only successfully build this if static libpthread is available,
1164+
# which is only recent glibc 2.34+ such as Ubuntu22+. We also limit to 64-bit
1165+
# due to pain building 32-bit on a 64-bit machine.
1166+
if (X64 AND "${libpthread}" MATCHES ".a$")
1167+
add_executable(tool.drcacheoff.purestatic tests/burst_static.cpp)
1168+
append_property_list(TARGET tool.drcacheoff.purestatic
1169+
LINK_FLAGS "-static -Wl,--no-export-dynamic")
1170+
configure_DynamoRIO_static(tool.drcacheoff.purestatic)
1171+
use_DynamoRIO_static_client(tool.drcacheoff.purestatic drmemtrace_drstatic)
1172+
target_link_libraries(tool.drcacheoff.purestatic test_helpers)
1173+
endif ()
11371174
endif ()
11381175

11391176
if (NOT RISCV64) # TODO i#3544: Port tests to RISC-V 64
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
pre-DR init
2+
pre-DR start
3+
pre-DR detach
4+
DynamoRIO statistics:
5+
*Peak threads under DynamoRIO control : *1
6+
.*
7+
all done
8+
pre-DR init
9+
pre-DR start
10+
pre-DR detach
11+
DynamoRIO statistics:
12+
*Peak threads under DynamoRIO control : *1
13+
.*
14+
all done
15+
pre-DR init
16+
pre-DR start
17+
pre-DR detach
18+
DynamoRIO statistics:
19+
*Peak threads under DynamoRIO control : *1
20+
.*
21+
all done
22+
Cache simulation results:
23+
Core #0 \(traced CPU\(s\): #0\)
24+
L1I0 .* stats:
25+
Hits: *[0-9,\.]*
26+
Misses: *[0-9,\.]*
27+
Compulsory misses: *[0-9,\.]*
28+
Invalidations: *0
29+
.* Miss rate: [0-3][,\.]..%
30+
L1D0 .* stats:
31+
Hits: *[0-9,\.]*
32+
Misses: *[0-9,\.]*
33+
Compulsory misses: *[0-9,\.]*
34+
Invalidations: *0
35+
.* Miss rate: [0-3][,\.]..%
36+
Core #1 \(traced CPU\(s\): \)
37+
Core #2 \(traced CPU\(s\): \)
38+
Core #3 \(traced CPU\(s\): \)
39+
LL .* stats:
40+
Hits: *[0-9,\.]*
41+
Misses: *[0-9,\.]*
42+
Compulsory misses: *[0-9,\.]*
43+
Invalidations: *0
44+
.* Local miss rate: *[0-9,.]*%
45+
Child hits: *[0-9,\.]*
46+
Total miss rate: [0-1][,\.]..%

clients/drcachesim/tracer/tracer.cpp

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* ******************************************************************************
2-
* Copyright (c) 2011-2024 Google, Inc. All rights reserved.
2+
* Copyright (c) 2011-2025 Google, Inc. All rights reserved.
33
* Copyright (c) 2010 Massachusetts Institute of Technology All rights reserved.
44
* ******************************************************************************/
55

@@ -2538,14 +2538,17 @@ drmemtrace_client_main(client_id_t id, int argc, const char *argv[])
25382538
*/
25392539

25402540
/* To support statically linked multiple clients, we add drmemtrace_client_main
2541-
* as the real client init function and make dr_client_main a weak symbol.
2542-
* We could also use alias to link dr_client_main to drmemtrace_client_main.
2543-
* A simple call won't add too much overhead, and works both in Windows and Linux.
2544-
* To automate the process and minimize the code change, we should investigate the
2545-
* approach that uses command-line link option to alias two symbols.
2541+
* as the real client init function and let a separate dr_client_main call
2542+
* drmemtrace_client_main. Since dynamorio_static now provides its own weak
2543+
* dr_client_main symbol, we can't simply always provide a weak dr_client_main here:
2544+
* it must either be present and strong or not present, controlled by the
2545+
* DRMEMTRACE_NO_MAIN define.
25462546
*/
2547-
DR_EXPORT WEAK void
2547+
#ifndef DRMEMTRACE_NO_MAIN
2548+
DR_EXPORT
2549+
void
25482550
dr_client_main(client_id_t id, int argc, const char *argv[])
25492551
{
25502552
dynamorio::drmemtrace::drmemtrace_client_main(id, argc, argv);
25512553
}
2554+
#endif

core/lib/instrument.c

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/* ******************************************************************************
2-
* Copyright (c) 2010-2024 Google, Inc. All rights reserved.
2+
* Copyright (c) 2010-2025 Google, Inc. All rights reserved.
33
* Copyright (c) 2010-2011 Massachusetts Institute of Technology All rights reserved.
44
* Copyright (c) 2002-2010 VMware, Inc. All rights reserved.
55
* ******************************************************************************/
@@ -371,6 +371,19 @@ DECLARE_CXTSWPROT_VAR(static mutex_t client_aux_lib64_lock,
371371
INIT_LOCK_FREE(client_aux_lib64_lock));
372372
#endif
373373

374+
#if defined(STATIC_LIBRARY) && !defined(WINDOWS)
375+
// To support static DR used for both standalone and clients we need to provide
376+
// some copy of client main. There is no WEAK on Windows so we do not support
377+
// this usage there.
378+
WEAK void
379+
dr_client_main(client_id_t id, int argc, const char *argv[])
380+
{
381+
// This will be called when using static DR but no client, so we can't
382+
// assert even though this should not be reached when there is a real
383+
// client whose non-weak dr_client_main overrides this.
384+
}
385+
#endif
386+
374387
/****************************************************************************/
375388
/* INTERNAL ROUTINES */
376389

@@ -577,8 +590,16 @@ add_client_lib(const char *path, const char *id_str, const char *options)
577590
/* PR 250952: version check */
578591
int *uses_dr_version =
579592
(int *)lookup_library_routine(client_lib, USES_DR_VERSION_NAME);
580-
if (uses_dr_version == NULL || *uses_dr_version < OLDEST_COMPATIBLE_VERSION ||
581-
*uses_dr_version > NEWEST_COMPATIBLE_VERSION) {
593+
bool pure_static = false;
594+
#ifdef STATIC_LIBRARY
595+
if (uses_dr_version == NULL) {
596+
// We assume we're in a pure-static app where dlsym fails.
597+
pure_static = true;
598+
}
599+
#endif
600+
if (!pure_static &&
601+
(uses_dr_version == NULL || *uses_dr_version < OLDEST_COMPATIBLE_VERSION ||
602+
*uses_dr_version > NEWEST_COMPATIBLE_VERSION)) {
582603
/* not a fatal usage error since we want release build to continue */
583604
CLIENT_ASSERT(false,
584605
"client library is incompatible with this version of DR");
@@ -596,8 +617,9 @@ add_client_lib(const char *path, const char *id_str, const char *options)
596617
// to the dll bounds functions. xref i#3387.
597618
client_start = get_dynamorio_dll_start();
598619
client_end = get_dynamorio_dll_end();
599-
ASSERT(client_start <= (app_pc)uses_dr_version &&
600-
(app_pc)uses_dr_version < client_end);
620+
ASSERT(pure_static ||
621+
(client_start <= (app_pc)uses_dr_version &&
622+
(app_pc)uses_dr_version < client_end));
601623
#else
602624
DEBUG_DECLARE(bool ok =)
603625
shared_library_bounds(client_lib, (byte *)uses_dr_version, NULL,
@@ -773,6 +795,15 @@ instrument_init(void)
773795
(*init)(client_libs[i].id, client_libs[i].argc, client_libs[i].argv);
774796
else if (legacy != NULL)
775797
(*legacy)(client_libs[i].id);
798+
#if defined(STATIC_LIBRARY) && !defined(WINDOWS)
799+
else {
800+
// For pure-static apps we support only INSTRUMENT_INIT_NAME.
801+
// There is no WEAK support on Windows so we do not support this there
802+
// (plus pure-static is not really practical either).
803+
extern void dr_client_main(uint id, int argc, const char *argv[]);
804+
dr_client_main(client_libs[i].id, client_libs[i].argc, client_libs[i].argv);
805+
}
806+
#endif
776807
}
777808

778809
/* We now initialize the 1st thread before coming here, so we can

ext/CMakeLists.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# **********************************************************
2-
# Copyright (c) 2010-2022 Google, Inc. All rights reserved.
2+
# Copyright (c) 2010-2025 Google, Inc. All rights reserved.
33
# Copyright (c) 2010 VMware, Inc. All rights reserved.
44
# **********************************************************
55

@@ -61,8 +61,12 @@ add_dr_defines()
6161

6262
# This lets us share common code among all extensions. We use a macro to
6363
# avoid scope issues and avoid having to call configure_DynamoRIO_global().
64-
macro(configure_extension target is_static)
65-
configure_DynamoRIO_client(${target})
64+
macro(configure_extension target is_static static_DR)
65+
if (${static_DR})
66+
configure_DynamoRIO_static_client(${target})
67+
else ()
68+
configure_DynamoRIO_client(${target})
69+
endif ()
6670

6771
# ensure we rebuild if includes change
6872
add_dependencies(${target} api_headers)

ext/drbbdup/CMakeLists.txt

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# **********************************************************
2-
# Copyright (c) 2013-2020 Google, Inc. All rights reserved.
2+
# Copyright (c) 2013-2025 Google, Inc. All rights reserved.
33
# **********************************************************
44

55
# Redistribution and use in source and binary forms, with or without
@@ -47,15 +47,21 @@ set(srcs
4747
set(srcs_static ${srcs})
4848

4949
add_library(drbbdup SHARED ${srcs})
50-
configure_extension(drbbdup OFF)
50+
configure_extension(drbbdup OFF OFF)
5151
use_DynamoRIO_extension(drbbdup drcontainers)
5252
use_DynamoRIO_extension(drbbdup drmgr)
5353
use_DynamoRIO_extension(drbbdup drreg)
5454

5555
add_library(drbbdup_static STATIC ${srcs_static})
56-
configure_extension(drbbdup_static ON)
56+
configure_extension(drbbdup_static ON OFF)
5757
use_DynamoRIO_extension(drbbdup_static drcontainers)
5858
use_DynamoRIO_extension(drbbdup_static drmgr_static)
5959
use_DynamoRIO_extension(drbbdup_static drreg_static)
6060

61+
add_library(drbbdup_drstatic STATIC ${srcs_static})
62+
configure_extension(drbbdup_drstatic ON ON)
63+
use_DynamoRIO_extension(drbbdup_drstatic drcontainers_drstatic)
64+
use_DynamoRIO_extension(drbbdup_drstatic drmgr_drstatic)
65+
use_DynamoRIO_extension(drbbdup_drstatic drreg_drstatic)
66+
6167
install_ext_header(drbbdup.h)

ext/drcallstack/CMakeLists.txt

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# **********************************************************
2-
# Copyright (c) 2021 Google, Inc. All rights reserved.
2+
# Copyright (c) 2021-2025 Google, Inc. All rights reserved.
33
# **********************************************************
44

55
# Redistribution and use in source and binary forms, with or without
@@ -48,11 +48,15 @@ endif ()
4848

4949
add_library(drcallstack SHARED ${srcs})
5050
set(PREFERRED_BASE 0x79800000)
51-
configure_extension(drcallstack OFF)
51+
configure_extension(drcallstack OFF OFF)
5252
target_link_libraries(drcallstack unwind)
5353

5454
add_library(drcallstack_static STATIC ${srcs_static})
55-
configure_extension(drcallstack_static ON)
55+
configure_extension(drcallstack_static ON OFF)
5656
target_link_libraries(drcallstack_static unwind)
5757

58+
add_library(drcallstack_drstatic STATIC ${srcs_static})
59+
configure_extension(drcallstack_drstatic ON ON)
60+
target_link_libraries(drcallstack_drstatic unwind)
61+
5862
install_ext_header(drcallstack.h)

0 commit comments

Comments
 (0)