mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-26 22:38:30 +00:00
Add some documentation
This commit is contained in:
parent
567d8fe32d
commit
1ff037df3c
5 changed files with 177 additions and 22 deletions
|
@ -544,8 +544,13 @@ static void *__mmap(char *addr, size_t size, int prot, int flags, int fd,
|
||||||
int gransz = __gransize;
|
int gransz = __gransize;
|
||||||
|
|
||||||
// validate arguments
|
// validate arguments
|
||||||
if (((uintptr_t)addr & (gransz - 1)) || //
|
if ((uintptr_t)addr & (gransz - 1))
|
||||||
!size || (uintptr_t)addr + size < size)
|
addr = NULL;
|
||||||
|
if (!addr && (flags & (MAP_FIXED | MAP_FIXED_NOREPLACE)))
|
||||||
|
return (void *)eperm();
|
||||||
|
if ((intptr_t)addr < 0)
|
||||||
|
return (void *)enomem();
|
||||||
|
if (!size || (uintptr_t)addr + size < size)
|
||||||
return (void *)einval();
|
return (void *)einval();
|
||||||
if (size > WINMAXX)
|
if (size > WINMAXX)
|
||||||
return (void *)enomem();
|
return (void *)enomem();
|
||||||
|
@ -732,13 +737,100 @@ static void *__mremap(char *old_addr, size_t old_size, size_t new_size,
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates memory mapping.
|
||||||
|
*
|
||||||
|
* The mmap() function is used by Cosmopolitan's malloc() implementation
|
||||||
|
* to obtain new memory from the operating system. This function is also
|
||||||
|
* useful for establishing a mapping between a file on disk and a memory
|
||||||
|
* address, which avoids most need to call read() and write(). It is how
|
||||||
|
* executables are loaded into memory, for instance, in which case pages
|
||||||
|
* are loaded lazily from disk by the operating system.
|
||||||
|
*
|
||||||
|
* The `addr` parameter may be zero. This lets the implementation choose
|
||||||
|
* an available address in memory. OSes normally pick something randomly
|
||||||
|
* assigned, for security. Most OSes try to make sure subsequent mapping
|
||||||
|
* requests will be adjacent to one another. More paranoid OSes may have
|
||||||
|
* different mappings be sparse, with unmapped content between them. You
|
||||||
|
* may not use the `MAP_FIXED` parameter to create a memory map at NULL.
|
||||||
|
*
|
||||||
|
* The `addr` parameter may be non-zero, in which case Cosmopolitan will
|
||||||
|
* give you a mapping at that specific address if it's available. When a
|
||||||
|
* mapping already exists at the requested address then another one will
|
||||||
|
* be chosen automatically. On most OSes the newly selected address will
|
||||||
|
* be as close-by as possible, but that's not guaranteed. If `MAP_FIXED`
|
||||||
|
* is also supplied in `flags` then this hint is taken as mandatory, and
|
||||||
|
* existing mappings at the requested interval shall be auto-unmapped.
|
||||||
|
*
|
||||||
|
* The `size` parameter is implicitly rounded up to the system page size
|
||||||
|
* reported by getpagesize() and sysconf(_SC_PAGESIZE). Your extra bytes
|
||||||
|
* will be zero-initialized.
|
||||||
|
*
|
||||||
|
* The returned address will always be aligned, on the system allocation
|
||||||
|
* granularity. This value may be obtained from getgransize() or calling
|
||||||
|
* sysconf(_SC_GRANSIZE). Granularity is always greater than or equal to
|
||||||
|
* the page size. On some platforms, i.e. Windows, it may be larger than
|
||||||
|
* the page size.
|
||||||
|
*
|
||||||
|
* The `prot` value specifies the memory protection of the mapping. This
|
||||||
|
* may be `PROT_NONE` to disallow all access otherwise it's a bitwise or
|
||||||
|
* of the following constants:
|
||||||
|
*
|
||||||
|
* - `PROT_READ` allows read access
|
||||||
|
* - `PROT_WRITE` allows write access
|
||||||
|
* - `PROT_EXEC` allows execute access
|
||||||
|
*
|
||||||
|
* Some OSes (i.e. OpenBSD) will raise an error if both `PROT_WRITE` and
|
||||||
|
* `PROT_EXEC` are requested. You may still modify executable memory but
|
||||||
|
* you must use mprotect() to transition between the two states. On some
|
||||||
|
* OSes like MacOS ARM64, you need to pass the `MAP_JIT` flag to get RWX
|
||||||
|
* memory, which is considered zero on other OSes.
|
||||||
|
*
|
||||||
|
* The lower bits of the `flags` parameter specify the `MAP_TYPE`, which
|
||||||
|
* may be:
|
||||||
|
*
|
||||||
|
* - `MAP_PRIVATE` for non-shared and copy-on-write mappings
|
||||||
|
* - `MAP_SHARED` for memory that may be shared between processes
|
||||||
|
*
|
||||||
|
* Your `fd` argument specifies the file descriptor of the open file you
|
||||||
|
* want to map. This parameter is ignored when `MAP_ANONYMOUS` is passed
|
||||||
|
* via `flags`.
|
||||||
|
*
|
||||||
|
* Your `off` argument specifies the offset into a, file at which mapped
|
||||||
|
* memory shall begin. It must be aligned to the allocation granularity,
|
||||||
|
* which may be obtained from getgransize() or sysconf(_SC_GRANSIZE).
|
||||||
|
*
|
||||||
|
* The `MAP_FIXED_NOREPLACE` flag may be passed in `flags` which has the
|
||||||
|
* same behavior as `MAP_FIXED` except it raises `EEXIST` when a mapping
|
||||||
|
* already exists on the requested interval.
|
||||||
|
*
|
||||||
|
* The `MAP_CONCEAL` flag may be passed to prevent a memory mapping from
|
||||||
|
* appearing in core dumps. This is currently supported on BSD OSes, and
|
||||||
|
* is ignored on everything else.
|
||||||
|
*/
|
||||||
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
void *mmap(void *addr, size_t size, int prot, int flags, int fd, int64_t off) {
|
||||||
void *res = __mmap(addr, size, prot, flags, fd, off);
|
void *res = __mmap(addr, size, prot, flags, fd, off);
|
||||||
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m", addr, size,
|
STRACE("mmap(%p, %'zu, %s, %s, %d, %'ld) → %p% m (%'zu bytes total)", addr,
|
||||||
DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res);
|
size, DescribeProtFlags(prot), DescribeMapFlags(flags), fd, off, res,
|
||||||
|
__maps.pages * __pagesize);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Changes memory mapping.
|
||||||
|
*
|
||||||
|
* This system call lets you move memory without copying it. It can also
|
||||||
|
* be used to shrink memory mappings.
|
||||||
|
*
|
||||||
|
* This system call is supported on Linux and NetBSD. It's used by Cosmo
|
||||||
|
* Libc's realloc() implementation under the hood.
|
||||||
|
*
|
||||||
|
* The `flags` parameter may have:
|
||||||
|
*
|
||||||
|
* - `MREMAP_MAYMOVE` to allow relocation
|
||||||
|
* - `MREMAP_FIXED` in which case an additional parameter is taken
|
||||||
|
*
|
||||||
|
*/
|
||||||
void *mremap(void *old_addr, size_t old_size, size_t new_size, int flags, ...) {
|
void *mremap(void *old_addr, size_t old_size, size_t new_size, int flags, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
void *new_addr = 0;
|
void *new_addr = 0;
|
||||||
|
@ -748,11 +840,19 @@ void *mremap(void *old_addr, size_t old_size, size_t new_size, int flags, ...) {
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
void *res = __mremap(old_addr, old_size, new_size, flags, new_addr);
|
void *res = __mremap(old_addr, old_size, new_size, flags, new_addr);
|
||||||
STRACE("mremap(%p, %'zu, %'zu, %s, %p) → %p% m", old_addr, old_size, new_size,
|
STRACE("mremap(%p, %'zu, %'zu, %s, %p) → %p% m (%'zu bytes total)", old_addr,
|
||||||
DescribeMremapFlags(flags), new_addr, res);
|
old_size, new_size, DescribeMremapFlags(flags), new_addr, res,
|
||||||
|
__maps.pages * __pagesize);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes memory mapping.
|
||||||
|
*
|
||||||
|
* The `size` parameter is implicitly rounded up to the page size.
|
||||||
|
*
|
||||||
|
* @return 0 on success, or -1 w/ errno.
|
||||||
|
*/
|
||||||
int munmap(void *addr, size_t size) {
|
int munmap(void *addr, size_t size) {
|
||||||
int rc = __munmap(addr, size);
|
int rc = __munmap(addr, size);
|
||||||
STRACE("munmap(%p, %'zu) → %d% m", addr, size, rc);
|
STRACE("munmap(%p, %'zu) → %d% m", addr, size, rc);
|
||||||
|
|
|
@ -223,7 +223,6 @@ syscon mmap MAP_TYPE 15 15 15 15 15 15 15 15 # mask for type
|
||||||
syscon mmap MAP_FIXED 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 # unix consensus; openbsd appears to forbid; faked nt
|
syscon mmap MAP_FIXED 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 0x00000010 # unix consensus; openbsd appears to forbid; faked nt
|
||||||
syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x08000000 0x00004000 0x00004000 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+; MAP_FIXED|MAP_EXCL on FreeBSD
|
syscon mmap MAP_FIXED_NOREPLACE 0x08000000 0x08000000 0x00004000 0x00004000 0x08000000 0x08000000 0x08000000 0x08000000 # handled and defined by cosmo runtime; 0x100000 on linux 4.7+; MAP_FIXED|MAP_EXCL on FreeBSD
|
||||||
syscon mmap MAP_ANONYMOUS 0x00000020 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
|
syscon mmap MAP_ANONYMOUS 0x00000020 0x00000020 0x00001000 0x00001000 0x00001000 0x00001000 0x00001000 0x00000020 # bsd consensus; faked nt
|
||||||
syscon mmap MAP_GROWSDOWN 0x00000100 0x00000100 0 0 0 0 0 0 # use MAP_STACK; abstracted by MAP_STACK; may be passed to __sys_mmap() for low-level Linux fiddling
|
|
||||||
syscon mmap MAP_LOCKED 0x00002000 0x00002000 0 0 0 0 0 0
|
syscon mmap MAP_LOCKED 0x00002000 0x00002000 0 0 0 0 0 0
|
||||||
syscon mmap MAP_NORESERVE 0x00004000 0x00004000 0x00000040 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
|
syscon mmap MAP_NORESERVE 0x00004000 0x00004000 0x00000040 0x00000040 0 0 0x00000040 0 # Linux calls it "reserve"; NT calls it "commit"? which is default?
|
||||||
syscon mmap MAP_POPULATE 0x00008000 0x00008000 0 0 0x00040000 0 0 0 # MAP_PREFAULT_READ on FreeBSD; can avoid madvise(MADV_WILLNEED) on private file mapping
|
syscon mmap MAP_POPULATE 0x00008000 0x00008000 0 0 0x00040000 0 0 0 # MAP_PREFAULT_READ on FreeBSD; can avoid madvise(MADV_WILLNEED) on private file mapping
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
#include "libc/sysv/consts/syscon.internal.h"
|
|
||||||
.syscon mmap,MAP_GROWSDOWN,0x00000100,0x00000100,0,0,0,0,0,0
|
|
|
@ -22,6 +22,7 @@
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/maps.h"
|
#include "libc/intrin/maps.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
#include "libc/literal.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
#include "libc/runtime/sysconf.h"
|
#include "libc/runtime/sysconf.h"
|
||||||
#include "libc/stdio/rand.h"
|
#include "libc/stdio/rand.h"
|
||||||
|
@ -146,7 +147,6 @@ TEST(mmap, hint) {
|
||||||
TEST(mprotect, punchHoleAndFillHole) {
|
TEST(mprotect, punchHoleAndFillHole) {
|
||||||
char *p;
|
char *p;
|
||||||
int count = __maps.count;
|
int count = __maps.count;
|
||||||
int gransz = getgransize();
|
|
||||||
|
|
||||||
// obtain memory
|
// obtain memory
|
||||||
ASSERT_NE(MAP_FAILED,
|
ASSERT_NE(MAP_FAILED,
|
||||||
|
@ -223,16 +223,17 @@ TEST(mmap, testMapFile_fdGetsClosed_makesNoDifference) {
|
||||||
TEST(mmap, fileOffset) {
|
TEST(mmap, fileOffset) {
|
||||||
int fd;
|
int fd;
|
||||||
char *map;
|
char *map;
|
||||||
int offset_align = IsWindows() ? gransz : getpagesize();
|
|
||||||
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
ASSERT_NE(-1, (fd = open("foo", O_CREAT | O_RDWR, 0644)));
|
||||||
EXPECT_NE(-1, ftruncate(fd, offset_align * 2));
|
EXPECT_NE(-1, ftruncate(fd, gransz * 2));
|
||||||
EXPECT_NE(-1, pwrite(fd, "hello", 5, offset_align * 0));
|
EXPECT_NE(-1, pwrite(fd, "hello", 5, gransz * 0));
|
||||||
EXPECT_NE(-1, pwrite(fd, "there", 5, offset_align * 1));
|
EXPECT_NE(-1, pwrite(fd, "there", 5, gransz * 1));
|
||||||
EXPECT_NE(-1, fdatasync(fd));
|
EXPECT_NE(-1, fdatasync(fd));
|
||||||
ASSERT_NE(MAP_FAILED, (map = mmap(NULL, offset_align, PROT_READ, MAP_PRIVATE,
|
ASSERT_SYS(EINVAL, MAP_FAILED,
|
||||||
fd, offset_align)));
|
mmap(NULL, gransz, PROT_READ, MAP_PRIVATE, fd, gransz - 1));
|
||||||
|
ASSERT_NE(MAP_FAILED,
|
||||||
|
(map = mmap(NULL, gransz, PROT_READ, MAP_PRIVATE, fd, gransz)));
|
||||||
EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map);
|
EXPECT_EQ(0, memcmp(map, "there", 5), "%#.*s", 5, map);
|
||||||
EXPECT_NE(-1, munmap(map, offset_align));
|
EXPECT_NE(-1, munmap(map, gransz));
|
||||||
EXPECT_NE(-1, close(fd));
|
EXPECT_NE(-1, close(fd));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -263,6 +264,67 @@ TEST(mmap, ziposCannotBeShared) {
|
||||||
close(fd);
|
close(fd);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST(mmap, misalignedAddr_justIgnoresIt) {
|
||||||
|
char *p;
|
||||||
|
ASSERT_NE(MAP_FAILED, (p = mmap((void *)1, 1, PROT_READ,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)));
|
||||||
|
munmap(p, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mmap, nullFixed_isNotAllowed) {
|
||||||
|
ASSERT_SYS(
|
||||||
|
EPERM, MAP_FAILED,
|
||||||
|
mmap(0, 1, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));
|
||||||
|
ASSERT_SYS(EPERM, MAP_FAILED,
|
||||||
|
mmap(0, 1, PROT_NONE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED_NOREPLACE, -1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
static int GetBitsInAddressSpace(void) {
|
||||||
|
int i;
|
||||||
|
void *ptr;
|
||||||
|
uint64_t want;
|
||||||
|
for (i = 0; i < 40; ++i) {
|
||||||
|
want = UINT64_C(0x8123000000000000) >> i;
|
||||||
|
if (want > UINTPTR_MAX)
|
||||||
|
continue;
|
||||||
|
if (msync((void *)(uintptr_t)want, 1, MS_ASYNC) == 0 || errno == EBUSY)
|
||||||
|
return 64 - i;
|
||||||
|
ptr = mmap((void *)(uintptr_t)want, 1, PROT_READ,
|
||||||
|
MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
|
||||||
|
if (ptr != MAP_FAILED) {
|
||||||
|
munmap(ptr, 1);
|
||||||
|
return 64 - i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mmap, negative_isNotAllowed) {
|
||||||
|
ASSERT_SYS(ENOMEM, MAP_FAILED,
|
||||||
|
mmap((void *)-(70 * 1024 * 1024), 1, PROT_NONE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(mmap, pml5t) {
|
||||||
|
switch (GetBitsInAddressSpace()) {
|
||||||
|
case 56:
|
||||||
|
ASSERT_EQ((void *)0x00fff2749119c000,
|
||||||
|
mmap((void *)0x00fff2749119c000, 1, PROT_NONE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));
|
||||||
|
munmap((void *)0x00fff2749119c000, 1);
|
||||||
|
break;
|
||||||
|
case 48:
|
||||||
|
ASSERT_EQ((void *)0x0000f2749119c000,
|
||||||
|
mmap((void *)0x0000f2749119c000, 1, PROT_NONE,
|
||||||
|
MAP_ANONYMOUS | MAP_PRIVATE | MAP_FIXED, -1, 0));
|
||||||
|
munmap((void *)0x0000f2749119c000, 1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
// zipos NON-SHARED READ-ONLY FILE MEMORY
|
// zipos NON-SHARED READ-ONLY FILE MEMORY
|
||||||
|
|
||||||
|
|
6
third_party/dlmalloc/platform.inc
vendored
6
third_party/dlmalloc/platform.inc
vendored
|
@ -505,11 +505,7 @@ FORCEINLINE int win32munmap(void* ptr, size_t size) {
|
||||||
* Define CALL_MREMAP
|
* Define CALL_MREMAP
|
||||||
*/
|
*/
|
||||||
#if HAVE_MMAP && HAVE_MREMAP
|
#if HAVE_MMAP && HAVE_MREMAP
|
||||||
#ifdef MREMAP
|
#define CALL_MREMAP(addr, osz, nsz, mv) ({ int olderr = errno; void *res = mremap((addr), (osz), (nsz), (mv)); if (res == MAP_FAILED) errno = olderr; res; })
|
||||||
#define CALL_MREMAP(addr, osz, nsz, mv) MREMAP((addr), (osz), (nsz), (mv))
|
|
||||||
#else /* MREMAP */
|
|
||||||
#define CALL_MREMAP(addr, osz, nsz, mv) MREMAP_DEFAULT((addr), (osz), (nsz), (mv))
|
|
||||||
#endif /* MREMAP */
|
|
||||||
#else /* HAVE_MMAP && HAVE_MREMAP */
|
#else /* HAVE_MMAP && HAVE_MREMAP */
|
||||||
#define CALL_MREMAP(addr, osz, nsz, mv) MAP_FAILED
|
#define CALL_MREMAP(addr, osz, nsz, mv) MAP_FAILED
|
||||||
#endif /* HAVE_MMAP && HAVE_MREMAP */
|
#endif /* HAVE_MMAP && HAVE_MREMAP */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue