diff --git a/cmake/HPX_GeneratePackage.cmake b/cmake/HPX_GeneratePackage.cmake index a3d4cb97315e..3ef905f4b7a6 100644 --- a/cmake/HPX_GeneratePackage.cmake +++ b/cmake/HPX_GeneratePackage.cmake @@ -74,6 +74,11 @@ else() endif() endif() +set(HPX_LINKER_FLAGS "") +if(CMAKE_SYSTEM_NAME STREQUAL Linux) + set(HPX_LINKER_FLAGS "-Wl,-wrap=__libc_start_main") +endif() + # Get the include directories we need ... get_directory_property(_INCLUDE_DIRS INCLUDE_DIRECTORIES) @@ -230,4 +235,3 @@ install( DESTINATION ${LIB}/bazel COMPONENT bazel ) - diff --git a/cmake/HPX_SetupTarget.cmake b/cmake/HPX_SetupTarget.cmake index ae4b3b41ee7b..7d36ef38eec1 100644 --- a/cmake/HPX_SetupTarget.cmake +++ b/cmake/HPX_SetupTarget.cmake @@ -187,7 +187,6 @@ function(hpx_setup_target target) set(_USE_CONFIG 0) endif() - # linker instructions if(NOT target_NOLIBS) set(hpx_libs hpx) if(NOT target_STATIC_LINKING) @@ -204,6 +203,10 @@ function(hpx_setup_target target) if(DEFINED HPX_LIBRARIES) set(hpx_libs ${hpx_libs} ${HPX_LIBRARIES}) endif() + get_target_property(target_type ${target} TYPE) + if(CMAKE_SYSTEM_NAME STREQUAL Linux AND target_type STREQUAL EXECUTABLE) + set_target_properties(${target} PROPERTIES LINK_FLAGS "-Wl,-wrap=__libc_start_main") + endif() else() target_compile_options(${target} PUBLIC ${CXX_FLAG}) endif() diff --git a/cmake/templates/hpx_application.pc.in b/cmake/templates/hpx_application.pc.in index 23a1c4f641a0..f943a62f6ec9 100644 --- a/cmake/templates/hpx_application.pc.in +++ b/cmake/templates/hpx_application.pc.in @@ -12,6 +12,5 @@ includedir=${exec_prefix}/include Name: hpx_application Description: High Performance ParalleX (application configuration) Version: @HPX_VERSION@ -Libs: @CXX_FLAG@ -L${libdir} @HPX_PKG_LIBRARY_DIR@ @HPX_PKG_LIBRARIES@ +Libs: @CXX_FLAG@ -L${libdir} @HPX_PKG_LIBRARY_DIR@ @HPX_PKG_LIBRARIES@ @HPX_LINKER_FLAGS@ Cflags: @CXX_FLAG@ @HPX_CONF_INCLUDE_DIRS@ -DHPX_APPLICATION_EXPORTS -DHPX_ENABLE_ASSERT_HANDLER - diff --git a/cmake/templates/hpx_application_debug.pc.in b/cmake/templates/hpx_application_debug.pc.in index 4dcfaabc2497..c4e015e01ec0 100644 --- a/cmake/templates/hpx_application_debug.pc.in +++ b/cmake/templates/hpx_application_debug.pc.in @@ -12,6 +12,5 @@ includedir=${exec_prefix}/include Name: hpx_application Description: High Performance ParalleX (application configuration) - debug build Version: @HPX_VERSION@ -Libs: @CXX_FLAG@ -L${libdir} @HPX_PKG_LIBRARY_DIR@ @HPX_PKG_DEBUG_LIBRARIES@ +Libs: @CXX_FLAG@ -L${libdir} @HPX_PKG_LIBRARY_DIR@ @HPX_PKG_DEBUG_LIBRARIES@ @HPX_LINKER_FLAGS@ Cflags: @CXX_FLAG@ -DHPX_DEBUG @HPX_CONF_INCLUDE_DIRS@ -DHPX_APPLICATION_EXPORTS -DHPX_ENABLE_ASSERT_HANDLER - diff --git a/hpx/hpx_main.hpp b/hpx/hpx_main.hpp index 3ba45b524928..28132fba2436 100644 --- a/hpx/hpx_main.hpp +++ b/hpx/hpx_main.hpp @@ -1,4 +1,5 @@ // Copyright (c) 2007-2014 Hartmut Kaiser +// Copyright (c) 2018 Nikunj Gupta // // Distributed under the Boost Software License, Version 1.0. (See accompanying // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -9,6 +10,20 @@ #include #include +// We support different implementation depending upon the Operating +// System in use. +#if defined(__linux) || defined(__linux__) || defined(linux) + +namespace hpx_start { + // include_libhpx_wrap here is an override for the one present in + // src/hpx_wrap.cpp. The value of this variable defines if we need + // to change the program's entry point or not. + extern bool include_libhpx_wrap; + bool include_libhpx_wrap = true; +} + +#else + #if defined(HPX_HAVE_STATIC_LINKING) #include #endif @@ -17,5 +32,6 @@ // as the first HPX-thread (equivalent to hpx_main()). This is implemented by // a macro redefining main, so we disable it by default. #define main hpx_startup::user_main +#endif #endif /*HPX_HPX_MAIN_HPP*/ diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e27c5d2c0bf2..b14ad6f489d9 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,5 +1,6 @@ # Copyright (c) 2007-2017 Hartmut Kaiser # Copyright (c) 2011 Bryce Lelbach +# Copyright (c) 2018 Nikunj Gupta # # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) @@ -20,7 +21,7 @@ endforeach() # libhpx sources add_hpx_library_sources(hpx GLOB GLOBS "${PROJECT_SOURCE_DIR}/src/*.cpp" - EXCLUDE "(.*(hpx_main|hpx_user).*[.]cpp)|main.cpp") + EXCLUDE "(.*(hpx_main|hpx_user).*[.]cpp)|main.cpp|hpx_wrap.cpp") add_hpx_library_sources(hpx GLOB GLOBS "${PROJECT_SOURCE_DIR}/src/pre_main.cpp" APPEND) @@ -44,7 +45,6 @@ add_hpx_library_sources(hpx GLOB_RECURSE GLOBS "${PROJECT_SOURCE_DIR}/src/compat/*.cpp" APPEND) - # libhpx_init sources add_hpx_library_sources(hpx_init GLOB GLOBS "${PROJECT_SOURCE_DIR}/src/hpx_*.cpp" diff --git a/src/hpx_wrap.cpp b/src/hpx_wrap.cpp new file mode 100644 index 000000000000..7107914f0724 --- /dev/null +++ b/src/hpx_wrap.cpp @@ -0,0 +1,131 @@ +// Copyright (c) 20018 Nikunj Gupta +// +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +// The following implementation is only possible for Linux systems. +#if defined(__linux) || defined(__linux__) || defined(linux) + +namespace hpx_start { + // include_libhpx_wrap is a weak symbol which helps to determine the course + // of function calls at runtime. It has a deafult value of `false` which + // corresponds to the program's entry point being main(). + // It is overriden in hpx/hpx_main.hpp. Thus, inclusion of the header file + // will change the program's entry point to HPX's own custom entry point + // initialize_main. Subsequent calls before entering main() are handled + // by this code. + extern bool include_libhpx_wrap; + bool include_libhpx_wrap __attribute__((weak)) = false; +} + +#include +#include + +#include +#include + +//////////////////////////////////////////////////////////////////////////////// +// Function declarations +// + +namespace hpx_start{ + // Main entry point of HPX runtime system + extern int hpx_entry(int argc, char* argv[]); +} + +// HPX's implented program's entry point +extern int initialize_main(int argc, char** argv, char** envp); + +// Real libc function __libc_start_main. Function definition can be +// found in the glibc source in `glibc/csu/libc-start.c` +extern "C" int __real___libc_start_main ( + int (*main)(int, char**, char**), int argc, char * * ubp_av, + void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void (* stack_end)); + +// Wrapper function for __libc_start_main +extern "C" int __wrap___libc_start_main ( + int (*main)(int, char**, char**), int argc, char * * ubp_av, + void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void (* stack_end)); + + +//////////////////////////////////////////////////////////////////////////////// +// Global pointers + +namespace hpx_start { + // actual_main is responsible to store the pointer to the main() + // function. POSIX implementation of main requires pointer to envp + // so it is stored as well. + int (*actual_main)(int, char**, char**) = nullptr; + char** __envp = nullptr; + + + // main entry point of the HPX runtime system + int hpx_entry(int argc, char* argv[]) + { + // Call to the main() function + int return_value = hpx_start::actual_main(argc, argv, __envp); + + //Finalizing the HPX runtime + return hpx::finalize(return_value); + } +} + +// This is the main entry point of C runtime system. +// The HPX runtime system is initialized here, which +// is similar to initializing HPX from main() and utilising +// the hpx_main() as the entry point. +int initialize_main(int argc, char** argv, char** envp) +{ + // initializing envp pointer to utilize when + // calling the actual main. + hpx_start::__envp = envp; + + // Configuring HPX system before runtime + std::vector const cfg = { + "hpx.commandline.allow_unknown!=1", + "hpx.commandline.aliasing=0", + }; + + using hpx::util::placeholders::_1; + using hpx::util::placeholders::_2; + hpx::util::function_nonser start_function = + hpx::util::bind(&hpx_start::hpx_entry, _1, _2); + + // Initialize the HPX runtime system + return hpx::init(start_function, argc, argv, + cfg, hpx::runtime_mode_console); +} + + +//////////////////////////////////////////////////////////////////////////////// +// Wrapper for the libc function __libc_start_main +// + +// We are hooking into __libc_start_main to change the entry +// point of the C runtime system to our custom implemented +// function initialize_main +extern "C" int __wrap___libc_start_main ( + int (*main)(int, char**, char**), int argc, char * * ubp_av, + void (*init) (void), void (*fini) (void), + void (*rtld_fini) (void), void (* stack_end)) +{ + + // We determine the function call stack at runtime from the + // value of include_libhpx_wrap. + if(hpx_start::include_libhpx_wrap) { + // Assigning pointer to C main to actual_main + hpx_start::actual_main = main; + + // Calling original __libc_start_main with our custom entry point. + return __real___libc_start_main(&initialize_main, argc, ubp_av, init, + fini, rtld_fini, stack_end); + } + return __real___libc_start_main(main, argc, ubp_av, init, + fini, rtld_fini, stack_end); + +} +//////////////////////////////////////////////////////////////////////////////// + +#endif