forked from OSchip/llvm-project
Add implementations of POSIX mmap and munmap functions.
Summary: A set of of linux x86_64 internal syscall helpers have also been added. This change does not try to be perfect with respect to OS and machine abstractions. A TODO note has been added at places where such abstractions would help and make the arrangement scalable and cleaner. Addressing the TODOs and building such abstractions is not in the scope of this change. It is hoped that follow up changes cleaning up the problem areas and addressing the TODOs will better illustrate the need for the changes. This change also does not try to imitate mmap and munmap implementations of other libcs. The idea here is to put in the bare minimum required to obtain a working mmap and munmap, and then add the rest of the functionality on an as needed basis. Reviewers: abrachet, phosek, stanshebs, theraven Subscribers: mgorny, MaskRay, jfb, libc-commits Tags: #libc-project Differential Revision: https://reviews.llvm.org/D71634
This commit is contained in:
parent
187f66bcac
commit
e5a743c4f6
|
@ -19,7 +19,8 @@ set(LIBC_TARGET_MACHINE ${CMAKE_SYSTEM_PROCESSOR})
|
|||
include(CMakeParseArguments)
|
||||
include(LLVMLibCRules)
|
||||
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(src)
|
||||
add_subdirectory(config)
|
||||
add_subdirectory(include)
|
||||
add_subdirectory(lib)
|
||||
add_subdirectory(utils)
|
||||
|
|
|
@ -250,7 +250,7 @@ function(add_redirector_object target_name)
|
|||
)
|
||||
endfunction(add_redirector_object)
|
||||
|
||||
# Rule to build a shared library of redirector objects
|
||||
# Rule to build a shared library of redirector objects.
|
||||
function(add_redirector_library target_name)
|
||||
cmake_parse_arguments(
|
||||
"REDIRECTOR_LIBRARY"
|
||||
|
@ -287,6 +287,15 @@ function(add_redirector_library target_name)
|
|||
)
|
||||
endfunction(add_redirector_library)
|
||||
|
||||
# Rule to add a gtest unittest.
|
||||
# Usage
|
||||
# add_libc_unittest(
|
||||
# <target name>
|
||||
# SUITE <name of the suite this test belongs to>
|
||||
# SRCS <list of .cpp files for the test>
|
||||
# HDRS <list of .h files for the test>
|
||||
# DEPENDS <list of dependencies>
|
||||
# )
|
||||
function(add_libc_unittest target_name)
|
||||
if(NOT LLVM_INCLUDE_TESTS)
|
||||
return()
|
||||
|
@ -306,15 +315,19 @@ function(add_libc_unittest target_name)
|
|||
message(FATAL_ERROR "'add_libc_unittest' target requires a DEPENDS list of 'add_entrypoint_object' targets.")
|
||||
endif()
|
||||
|
||||
set(entrypoint_objects "")
|
||||
set(library_deps "")
|
||||
foreach(dep IN LISTS LIBC_UNITTEST_DEPENDS)
|
||||
get_target_property(dep_type ${dep} "TARGET_TYPE")
|
||||
string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
|
||||
if(NOT dep_is_entrypoint)
|
||||
message(FATAL_ERROR "Dependency '${dep}' of 'add_entrypoint_unittest' is not an 'add_entrypoint_object' target.")
|
||||
if (dep_type)
|
||||
string(COMPARE EQUAL ${dep_type} ${ENTRYPOINT_OBJ_TARGET_TYPE} dep_is_entrypoint)
|
||||
if(dep_is_entrypoint)
|
||||
get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
|
||||
list(APPEND library_deps ${obj_file})
|
||||
continue()
|
||||
endif()
|
||||
endif()
|
||||
get_target_property(obj_file ${dep} "OBJECT_FILE_RAW")
|
||||
list(APPEND entrypoint_objects "${obj_file}")
|
||||
# TODO: Check if the dep is a normal CMake library target. If yes, then add it
|
||||
# to the list of library_deps.
|
||||
endforeach(dep)
|
||||
|
||||
add_executable(
|
||||
|
@ -329,8 +342,13 @@ function(add_libc_unittest target_name)
|
|||
${LLVM_MAIN_SRC_DIR}/utils/unittest/googletest/include
|
||||
${LLVM_MAIN_SRC_DIR}/utils/unittest/googlemock/include
|
||||
${LIBC_SOURCE_DIR}
|
||||
${LIBC_BUILD_DIR}
|
||||
)
|
||||
target_link_libraries(${target_name} PRIVATE ${entrypoint_objects} gtest_main gtest)
|
||||
|
||||
if(library_deps)
|
||||
target_link_libraries(${target_name} PRIVATE ${library_deps})
|
||||
endif()
|
||||
|
||||
set_target_properties(${target_name} PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_dependencies(
|
||||
|
@ -338,6 +356,9 @@ function(add_libc_unittest target_name)
|
|||
${LIBC_UNITTEST_DEPENDS}
|
||||
gtest
|
||||
)
|
||||
|
||||
target_link_libraries(${target_name} PRIVATE gtest_main gtest)
|
||||
|
||||
add_custom_command(
|
||||
TARGET ${target_name}
|
||||
POST_BUILD
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(linux)
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(x86_64)
|
|
@ -4,18 +4,6 @@ include "spec/linux.td"
|
|||
include "spec/posix.td"
|
||||
include "spec/stdc.td"
|
||||
|
||||
def FloatT : TypeDecl<"float_t"> {
|
||||
let Decl = [{
|
||||
#if __FLT_EVAL_METHOD__ == 1
|
||||
typedef float float_t
|
||||
#elif __FLT_EVAL_METHOD__ == 2
|
||||
...
|
||||
#else
|
||||
...
|
||||
#endif
|
||||
}]; // This is only an example and not exactly how it will appear
|
||||
}
|
||||
|
||||
def SizeT : TypeDecl<"size_t"> {
|
||||
let Decl = [{
|
||||
#define __need_size_t
|
||||
|
@ -23,6 +11,13 @@ def SizeT : TypeDecl<"size_t"> {
|
|||
}];
|
||||
}
|
||||
|
||||
def OffT : TypeDecl<"off_t"> {
|
||||
let Decl = [{
|
||||
#define __need_off_t
|
||||
#include <__posix-types.h>
|
||||
}];
|
||||
}
|
||||
|
||||
def NullMacro : MacroDef<"NULL"> {
|
||||
let Defn = [{
|
||||
#define __need_NULL
|
||||
|
@ -42,10 +37,6 @@ def MathAPI : PublicAPI<"math.h"> {
|
|||
"acos",
|
||||
"acosl",
|
||||
];
|
||||
|
||||
let TypeDeclarations = [
|
||||
FloatT,
|
||||
];
|
||||
}
|
||||
|
||||
def StringAPI : PublicAPI<"string.h"> {
|
||||
|
@ -111,3 +102,34 @@ def ErrnoAPI : PublicAPI<"errno.h"> {
|
|||
MacroDefineIfNot<"EHWPOISON", "133">,
|
||||
];
|
||||
}
|
||||
|
||||
def SysMManAPI : PublicAPI<"sys/mman.h"> {
|
||||
let Macros = [
|
||||
SimpleMacroDef<"PROT_NONE", "0">,
|
||||
SimpleMacroDef<"PROT_READ", "1">,
|
||||
SimpleMacroDef<"PROT_WRITE", "2">,
|
||||
SimpleMacroDef<"PROT_EXEC", "4">,
|
||||
|
||||
SimpleMacroDef<"MAP_FIXED", "1">,
|
||||
SimpleMacroDef<"MAP_PRIVATE", "2">,
|
||||
SimpleMacroDef<"MAP_SHARED", "4">,
|
||||
|
||||
SimpleMacroDef<"MAP_FAILED", "((void*)-1)">,
|
||||
|
||||
// TODO: The value of 0x20 is good for x86_64, but has to be extended
|
||||
// in some manner to accommodate other machine architectures.
|
||||
SimpleMacroDef<"MAP_ANONYMOUS", "0x20">
|
||||
|
||||
// TODO: Add other MAP_* macros used by Linux.
|
||||
];
|
||||
|
||||
let TypeDeclarations = [
|
||||
SizeT,
|
||||
OffT,
|
||||
];
|
||||
|
||||
let Functions = [
|
||||
"mmap",
|
||||
"munmap",
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//===---- Definition of LLVM_LIBC_ENTRYPOINT macro for ELF paltforms ----*-===//
|
||||
//===----- Definition of platform specific macros for ELF paltforms -------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
|
@ -11,3 +11,9 @@
|
|||
#define ENTRYPOINT_SECTION_ATTRIBUTE(name) \
|
||||
__attribute__((section(".llvm.libc.entrypoint."#name)))
|
||||
#define LLVM_LIBC_ENTRYPOINT(name) ENTRYPOINT_SECTION_ATTRIBUTE(name) name
|
||||
|
||||
// TODO: Get rid of the PAGE_SIZE macro. It is present only as an interim
|
||||
// measure until we can move the implementations of mmap and munmap to under
|
||||
// the config/linux directory. After that, the implementations can use
|
||||
// EXEC_PAGESIZE until page size can be read from the aux vector.
|
||||
#define PAGE_SIZE 4096
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,10 @@
|
|||
add_custom_target(libc_linux_x86_64_unittests)
|
||||
|
||||
add_libc_unittest(
|
||||
libc_linux_x86_64_syscall_unittest
|
||||
SUITE libc_linux_x86_64_unittests
|
||||
SRCS syscall_test.cpp
|
||||
DEPENDS
|
||||
syscall_impl_h
|
||||
support_common_h
|
||||
)
|
|
@ -0,0 +1,93 @@
|
|||
//===------------ inline implementation of x86_64 syscalls --------------*-===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
%%begin()
|
||||
|
||||
#include "src/__support/common.h"
|
||||
|
||||
#define SYSCALL_CLOBBER_LIST "rcx", "r11", "memory"
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
inline long syscall(long __number) {
|
||||
long retcode;
|
||||
LIBC_INLINE_ASM("syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
inline long syscall(long __number, long __arg1) {
|
||||
long retcode;
|
||||
LIBC_INLINE_ASM("syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number), "D"(__arg1) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
inline long syscall(long __number, long __arg1, long __arg2) {
|
||||
long retcode;
|
||||
LIBC_INLINE_ASM("syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number), "D"(__arg1), "S"(__arg2) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
inline long syscall(long __number, long __arg1, long __arg2, long __arg3) {
|
||||
long retcode;
|
||||
LIBC_INLINE_ASM("syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number), "D"(__arg1), "S"(__arg2), "d"(__arg3) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
inline long syscall(
|
||||
long __number, long __arg1, long __arg2, long __arg3, long __arg4) {
|
||||
long retcode;
|
||||
register long r10 __asm__("r10") = __arg4;
|
||||
LIBC_INLINE_ASM("syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number), "D"(__arg1), "S"(__arg2), "d"(__arg3), "r"(r10) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
inline long syscall(long __number, long __arg1, long __arg2, long __arg3,
|
||||
long __arg4, long __arg5) {
|
||||
long retcode;
|
||||
register long r10 __asm__("r10") = __arg4;
|
||||
register long r8 __asm__("r8") = __arg5;
|
||||
LIBC_INLINE_ASM(
|
||||
"syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number), "D"(__arg1), "S"(__arg2), "d"(__arg3), "r"(r10), "r"(r8) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
inline long syscall(long __number, long __arg1, long __arg2, long __arg3,
|
||||
long __arg4, long __arg5, long __arg6) {
|
||||
long retcode;
|
||||
register long r10 __asm__("r10") = __arg4;
|
||||
register long r8 __asm__("r8") = __arg5;
|
||||
register long r9 __asm__("r9") = __arg6;
|
||||
LIBC_INLINE_ASM(
|
||||
"syscall" :
|
||||
"=a"(retcode) :
|
||||
"a"(__number), "D"(__arg1), "S"(__arg2), "d"(__arg3), "r"(r10), "r"(r8), "r"(r9) :
|
||||
SYSCALL_CLOBBER_LIST);
|
||||
return retcode;
|
||||
}
|
||||
|
||||
#undef SYSCALL_CLOBBER_LIST
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,40 @@
|
|||
//===------------------ Unittests for x86_64 syscalls ---------------------===//
|
||||
//
|
||||
// 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/unistd/syscall.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include <functional>
|
||||
|
||||
TEST(X86_64_SyscallTest, APITest) {
|
||||
// We only do a signature test here. Actual functionality tests are
|
||||
// done by the unit tests of the syscall wrappers like mmap.
|
||||
|
||||
std::function<long(long)> f([](long n) { return __llvm_libc::syscall(n); });
|
||||
std::function<long(long, long)> f1(
|
||||
[](long n, long a1) { return __llvm_libc::syscall(n, a1); });
|
||||
std::function<long(long, long, long)> f2(
|
||||
[](long n, long a1, long a2) { return __llvm_libc::syscall(n, a1, a2); });
|
||||
std::function<long(long, long, long, long)> f3(
|
||||
[](long n, long a1, long a2, long a3) {
|
||||
return __llvm_libc::syscall(n, a1, a2, a3);
|
||||
});
|
||||
std::function<long(long, long, long, long, long)> f4(
|
||||
[](long n, long a1, long a2, long a3, long a4) {
|
||||
return __llvm_libc::syscall(n, a1, a2, a3, a4);
|
||||
});
|
||||
std::function<long(long, long, long, long, long, long)> f5(
|
||||
[](long n, long a1, long a2, long a3, long a4, long a5) {
|
||||
return __llvm_libc::syscall(n, a1, a2, a3, a4, a5);
|
||||
});
|
||||
std::function<long(long, long, long, long, long, long, long)> f6(
|
||||
[](long n, long a1, long a2, long a3, long a4, long a5, long a6) {
|
||||
return __llvm_libc::syscall(n, a1, a2, a3, a4, a5, a6);
|
||||
});
|
||||
}
|
|
@ -5,6 +5,12 @@ add_header(
|
|||
__llvm-libc-common.h
|
||||
)
|
||||
|
||||
add_header(
|
||||
libc_posix_types_h
|
||||
HDR
|
||||
__posix-types.h
|
||||
)
|
||||
|
||||
add_header(
|
||||
ctype_h
|
||||
HDR
|
||||
|
@ -38,3 +44,26 @@ add_gen_header(
|
|||
DATA_FILES
|
||||
../config/${LIBC_TARGET_OS}/errno.h.in
|
||||
)
|
||||
|
||||
# TODO: Not all platforms will have a include/sys directory. Add the sys
|
||||
# directory and the targets for sys/*.h files conditional to the OS requiring
|
||||
# them.
|
||||
file(MAKE_DIRECTORY "sys")
|
||||
|
||||
add_gen_header(
|
||||
sys_mman_h
|
||||
DEF_FILE sys/mman.h.def
|
||||
GEN_HDR sys/mman.h
|
||||
DEPENDS
|
||||
libc_posix_types_h
|
||||
)
|
||||
|
||||
add_gen_header(
|
||||
sys_syscall_h
|
||||
DEF_FILE sys/syscall.h.def
|
||||
GEN_HDR sys/syscall.h
|
||||
PARAMS
|
||||
syscall_numbers=../config/${LIBC_TARGET_OS}/syscall_numbers.h.inc
|
||||
DATA_FILES
|
||||
../config/${LIBC_TARGET_OS}/syscall_numbers.h.inc
|
||||
)
|
||||
|
|
|
@ -0,0 +1,16 @@
|
|||
//===----------------- Definitions of common POSIX types ------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// This header file does not have a header guard. It is internal to LLVM libc
|
||||
// and intended to be used to pick specific definitions without polluting the
|
||||
// public headers with unneccesary definitions.
|
||||
|
||||
#if defined(__need_off_t) && !defined(__llvm_libc_off_t_defined)
|
||||
typedef __INT64_TYPE__ off_t;
|
||||
#define __llvm_libc_off_t_defined
|
||||
#endif // __need_off_t
|
|
@ -0,0 +1,11 @@
|
|||
//===------------------------- POSIX header mman.h ------------------------===//
|
||||
//
|
||||
// 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 <__llvm-libc-common.h>
|
||||
|
||||
%%public_api()
|
|
@ -0,0 +1,12 @@
|
|||
//===---------------------- Linux like sys/syscall.h ----------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
<!> If syscall.h were a linux only file, then we do not need this indirection.
|
||||
<!> However, to keep the option of a non-linux OS requiring a syscall.h file,
|
||||
<!> with its own special syscall numbers, we use this indirection.
|
||||
%%include_file(${syscall_numbers})
|
|
@ -8,6 +8,10 @@ add_entrypoint_library(
|
|||
# string.h entrypoints
|
||||
strcpy
|
||||
strcat
|
||||
|
||||
# sys/mman.h entrypoints
|
||||
mmap
|
||||
munmap
|
||||
)
|
||||
|
||||
add_entrypoint_library(
|
||||
|
|
|
@ -60,7 +60,15 @@ def Linux : StandardSpec<"Linux"> {
|
|||
[] // Functions
|
||||
>;
|
||||
|
||||
HeaderSpec SysMMan = HeaderSpec<
|
||||
"sys/mman.h",
|
||||
[Macro<"MAP_ANONYMOUS">],
|
||||
[], // Types
|
||||
[] // Functions
|
||||
>;
|
||||
|
||||
let Headers = [
|
||||
Errno,
|
||||
SysMMan,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
def POSIX : StandardSpec<"POSIX"> {
|
||||
NamedType OffTType = NamedType<"off_t">;
|
||||
|
||||
HeaderSpec Errno = HeaderSpec<
|
||||
"errno.h",
|
||||
[
|
||||
|
@ -85,7 +87,47 @@ def POSIX : StandardSpec<"POSIX"> {
|
|||
[] // Functions
|
||||
>;
|
||||
|
||||
HeaderSpec SysMMan = HeaderSpec<
|
||||
"sys/mman.h",
|
||||
[
|
||||
// TODO: Add a facility to bunch macros into bitwise-or-able groups.
|
||||
// POSIX requires it, so such thing should be captured in this spec.
|
||||
Macro<"PROT_EXEC">,
|
||||
Macro<"PROT_NONE">,
|
||||
Macro<"PROT_READ">,
|
||||
Macro<"PROT_WRITE">,
|
||||
|
||||
Macro<"MAP_FIXED">,
|
||||
Macro<"MAP_PRIVATE">,
|
||||
Macro<"MAP_SHARED">,
|
||||
|
||||
Macro<"MAP_FAILED">,
|
||||
],
|
||||
[
|
||||
SizeTType,
|
||||
OffTType,
|
||||
],
|
||||
[
|
||||
FunctionSpec<
|
||||
"mmap",
|
||||
RetValSpec<VoidPtr>,
|
||||
[ArgSpec<VoidPtr>,
|
||||
ArgSpec<SizeTType>,
|
||||
ArgSpec<IntType>,
|
||||
ArgSpec<IntType>,
|
||||
ArgSpec<IntType>,
|
||||
ArgSpec<OffTType>]
|
||||
>,
|
||||
FunctionSpec<
|
||||
"munmap",
|
||||
RetValSpec<IntType>,
|
||||
[ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
|
||||
>,
|
||||
]
|
||||
>;
|
||||
|
||||
let Headers = [
|
||||
Errno,
|
||||
SysMMan,
|
||||
];
|
||||
}
|
||||
|
|
|
@ -35,6 +35,10 @@ def DoubleType : NamedType<"double">;
|
|||
def LongDoubleType : NamedType<"long double">;
|
||||
def CharType : NamedType<"char">;
|
||||
|
||||
// Common types
|
||||
def VoidPtr : PtrType<VoidType>;
|
||||
def SizeTType : NamedType<"size_t">;
|
||||
|
||||
class Macro<string name> {
|
||||
string Name = name;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
def StdC : StandardSpec<"stdc"> {
|
||||
PtrType VoidPtr = PtrType<VoidType>;
|
||||
ConstType ConstVoidPtr = ConstType<VoidPtr>;
|
||||
RestrictedPtrType VoidRestrictedPtr = RestrictedPtrType<VoidType>;
|
||||
ConstType ConstVoidRestrictedPtr = ConstType<VoidRestrictedPtr>;
|
||||
|
@ -9,8 +8,6 @@ def StdC : StandardSpec<"stdc"> {
|
|||
RestrictedPtrType CharRestrictedPtr = RestrictedPtrType<CharType>;
|
||||
ConstType ConstCharRestrictedPtr = ConstType<CharRestrictedPtr>;
|
||||
|
||||
NamedType SizeTType = NamedType<"size_t">;
|
||||
|
||||
HeaderSpec String = HeaderSpec<
|
||||
"string.h",
|
||||
[
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
add_subdirectory(errno)
|
||||
add_subdirectory(math)
|
||||
add_subdirectory(string)
|
||||
# TODO: Add this target conditional to the target OS.
|
||||
add_subdirectory(sys)
|
||||
add_subdirectory(unistd)
|
||||
|
||||
add_subdirectory(__support)
|
||||
|
|
|
@ -2,8 +2,8 @@ add_gen_header(
|
|||
support_common_h
|
||||
DEF_FILE common.h.def
|
||||
PARAMS
|
||||
entrypoint_macro=${LIBC_TARGET_OS}/entrypoint_macro.h.inc
|
||||
platform_defs=../../config/${LIBC_TARGET_OS}/platfrom_defs.h.inc
|
||||
GEN_HDR common.h
|
||||
DATA_FILES
|
||||
${LIBC_TARGET_OS}/entrypoint_macro.h.inc
|
||||
../../config/${LIBC_TARGET_OS}/platfrom_defs.h.inc
|
||||
)
|
||||
|
|
|
@ -9,10 +9,10 @@
|
|||
#ifndef LLVM_LIBC_SUPPORT_COMMON_H
|
||||
#define LLVM_LIBC_SUPPORT_COMMON_H
|
||||
|
||||
#define INLINE_ASM __asm__ __volatile__
|
||||
#define LIBC_INLINE_ASM __asm__ __volatile__
|
||||
|
||||
<!> The entrypoint macro has a platform specific definition. So, we include the
|
||||
<!> right definition at build time.
|
||||
%%include_file(${entrypoint_macro})
|
||||
<!> Include the platform specific definitions at build time. For example, that
|
||||
<!> of entrypoint macro.
|
||||
%%include_file(${platform_defs})
|
||||
|
||||
#endif // LLVM_LIBC_SUPPORT_COMMON_H
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
add_subdirectory(mman)
|
|
@ -0,0 +1,41 @@
|
|||
#TODO: The sources and target listed here should ideally live in config/linux.
|
||||
|
||||
add_entrypoint_object(
|
||||
mmap
|
||||
SRCS
|
||||
mmap.cpp
|
||||
HDRS
|
||||
mmap.h
|
||||
DEPENDS
|
||||
sys_mman_h
|
||||
sys_syscall_h
|
||||
syscall_impl_h
|
||||
__errno_location
|
||||
)
|
||||
|
||||
add_entrypoint_object(
|
||||
munmap
|
||||
SRCS
|
||||
munmap.cpp
|
||||
HDRS
|
||||
munmap.h
|
||||
DEPENDS
|
||||
sys_mman_h
|
||||
sys_syscall_h
|
||||
syscall_impl_h
|
||||
__errno_location
|
||||
)
|
||||
|
||||
add_custom_target(libc_sys_mman_unittests)
|
||||
|
||||
add_libc_unittest(
|
||||
mmap_test
|
||||
SUITE
|
||||
libc_sys_mman_unittests
|
||||
SRCS
|
||||
mmap_test.cpp
|
||||
DEPENDS
|
||||
mmap
|
||||
munmap
|
||||
__errno_location
|
||||
)
|
|
@ -0,0 +1,57 @@
|
|||
//===-------------- Implementation of the POSIX mmap function -------------===//
|
||||
//
|
||||
// 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/sys/mman/mmap.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/errno/llvmlibc_errno.h"
|
||||
|
||||
#include "src/unistd/syscall.h" // For internal syscall function.
|
||||
|
||||
#include <sys/syscall.h> // For syscall numbers.
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
// This function is currently linux only. It has to be refactored suitably if
|
||||
// mmap is to be supported on non-linux operating systems also.
|
||||
void *LLVM_LIBC_ENTRYPOINT(mmap)(void *addr, size_t size, int prot, int flags,
|
||||
int fd, off_t offset) {
|
||||
// A lot of POSIX standard prescribed validation of the parameters is not
|
||||
// done in this function as modern linux versions do it in the syscall.
|
||||
// TODO: Perform argument validation not done by the linux syscall.
|
||||
|
||||
#ifdef SYS_mmap2
|
||||
offset /= PAGE_SIZE;
|
||||
long syscall_number = SYS_mmap2;
|
||||
#elif SYS_mmap
|
||||
long syscall_number = SYS_mmap;
|
||||
#else
|
||||
#error "Target platform does not have SYS_mmap or SYS_mmap2 defined"
|
||||
#endif
|
||||
|
||||
long ret_val =
|
||||
__llvm_libc::syscall(syscall_number, reinterpret_cast<long>(addr), size,
|
||||
prot, flags, fd, offset);
|
||||
|
||||
// The mmap/mmap2 syscalls return negative values on error. These negative
|
||||
// values are actually the negative values of the error codes. So, fix them
|
||||
// up in case an error code is detected.
|
||||
//
|
||||
// A point to keep in mind for the fix up is that a negative return value
|
||||
// from the syscall can also be an error-free value returned by the syscall.
|
||||
// However, since a valid return address cannot be within the last page, a
|
||||
// return value corresponding to a location in the last page is an error
|
||||
// value.
|
||||
if (ret_val < 0 && ret_val > -PAGE_SIZE) {
|
||||
llvmlibc_errno = -ret_val;
|
||||
return MAP_FAILED;
|
||||
}
|
||||
|
||||
return reinterpret_cast<void *>(ret_val);
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
|||
//===-------------- Implementation header for mmap function ------ *-C++-* ===//
|
||||
//
|
||||
// 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_SYS_MMAN_MMAP_H
|
||||
#define LLVM_LIBC_SRC_SYS_MMAN_MMAP_H
|
||||
|
||||
#include <sys/mman.h> // For size_t and off_t
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
void *mmap(void *addr, size_t size, int prot, int flags, int fd, off_t offset);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_SYS_MMAN_MMAP_H
|
|
@ -0,0 +1,48 @@
|
|||
//===------------------ Unittests for mmap and munmap ---------------------===//
|
||||
//
|
||||
// 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/errno/llvmlibc_errno.h"
|
||||
#include "src/sys/mman/mmap.h"
|
||||
#include "src/sys/mman/munmap.h"
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
#include "errno.h"
|
||||
#include "sys/mman.h"
|
||||
|
||||
TEST(MMapTest, NoError) {
|
||||
size_t alloc_size = 128;
|
||||
llvmlibc_errno = 0;
|
||||
void *addr = __llvm_libc::mmap(nullptr, alloc_size, PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
EXPECT_EQ(0, llvmlibc_errno);
|
||||
EXPECT_NE(addr, MAP_FAILED);
|
||||
|
||||
int *array = reinterpret_cast<int *>(addr);
|
||||
// Reading from the memory should not crash the test.
|
||||
// Since we used the MAP_ANONYMOUS flag, the contents of the newly
|
||||
// allocated memory should be initialized to zero.
|
||||
EXPECT_EQ(array[0], 0);
|
||||
|
||||
int ret_val = __llvm_libc::munmap(addr, alloc_size);
|
||||
EXPECT_EQ(0, ret_val);
|
||||
EXPECT_EQ(0, llvmlibc_errno);
|
||||
}
|
||||
|
||||
TEST(MMapTest, Error_InvalidSize) {
|
||||
llvmlibc_errno = 0;
|
||||
void *addr = __llvm_libc::mmap(nullptr, 0, PROT_READ,
|
||||
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
EXPECT_EQ(EINVAL, llvmlibc_errno);
|
||||
EXPECT_EQ(addr, MAP_FAILED);
|
||||
|
||||
llvmlibc_errno = 0;
|
||||
int ret_val = __llvm_libc::munmap(0, 0);
|
||||
EXPECT_EQ(-1, ret_val);
|
||||
EXPECT_EQ(EINVAL, llvmlibc_errno);
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
//===------------- Implementation of the POSIX munmap function ------------===//
|
||||
//
|
||||
// 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/sys/mman/munmap.h"
|
||||
#include "src/__support/common.h"
|
||||
#include "src/errno/llvmlibc_errno.h"
|
||||
|
||||
#include "src/unistd/syscall.h" // For internal syscall function.
|
||||
|
||||
#include <sys/syscall.h> // For syscall numbers.
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
// This function is currently linux only. It has to be refactored suitably if
|
||||
// mmap is to be supported on non-linux operating systems also.
|
||||
int LLVM_LIBC_ENTRYPOINT(munmap)(void *addr, size_t size) {
|
||||
long ret_val =
|
||||
__llvm_libc::syscall(SYS_munmap, reinterpret_cast<long>(addr), size);
|
||||
|
||||
// A negative return value indicates an error with the magnitude of the
|
||||
// value being the error code.
|
||||
if (ret_val < 0) {
|
||||
llvmlibc_errno = -ret_val;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace __llvm_libc
|
|
@ -0,0 +1,20 @@
|
|||
//===-------------- Implementation header for mumap function ----- *-C++-* ===//
|
||||
//
|
||||
// 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_SYS_MMAN_MUNMAP_H
|
||||
#define LLVM_LIBC_SRC_SYS_MMAN_MUNMAP_H
|
||||
|
||||
#include <sys/mman.h> // For size_t
|
||||
|
||||
namespace __llvm_libc {
|
||||
|
||||
int munmap(void *addr, size_t size);
|
||||
|
||||
} // namespace __llvm_libc
|
||||
|
||||
#endif // LLVM_LIBC_SRC_SYS_MMAN_MUNMAP_H
|
|
@ -0,0 +1,9 @@
|
|||
add_gen_header(
|
||||
syscall_impl_h
|
||||
DEF_FILE syscall.h.def
|
||||
GEN_HDR syscall.h
|
||||
PARAMS
|
||||
inline_syscalls=../../config/${LIBC_TARGET_OS}/${LIBC_TARGET_MACHINE}/syscall.h.inc
|
||||
DATA_FILES
|
||||
../../config/${LIBC_TARGET_OS}/${LIBC_TARGET_MACHINE}/syscall.h.inc
|
||||
)
|
|
@ -0,0 +1,9 @@
|
|||
//===--------------- Internal syscall declarations --------------*- C++ -*-===//
|
||||
//
|
||||
// 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_file(${inline_syscalls})
|
Loading…
Reference in New Issue