2,320 changes: 2,320 additions & 0 deletions libc/config/linux/syscall_numbers.h.inc

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions libc/config/linux/x86_64/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
93 changes: 93 additions & 0 deletions libc/config/linux/x86_64/syscall.h.inc
Original file line number Diff line number Diff line change
@@ -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
40 changes: 40 additions & 0 deletions libc/config/linux/x86_64/syscall_test.cpp
Original file line number Diff line number Diff line change
@@ -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);
});
}
29 changes: 29 additions & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
)
16 changes: 16 additions & 0 deletions libc/include/__posix-types.h
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions libc/include/sys/mman.h.def
Original file line number Diff line number Diff line change
@@ -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()
12 changes: 12 additions & 0 deletions libc/include/sys/syscall.h.def
Original file line number Diff line number Diff line change
@@ -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})
4 changes: 4 additions & 0 deletions libc/lib/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ add_entrypoint_library(
# string.h entrypoints
strcpy
strcat

# sys/mman.h entrypoints
mmap
munmap
)

add_entrypoint_library(
Expand Down
8 changes: 8 additions & 0 deletions libc/spec/linux.td
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,15 @@ def Linux : StandardSpec<"Linux"> {
[] // Functions
>;

HeaderSpec SysMMan = HeaderSpec<
"sys/mman.h",
[Macro<"MAP_ANONYMOUS">],
[], // Types
[] // Functions
>;

let Headers = [
Errno,
SysMMan,
];
}
42 changes: 42 additions & 0 deletions libc/spec/posix.td
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
def POSIX : StandardSpec<"POSIX"> {
NamedType OffTType = NamedType<"off_t">;

HeaderSpec Errno = HeaderSpec<
"errno.h",
[
Expand Down Expand Up @@ -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,
];
}
4 changes: 4 additions & 0 deletions libc/spec/spec.td
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
3 changes: 0 additions & 3 deletions libc/spec/stdc.td
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
def StdC : StandardSpec<"stdc"> {
PtrType VoidPtr = PtrType<VoidType>;
ConstType ConstVoidPtr = ConstType<VoidPtr>;
RestrictedPtrType VoidRestrictedPtr = RestrictedPtrType<VoidType>;
ConstType ConstVoidRestrictedPtr = ConstType<VoidRestrictedPtr>;
Expand All @@ -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",
[
Expand Down
3 changes: 3 additions & 0 deletions libc/src/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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)
4 changes: 2 additions & 2 deletions libc/src/__support/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
)
8 changes: 4 additions & 4 deletions libc/src/__support/common.h.def
Original file line number Diff line number Diff line change
Expand Up @@ -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
1 change: 1 addition & 0 deletions libc/src/sys/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
add_subdirectory(mman)
41 changes: 41 additions & 0 deletions libc/src/sys/mman/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
57 changes: 57 additions & 0 deletions libc/src/sys/mman/mmap.cpp
Original file line number Diff line number Diff line change
@@ -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 changes: 20 additions & 0 deletions libc/src/sys/mman/mmap.h
Original file line number Diff line number Diff line change
@@ -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
48 changes: 48 additions & 0 deletions libc/src/sys/mman/mmap_test.cpp
Original file line number Diff line number Diff line change
@@ -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);
}
35 changes: 35 additions & 0 deletions libc/src/sys/mman/munmap.cpp
Original file line number Diff line number Diff line change
@@ -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
20 changes: 20 additions & 0 deletions libc/src/sys/mman/munmap.h
Original file line number Diff line number Diff line change
@@ -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
9 changes: 9 additions & 0 deletions libc/src/unistd/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -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
)
9 changes: 9 additions & 0 deletions libc/src/unistd/syscall.h.def
Original file line number Diff line number Diff line change
@@ -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})