Illustrate a redirector using the example of round function from math.h.

Setup demonstrated in this patch is only for ELF-ish platforms.

Also note:

1. Use of redirectors is a temporary scheme. They will be removed once
   LLVM-libc has implementations for the redirected functions.
2. Redirectors are optional. One can choose to not include them in the
   LLVM-libc build for their platform.
3. Even with redirectors used, we want to link to the system libc
   dynamically.

Reviewers: dlj, hfinkel, jakehehrlich, phosek, stanshebs, theraven, alexshap

Subscribers: mgorny, libc-commits

Tags: #libc-project

Differential Revision: https://reviews.llvm.org/D69020
This commit is contained in:
Siva Chandra Reddy
2019-10-15 13:25:36 -07:00
parent 9b0dfdf5e1
commit 9364107cf3
11 changed files with 247 additions and 5 deletions

View File

@@ -100,6 +100,7 @@ set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
# Usage:
# add_entrypoint_object(
# <target_name>
# [REDIRECTED] # Specified if the entrypoint is redirected.
# SRCS <list of .cpp files>
# HDRS <list of .h files>
# DEPENDS <list of dependencies>
@@ -107,7 +108,7 @@ set(ENTRYPOINT_OBJ_TARGET_TYPE "ENTRYPOINT_OBJ")
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 @@ function(add_entrypoint_object target_name)
${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 @@ function(add_entrypoint_object target_name)
COMMAND ${CMAKE_LINKER} -r $<TARGET_OBJECTS:${target_name}_objects> -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 $<TARGET_FILE:llvm-objcopy> --add-symbol "${target_name}=.llvm.libc.entrypoint.${target_name}:${alias_attributes}" ${object_file_raw} ${object_file}
)
add_custom_target(
@@ -219,6 +226,67 @@ function(add_entrypoint_library target_name)
)
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 $<TARGET_OBJECTS:${dep}>)
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()

View File

@@ -13,6 +13,10 @@ Every entrypoint in LLVM-libc has its own build target. This target is listed
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 @@ the ``lib`` directory as ``add_entrypoint_library`` targets. An
``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.

69
libc/docs/redirectors.rst Normal file
View File

@@ -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:
<img src="./redirectors_schematic.svg">
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 <math.h> // 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

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -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
)

View File

@@ -1,3 +1,4 @@
add_subdirectory(string)
add_subdirectory(math)
add_subdirectory(__support)

View File

@@ -0,0 +1 @@
add_subdirectory(round)

View File

@@ -0,0 +1,14 @@
add_entrypoint_object(
round
REDIRECTED
SRCS
round.cpp
HDRS
round.h
)
add_redirector_object(
round_redirector
SRC
round_redirector.cpp
)

View File

@@ -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

View File

@@ -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

View File

@@ -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 <math.h>
namespace llvm_libc {
double __round_redirector(double x) {
return ::round(x);
}
} // namespace llvm_libc