How to Build a Tool

To use the DynamoRIO API, a tool, or "client" of DynamoRIO, should include the main DynamoRIO header file:

#include "dr_api.h"

The client's target operating system and architecture must be specified by setting pre-processor defines before including the DynamoRIO header files. The appropriate library must then be linked with. The define choices are:

  1. WINDOWS, LINUX, or (coming soon) MACOS
  2. X86_32, X86_64, ARM_32, or ARM_64

Currently we provide a private loader for both Windows and Linux. With private loading, clients use a separate copy of each library from any copy used by the application.

If the private loader is deliberately disabled, for transparency reasons (see Client Transparency), clients should be self-contained and should not share libraries with the application. Without the private loader, 64-bit clients must take care to try and load themselves within reachable range of DynamoRIO's code caches by setting a preferred base address, although this may not always be honored by the system loader.

The DynamoRIO release supplies CMake configuration files to facilitate building clients with the proper compiler and linker flags. CMake is a cross-platform build system that generates Makefiles or other development system project files. A DynamoRIOConfig.cmake configuration file, along with supporting files, is distributed in the cmake/ directory.

In its CMakeLists.txt file, a client should first invoke a find_package(DynamoRIO) command. This can optionally take a version parameter. This adds DynamoRIO as an imported target. If found, the client should then invoke the configure_DynamoRIO_client() function in order to configure build settings. Here is an example:

add_library(myclient SHARED myclient.c)
if (NOT DynamoRIO_FOUND)
message(FATAL_ERROR "DynamoRIO package required to build")
endif(NOT DynamoRIO_FOUND)

The samples/CMakeLists.txt file in the release package serves as another example. The top of DynamoRIOConfig.cmake contains detailed instructions as well.

When configuring, the DynamoRIO_DIR CMake variable can be passed in to identify the directory that contains the DynamoRIOConfig.cmake file. For example:

mkdir ../build
cd ../build
cmake -DDynamoRIO_DIR=$DYNAMORIO_HOME/cmake ../myclient

The compiler needs to be configured prior to invoking cmake. If using gcc with a non-default target platform, the CFLAGS and CXXFLAGS environment variables should be set prior to invoking cmake. For example, to configure a 32-bit client when gcc's default is 64-bit:

mkdir ../build
cd ../build
CFLAGS=-m32 cmake -DDynamoRIO_DIR=$DYNAMORIO_HOME/cmake ../myclient

Note that CXXFLAGS should be set instead for a C++ client, and both should be set when building both types of clients from the same configuration (e.g., samples/CMakeLists.txt).

To improve clean call performance (see Clean Calls and -opt_cleancall), we recommend high levels of optimization when building a client.

If a client is not using CMake, the appropriate compiler and linker flags can be gleaned from DynamoRIOConfig.cmake. One method is to invoke CMake to generate a Makefile and then build with VERBOSE=1. We also summarize here the key flags required for 32-bit clients for gcc:

gcc -fPIC -shared -lgcc -DLINUX -DX86_32 -I$DYNAMORIO_HOME/include my-client.c

And for cl:

cl my-client.c /I$DYNAMORIO_HOME/include /GS- /DWINDOWS /DX86_32
/link /libpath:$DYNAMORIO_HOME/bin dynamorio.lib /dll /out:my-client.dll

For a 64-bit client with cl:

cl my-client.c /I$DYNAMORIO_HOME/include /GS- /DWINDOWS /DX86_64
/link /libpath:$DYNAMORIO_HOME/bin dynamorio.lib /dll /out:my-client.dll
/base:0x72000000 /fixed

For 64-bit Linux clients, setting the preferred base takes several steps. Refer to DynamoRIOConfig.cmake for details.

To make clean call sequences more likely to be optimized, it is recommended to compile the client with optimizations, -O2 for gcc or /O2 for cl.

Top-level include file for DynamoRIO API.