diff --git a/libc/cmake/modules/LLVMLibCRules.cmake b/libc/cmake/modules/LLVMLibCRules.cmake --- a/libc/cmake/modules/LLVMLibCRules.cmake +++ b/libc/cmake/modules/LLVMLibCRules.cmake @@ -100,6 +100,7 @@ # Usage: # add_entrypoint_object( # +# [REDIRECTED] # Specified if the entrypoint is redirected. # SRCS # HDRS # DEPENDS @@ -107,7 +108,7 @@ function(add_entrypoint_object target_name) cmake_parse_arguments( "ADD_ENTRYPOINT_OBJ" - "" # No optional arguments + "REDIRECTED" # Optional argument "" # No single value arguments "SRCS;HDRS;DEPENDS" # Multi value arguments ${ARGN} @@ -131,7 +132,7 @@ ${target_name}_objects BEFORE PRIVATE - -fpie -std=${LLVM_CXX_STD_default} + -fpie ${LLVM_CXX_STD_default} ) target_include_directories( ${target_name}_objects @@ -158,10 +159,16 @@ COMMAND ${CMAKE_LINKER} -r $ -o ${object_file_raw} ) + set(alias_attributes "0,function,global") + if(ADD_ENTRYPOINT_OBJ_REDIRECTED) + set(alias_attributes "${alias_attributes},hidden") + endif() + add_custom_command( OUTPUT ${object_file} - DEPENDS ${object_file_raw} - COMMAND ${CMAKE_OBJCOPY} --add-symbol "${target_name}=.llvm.libc.entrypoint.${target_name}:0,function,weak,global" ${object_file_raw} ${object_file} + # We llvm-objcopy here as GNU-binutils objcopy does not support the 'hidden' flag. + DEPENDS ${object_file_raw} ${llvm-objcopy} + COMMAND $ --add-symbol "${target_name}=.llvm.libc.entrypoint.${target_name}:${alias_attributes}" ${object_file_raw} ${object_file} ) add_custom_target( @@ -219,6 +226,67 @@ ) endfunction(add_entrypoint_library) +# Rule build a redirector object file. +function(add_redirector_object target_name) + cmake_parse_arguments( + "REDIRECTOR_OBJECT" + "" # No optional arguments + "SRC" # The cpp file in which the redirector is defined. + "" # No multivalue arguments + ${ARGN} + ) + if(NOT REDIRECTOR_OBJECT_SRC) + message(FATAL_ERROR "'add_redirector_object' rule requires SRC option listing one source file.") + endif() + + add_library( + ${target_name} + OBJECT + ${REDIRECTOR_OBJECT_SRC} + ) + target_compile_options( + ${target_name} + BEFORE PRIVATE -fPIC + ) +endfunction(add_redirector_object) + +# Rule to build a shared library of redirector objects +function(add_redirector_library target_name) + cmake_parse_arguments( + "REDIRECTOR_LIBRARY" + "" + "" + "DEPENDS" + ${ARGN} + ) + + set(obj_files "") + foreach(dep IN LISTS REDIRECTOR_LIBRARY_DEPENDS) + # TODO: Ensure that each dep is actually a add_redirector_object target. + list(APPEND obj_files $) + endforeach(dep) + + # TODO: Call the linker explicitly instead of calling the compiler driver to + # prevent DT_NEEDED on C++ runtime. + add_library( + ${target_name} + SHARED + ${obj_files} + ) + set_target_properties(${target_name} PROPERTIES LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}) + + target_link_libraries( + ${target_name} + -nostdlib -lc -lm + ) + + set_target_properties( + ${target_name} + PROPERTIES + LINKER_LANGUAGE "C" + ) +endfunction(add_redirector_library) + function(add_libc_unittest target_name) if(NOT LLVM_INCLUDE_TESTS) return() diff --git a/libc/docs/build_system.rst b/libc/docs/build_system.rst --- a/libc/docs/build_system.rst +++ b/libc/docs/build_system.rst @@ -13,6 +13,10 @@ using the ``add_entrypoint_object`` rule. This rule generates a single object file containing the implementation of the entrypoint. +Targets for redirecting entrypoints are also listed using the +``add_entrypoint_object`` rule. However, one will have to additionally specify +the ``REDIRECTED`` option with the rule. + Targets for entrypoint libraries -------------------------------- @@ -22,3 +26,18 @@ ``add_entrypoint_library`` target takes a list of ``add_entrypoint_object`` targets and produces a static library containing the object files corresponding to the ``add_entrypoint_targets``. + +Targets for redirectors +----------------------- + +Similar to how every entrypoint in LLVM-libc has its own build target, every +redirector function also has its own build target. This target is listed using +the ``add_redirector_object`` rule. This rule generates a single object file +which can be packaged along with other redirector objects into shared library +of redirectors (see below). + +Targets for library of redirectors +---------------------------------- + +Targets for shared libraries of redirectors are listed using the +``add_redirector_library`` rule. diff --git a/libc/docs/redirectors.rst b/libc/docs/redirectors.rst new file mode 100644 --- /dev/null +++ b/libc/docs/redirectors.rst @@ -0,0 +1,69 @@ +Redirectors +=========== + +When implementing a new C standard library (referred to as *libc* henceforth in +this document) starting from scratch, it is unrealistic to expect that we will +have the entire library available from day one. In such a scenario, a practical +approach is to redirect calls to the unimplemented functions to the same +functions from another fully functional libc implementation. Such a scheme can +also serve users who would like to mix and match implementations from LLVM libc +and another libc implementation. On most platforms, this other libc can be the +system libc itself. In this document, we present a strategy one can employ to +build redirectors to redirect from LLVM libc to the system libc. For now, the +scheme presented is limited to ELF platforms. + +Highlevel Mechanism +------------------- + +The highlevel scheme is as below: + + + +As shown in the diagram, the mechanism involves a redirector dynamic library +which goes in between the llvm-libc static library and the system libc dynamic +library. Essentially, LLVM libc provides implementations for all public +functions. However, some of the implementations do not actually implement the +expected functionality. Instead, they just call the corresponding function in +the redirector library, which in turn calls the same function from the system +libc. + +Implementation of redirecting entrypoints +----------------------------------------- + +Let us take the ``round`` function from ``math.h`` as an example to see what +it's implementation looks like when it just redirects to the ``round`` function +from the system libc. + +:: + namespace llvm_libc { + + double __redirected_round(double); + + double LLVM_LIBC_ENTRYPOINT(round)(double x) { + return __redirected_round(x); + } + + } // namespace llvm_libc + +As can be seen, the ``round`` function from LLVM libc does not call the +``round`` function from the system libc directly. It calls a function +``__redirected_round`` from the redirector library. The rest of the +code follows the conventions described in the *implementation standard* +document. + +Implementation of the redirector function +----------------------------------------- + +The function ``__redirected_round`` calls the ``round`` function from the system +libc. Its implementation is as follows:: + + #include // Header file from the system libc + + namespace llvm_libc { + + double __redirected_round(double x) { + return ::round(x); // Call to round from the system libc + } + + } // namespace llvm_libc + diff --git a/libc/docs/redirectors_schematic.svg b/libc/docs/redirectors_schematic.svg new file mode 100644 --- /dev/null +++ b/libc/docs/redirectors_schematic.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/libc/lib/CMakeLists.txt b/libc/lib/CMakeLists.txt --- a/libc/lib/CMakeLists.txt +++ b/libc/lib/CMakeLists.txt @@ -2,8 +2,21 @@ add_entrypoint_library( llvmlibc DEPENDS - ### C standard library entrypoints # string.h entrypoints + ## C standard library entrypoints strcpy strcat ) + +add_entrypoint_library( + llvmlibm + DEPENDS + # math.h entrypoints + round +) + +add_redirector_library( + llvmlibc_redirectors + DEPENDS + round_redirector +) diff --git a/libc/src/CMakeLists.txt b/libc/src/CMakeLists.txt --- a/libc/src/CMakeLists.txt +++ b/libc/src/CMakeLists.txt @@ -1,3 +1,4 @@ add_subdirectory(string) +add_subdirectory(math) add_subdirectory(__support) diff --git a/libc/src/math/CMakeLists.txt b/libc/src/math/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/math/CMakeLists.txt @@ -0,0 +1 @@ +add_subdirectory(round) diff --git a/libc/src/math/round/CMakeLists.txt b/libc/src/math/round/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/libc/src/math/round/CMakeLists.txt @@ -0,0 +1,14 @@ +add_entrypoint_object( + round + REDIRECTED + SRCS + round.cpp + HDRS + round.h +) + +add_redirector_object( + round_redirector + SRC + round_redirector.cpp +) diff --git a/libc/src/math/round/round.h b/libc/src/math/round/round.h new file mode 100644 --- /dev/null +++ b/libc/src/math/round/round.h @@ -0,0 +1,18 @@ +//===------------------ Implementation header for round -------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIBC_SRC_MATH_ROUND_H +#define LLVM_LIBC_SRC_MATH_ROUND_H + +namespace llvm_libc { + +double round(double x); + +} // namespace llvm_libc + +#endif // LLVM_LIBC_SRC_MATH_ROUND_H diff --git a/libc/src/math/round/round.cpp b/libc/src/math/round/round.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/round/round.cpp @@ -0,0 +1,21 @@ +//===---------------------- Implementation of round -----------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "src/math/round/round.h" + +#include "src/__support/common.h" + +namespace llvm_libc { + +double __round_redirector(double x); + +double LLVM_LIBC_ENTRYPOINT(round)(double x) { + return __round_redirector(x); +} + +} // namespace llvm_libc diff --git a/libc/src/math/round/round_redirector.cpp b/libc/src/math/round/round_redirector.cpp new file mode 100644 --- /dev/null +++ b/libc/src/math/round/round_redirector.cpp @@ -0,0 +1,17 @@ +//===---------------- Implementation of round redirector -----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include + +namespace llvm_libc { + +double __round_redirector(double x) { + return ::round(x); +} + +} // namespace llvm_libc