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:
Siva Chandra Reddy 2019-12-04 23:17:14 -08:00
parent 187f66bcac
commit e5a743c4f6
31 changed files with 2916 additions and 35 deletions

View File

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

View File

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

View File

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

View File

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

View File

@ -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",
];
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -8,6 +8,10 @@ add_entrypoint_library(
# string.h entrypoints
strcpy
strcat
# sys/mman.h entrypoints
mmap
munmap
)
add_entrypoint_library(

View File

@ -60,7 +60,15 @@ def Linux : StandardSpec<"Linux"> {
[] // Functions
>;
HeaderSpec SysMMan = HeaderSpec<
"sys/mman.h",
[Macro<"MAP_ANONYMOUS">],
[], // Types
[] // Functions
>;
let Headers = [
Errno,
SysMMan,
];
}

View File

@ -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,
];
}

View File

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

View File

@ -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",
[

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

20
libc/src/sys/mman/mmap.h Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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