mirror of
https://github.com/topjohnwu/crt0.git
synced 2024-11-23 11:29:47 +00:00
Initial source dump
This commit is contained in:
parent
8bdf0f2760
commit
6e502efbbb
24
Android.mk
Normal file
24
Android.mk
Normal file
@ -0,0 +1,24 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := crt0
|
||||
|
||||
# Manually link the compiler runtime library
|
||||
LOCAL_compiler_rt := $(shell $(TARGET_CC) -target $(LLVM_TRIPLE)$(TARGET_PLATFORM_LEVEL) --print-libgcc-file-name)
|
||||
|
||||
LOCAL_EXPORT_LDFLAGS := -static -nostartfiles -nodefaultlibs $(LOCAL_compiler_rt) -Wl,--error-limit=0
|
||||
LOCAL_CFLAGS := -Wno-c99-designator
|
||||
|
||||
LOCAL_SRC_FILES := \
|
||||
malloc.c \
|
||||
mem.c \
|
||||
misc.c \
|
||||
nolibc.c \
|
||||
stdio.c \
|
||||
syscall.c \
|
||||
bionic/dirent.cpp \
|
||||
bionic/strerror.cpp \
|
||||
bionic/syscall-$(TARGET_ARCH).S \
|
||||
tinystdio/tinystdio.c
|
||||
|
||||
include $(BUILD_STATIC_LIBRARY)
|
168
bionic/dirent.cpp
Normal file
168
bionic/dirent.cpp
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <malloc.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include "private/ErrnoRestorer.h"
|
||||
|
||||
extern "C" int sys_getdents64(unsigned int, dirent*, unsigned int);
|
||||
|
||||
// Apportable decided to copy the data structure from this file
|
||||
// and use it in their own code, but they also call into readdir.
|
||||
// In order to avoid a lockup, the structure must be maintained in
|
||||
// the exact same order as in L and below. New structure members
|
||||
// need to be added to the end of this structure.
|
||||
// See b/21037208 for more details.
|
||||
struct DIR {
|
||||
int fd_;
|
||||
size_t available_bytes_;
|
||||
dirent* next_;
|
||||
dirent buff_[15];
|
||||
long current_pos_;
|
||||
};
|
||||
|
||||
static DIR* __allocate_DIR(int fd) {
|
||||
DIR* d = reinterpret_cast<DIR*>(malloc(sizeof(DIR)));
|
||||
if (d == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
d->fd_ = fd;
|
||||
d->available_bytes_ = 0;
|
||||
d->next_ = nullptr;
|
||||
d->current_pos_ = 0L;
|
||||
return d;
|
||||
}
|
||||
|
||||
int dirfd(DIR* d) {
|
||||
return d->fd_;
|
||||
}
|
||||
|
||||
DIR* fdopendir(int fd) {
|
||||
// Is 'fd' actually a directory?
|
||||
struct stat sb;
|
||||
if (fstat(fd, &sb) == -1) {
|
||||
return nullptr;
|
||||
}
|
||||
if (!S_ISDIR(sb.st_mode)) {
|
||||
errno = ENOTDIR;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return __allocate_DIR(fd);
|
||||
}
|
||||
|
||||
DIR* opendir(const char* path) {
|
||||
int fd = open(path, O_CLOEXEC | O_DIRECTORY | O_RDONLY);
|
||||
return (fd != -1) ? __allocate_DIR(fd) : nullptr;
|
||||
}
|
||||
|
||||
static bool __fill_DIR(DIR* d) {
|
||||
int rc = TEMP_FAILURE_RETRY(sys_getdents64(d->fd_, d->buff_, sizeof(d->buff_)));
|
||||
if (rc <= 0) {
|
||||
return false;
|
||||
}
|
||||
d->available_bytes_ = rc;
|
||||
d->next_ = d->buff_;
|
||||
return true;
|
||||
}
|
||||
|
||||
static dirent* __readdir_locked(DIR* d) {
|
||||
if (d->available_bytes_ == 0 && !__fill_DIR(d)) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
dirent* entry = d->next_;
|
||||
d->next_ = reinterpret_cast<dirent*>(reinterpret_cast<char*>(entry) + entry->d_reclen);
|
||||
d->available_bytes_ -= entry->d_reclen;
|
||||
// The directory entry offset uses 0, 1, 2 instead of real file offset,
|
||||
// so the value range of long type is enough.
|
||||
d->current_pos_ = static_cast<long>(entry->d_off);
|
||||
return entry;
|
||||
}
|
||||
|
||||
dirent* readdir(DIR* d) {
|
||||
return __readdir_locked(d);
|
||||
}
|
||||
__strong_alias(readdir64, readdir);
|
||||
|
||||
int readdir_r(DIR* d, dirent* entry, dirent** result) {
|
||||
ErrnoRestorer errno_restorer;
|
||||
|
||||
*result = nullptr;
|
||||
errno = 0;
|
||||
|
||||
dirent* next = __readdir_locked(d);
|
||||
if (errno != 0 && next == nullptr) {
|
||||
return errno;
|
||||
}
|
||||
|
||||
if (next != nullptr) {
|
||||
memcpy(entry, next, next->d_reclen);
|
||||
*result = entry;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
__strong_alias(readdir64_r, readdir_r);
|
||||
|
||||
int closedir(DIR* d) {
|
||||
if (d == nullptr) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int fd = d->fd_;
|
||||
int rc = close(fd);
|
||||
free(d);
|
||||
return rc;
|
||||
}
|
||||
|
||||
void rewinddir(DIR* d) {
|
||||
lseek(d->fd_, 0, SEEK_SET);
|
||||
d->available_bytes_ = 0;
|
||||
d->current_pos_ = 0L;
|
||||
}
|
||||
|
||||
void seekdir(DIR* d, long offset) {
|
||||
off_t ret = lseek(d->fd_, offset, SEEK_SET);
|
||||
if (ret != -1L) {
|
||||
d->available_bytes_ = 0;
|
||||
d->current_pos_ = ret;
|
||||
}
|
||||
}
|
||||
|
||||
long telldir(DIR* d) {
|
||||
return d->current_pos_;
|
||||
}
|
36
bionic/private/ErrnoRestorer.h
Normal file
36
bionic/private/ErrnoRestorer.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <errno.h>
|
||||
|
||||
class ErrnoRestorer {
|
||||
public:
|
||||
explicit ErrnoRestorer() : saved_errno_(errno) {
|
||||
}
|
||||
|
||||
~ErrnoRestorer() {
|
||||
errno = saved_errno_;
|
||||
}
|
||||
|
||||
void override(int new_errno) {
|
||||
saved_errno_ = new_errno;
|
||||
}
|
||||
|
||||
private:
|
||||
int saved_errno_;
|
||||
};
|
115
bionic/private/bionic_asm.h
Normal file
115
bionic/private/bionic_asm.h
Normal file
@ -0,0 +1,115 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __ASSEMBLY__
|
||||
|
||||
/* https://github.com/android/ndk/issues/1422 */
|
||||
#include <features.h>
|
||||
|
||||
#include <asm/unistd.h> /* For system call numbers. */
|
||||
#define MAX_ERRNO 4095 /* For recognizing system call error returns. */
|
||||
|
||||
#define __bionic_asm_custom_entry(f)
|
||||
#define __bionic_asm_custom_end(f)
|
||||
#define __bionic_asm_function_type @function
|
||||
#define __bionic_asm_custom_note_gnu_section()
|
||||
|
||||
#if defined(__aarch64__)
|
||||
#include "bionic_asm_arm64.h"
|
||||
#elif defined(__arm__)
|
||||
#include "bionic_asm_arm.h"
|
||||
#elif defined(__i386__)
|
||||
#include "bionic_asm_x86.h"
|
||||
#elif defined(__riscv)
|
||||
#include "bionic_asm_riscv64.h"
|
||||
#elif defined(__x86_64__)
|
||||
#include "bionic_asm_x86_64.h"
|
||||
#endif
|
||||
|
||||
// Starts a normal assembler routine.
|
||||
#define ENTRY(__f) __ENTRY_WITH_BINDING(__f, .globl)
|
||||
|
||||
// Starts an assembler routine with hidden visibility.
|
||||
#define ENTRY_PRIVATE(__f) \
|
||||
__ENTRY_WITH_BINDING(__f, .globl); \
|
||||
.hidden __f;
|
||||
|
||||
// Starts an assembler routine that's weak so native bridges can override it.
|
||||
#define ENTRY_WEAK_FOR_NATIVE_BRIDGE(__f) __ENTRY_WITH_BINDING(__f, .weak)
|
||||
|
||||
// Starts an assembler routine with hidden visibility and no DWARF information.
|
||||
// Only used for internal functions passed via sa_restorer.
|
||||
// TODO: can't we just delete all those and let the kernel do its thing?
|
||||
#define ENTRY_NO_DWARF_PRIVATE(__f) \
|
||||
__ENTRY_NO_DWARF(__f, .globl); \
|
||||
.hidden __f;
|
||||
|
||||
// (Implementation detail.)
|
||||
#define __ENTRY_NO_DWARF(__f, __binding) \
|
||||
.text; \
|
||||
__binding __f; \
|
||||
.balign __bionic_asm_align; \
|
||||
.type __f, __bionic_asm_function_type; \
|
||||
__f: \
|
||||
__bionic_asm_custom_entry(__f);
|
||||
|
||||
// (Implementation detail.)
|
||||
#define __ENTRY_WITH_BINDING(__f, __binding) \
|
||||
__ENTRY_NO_DWARF(__f, __binding); \
|
||||
.cfi_startproc;
|
||||
|
||||
// Ends a normal assembler routine.
|
||||
#define END(__f) \
|
||||
.cfi_endproc; \
|
||||
END_NO_DWARF(__f)
|
||||
|
||||
// Ends an assembler routine with no DWARF information.
|
||||
// Only used for internal functions passed via sa_restorer.
|
||||
// TODO: can't we just delete all those and let the kernel do its thing?
|
||||
#define END_NO_DWARF(__f) \
|
||||
.size __f, .- __f; \
|
||||
__bionic_asm_custom_end(__f)
|
||||
|
||||
// Creates an alias `alias` for the symbol `original`.
|
||||
#define ALIAS_SYMBOL(alias, original) \
|
||||
.globl alias; \
|
||||
.equ alias, original
|
||||
|
||||
// Creates an alias `alias` for the symbol `original` that's weak so it can be
|
||||
// separately overridden by native bridges.
|
||||
#define ALIAS_SYMBOL_WEAK_FOR_NATIVE_BRIDGE(alias, original) \
|
||||
.weak alias; \
|
||||
.equ alias, original
|
||||
|
||||
// Adds a GNU property ELF note. Important on arm64 to declare PAC/BTI support.
|
||||
#define NOTE_GNU_PROPERTY() __bionic_asm_custom_note_gnu_section()
|
||||
|
||||
// Gives local labels a more convenient and readable syntax.
|
||||
#define L(__label) .L##__label
|
48
bionic/private/bionic_asm_arm.h
Normal file
48
bionic/private/bionic_asm_arm.h
Normal file
@ -0,0 +1,48 @@
|
||||
/* $OpenBSD: asm.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
|
||||
/* $NetBSD: asm.h,v 1.4 2001/07/16 05:43:32 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* William Jolitz.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)asm.h 5.5 (Berkeley) 5/7/91
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __bionic_asm_align 0
|
||||
|
||||
#undef __bionic_asm_custom_entry
|
||||
#undef __bionic_asm_custom_end
|
||||
#define __bionic_asm_custom_entry(f) .fnstart
|
||||
#define __bionic_asm_custom_end(f) .fnend
|
||||
|
||||
#undef __bionic_asm_function_type
|
||||
#define __bionic_asm_function_type #function
|
79
bionic/private/bionic_asm_arm64.h
Normal file
79
bionic/private/bionic_asm_arm64.h
Normal file
@ -0,0 +1,79 @@
|
||||
/* $OpenBSD: asm.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
|
||||
/* $NetBSD: asm.h,v 1.4 2001/07/16 05:43:32 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* William Jolitz.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)asm.h 5.5 (Berkeley) 5/7/91
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __bionic_asm_align 16
|
||||
|
||||
#undef __bionic_asm_function_type
|
||||
#define __bionic_asm_function_type %function
|
||||
|
||||
#if defined(__ARM_FEATURE_BTI_DEFAULT)
|
||||
#define __bionic_asm_aarch64_feature_bti (1 << 0)
|
||||
#undef __bionic_asm_custom_entry
|
||||
#define __bionic_asm_custom_entry(f) bti c
|
||||
#else
|
||||
#define __bionic_asm_aarch64_feature_bti 0
|
||||
#endif
|
||||
|
||||
#if defined(__ARM_FEATURE_PAC_DEFAULT)
|
||||
#define __bionic_asm_aarch64_feature_pac (1 << 1)
|
||||
#else
|
||||
#define __bionic_asm_aarch64_feature_pac 0
|
||||
#endif
|
||||
|
||||
#undef __bionic_asm_custom_note_gnu_section
|
||||
#define __bionic_asm_custom_note_gnu_section() \
|
||||
.pushsection .note.gnu.property, "a"; \
|
||||
.balign 8; \
|
||||
.long 4; \
|
||||
.long 0x10; \
|
||||
.long 0x5; /* NT_GNU_PROPERTY_TYPE_0 */ \
|
||||
.asciz "GNU"; \
|
||||
.long 0xc0000000; /* GNU_PROPERTY_AARCH64_FEATURE_1_AND */ \
|
||||
.long 4; \
|
||||
.long (__bionic_asm_aarch64_feature_pac | \
|
||||
__bionic_asm_aarch64_feature_bti); \
|
||||
.long 0; \
|
||||
.popsection;
|
||||
|
||||
#define NT_MEMTAG_LEVEL_MASK 3
|
||||
#define NT_MEMTAG_LEVEL_NONE 0
|
||||
#define NT_MEMTAG_LEVEL_ASYNC 1
|
||||
#define NT_MEMTAG_LEVEL_SYNC 2
|
||||
#define NT_MEMTAG_HEAP 4
|
||||
#define NT_MEMTAG_STACK 8
|
43
bionic/private/bionic_asm_riscv64.h
Normal file
43
bionic/private/bionic_asm_riscv64.h
Normal file
@ -0,0 +1,43 @@
|
||||
/* $OpenBSD: asm.h,v 1.1 2004/02/01 05:09:49 drahn Exp $ */
|
||||
/* $NetBSD: asm.h,v 1.4 2001/07/16 05:43:32 matt Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* William Jolitz.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* from: @(#)asm.h 5.5 (Berkeley) 5/7/91
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define __bionic_asm_align 16
|
||||
|
||||
#undef __bionic_asm_function_type
|
||||
#define __bionic_asm_function_type %function
|
51
bionic/private/bionic_asm_x86.h
Normal file
51
bionic/private/bionic_asm_x86.h
Normal file
@ -0,0 +1,51 @@
|
||||
/* $NetBSD: asm.h,v 1.40 2011/06/16 13:16:20 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* William Jolitz.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)asm.h 5.5 (Berkeley) 5/7/91
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PIC_PROLOGUE \
|
||||
pushl %ebx; \
|
||||
call 666f; \
|
||||
666: \
|
||||
popl %ebx; \
|
||||
addl $_GLOBAL_OFFSET_TABLE_+[.-666b], %ebx
|
||||
#define PIC_EPILOGUE \
|
||||
popl %ebx
|
||||
#define PIC_PLT(x) x@PLT
|
||||
#define PIC_GOT(x) x@GOT(%ebx)
|
||||
#define PIC_GOTOFF(x) x@GOTOFF(%ebx)
|
||||
|
||||
#define __bionic_asm_align 16
|
42
bionic/private/bionic_asm_x86_64.h
Normal file
42
bionic/private/bionic_asm_x86_64.h
Normal file
@ -0,0 +1,42 @@
|
||||
/* $NetBSD: asm.h,v 1.18 2013/09/12 15:36:17 joerg Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 1990 The Regents of the University of California.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to Berkeley by
|
||||
* William Jolitz.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the University nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* @(#)asm.h 5.5 (Berkeley) 5/7/91
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define PIC_PLT(x) x@PLT
|
||||
#define PIC_GOT(x) x@GOTPCREL(%rip)
|
||||
|
||||
#define __bionic_asm_align 16
|
171
bionic/private/bionic_errdefs.h
Normal file
171
bionic/private/bionic_errdefs.h
Normal file
@ -0,0 +1,171 @@
|
||||
/*
|
||||
* Copyright (C) 2023 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This header is used to define error constants and names;
|
||||
* it might be included several times.
|
||||
*/
|
||||
|
||||
#ifndef __BIONIC_ERRDEF
|
||||
#error __BIONIC_ERRDEF not defined
|
||||
#endif
|
||||
|
||||
__BIONIC_ERRDEF(0, "Success")
|
||||
__BIONIC_ERRDEF(EPERM, "Operation not permitted")
|
||||
__BIONIC_ERRDEF(ENOENT, "No such file or directory")
|
||||
__BIONIC_ERRDEF(ESRCH, "No such process")
|
||||
__BIONIC_ERRDEF(EINTR, "Interrupted system call")
|
||||
__BIONIC_ERRDEF(EIO, "I/O error")
|
||||
__BIONIC_ERRDEF(ENXIO, "No such device or address")
|
||||
__BIONIC_ERRDEF(E2BIG, "Argument list too long")
|
||||
__BIONIC_ERRDEF(ENOEXEC, "Exec format error")
|
||||
__BIONIC_ERRDEF(EBADF, "Bad file descriptor")
|
||||
__BIONIC_ERRDEF(ECHILD, "No child processes")
|
||||
__BIONIC_ERRDEF(EAGAIN, "Try again")
|
||||
__BIONIC_ERRDEF(ENOMEM, "Out of memory")
|
||||
__BIONIC_ERRDEF(EACCES, "Permission denied")
|
||||
__BIONIC_ERRDEF(EFAULT, "Bad address")
|
||||
__BIONIC_ERRDEF(ENOTBLK, "Block device required")
|
||||
__BIONIC_ERRDEF(EBUSY, "Device or resource busy")
|
||||
__BIONIC_ERRDEF(EEXIST, "File exists")
|
||||
__BIONIC_ERRDEF(EXDEV, "Cross-device link")
|
||||
__BIONIC_ERRDEF(ENODEV, "No such device")
|
||||
__BIONIC_ERRDEF(ENOTDIR, "Not a directory")
|
||||
__BIONIC_ERRDEF(EISDIR, "Is a directory")
|
||||
__BIONIC_ERRDEF(EINVAL, "Invalid argument")
|
||||
__BIONIC_ERRDEF(ENFILE, "File table overflow")
|
||||
__BIONIC_ERRDEF(EMFILE, "Too many open files")
|
||||
__BIONIC_ERRDEF(ENOTTY, "Inappropriate ioctl for device")
|
||||
__BIONIC_ERRDEF(ETXTBSY, "Text file busy")
|
||||
__BIONIC_ERRDEF(EFBIG, "File too large")
|
||||
__BIONIC_ERRDEF(ENOSPC, "No space left on device")
|
||||
__BIONIC_ERRDEF(ESPIPE, "Illegal seek")
|
||||
__BIONIC_ERRDEF(EROFS, "Read-only file system")
|
||||
__BIONIC_ERRDEF(EMLINK, "Too many links")
|
||||
__BIONIC_ERRDEF(EPIPE, "Broken pipe")
|
||||
__BIONIC_ERRDEF(EDOM, "Math argument out of domain of func")
|
||||
__BIONIC_ERRDEF(ERANGE, "Math result not representable")
|
||||
__BIONIC_ERRDEF(EDEADLK, "Resource deadlock would occur")
|
||||
__BIONIC_ERRDEF(ENAMETOOLONG, "File name too long")
|
||||
__BIONIC_ERRDEF(ENOLCK, "No record locks available")
|
||||
__BIONIC_ERRDEF(ENOSYS, "Function not implemented")
|
||||
__BIONIC_ERRDEF(ENOTEMPTY, "Directory not empty")
|
||||
__BIONIC_ERRDEF(ELOOP, "Too many symbolic links encountered")
|
||||
__BIONIC_ERRDEF(ENOMSG, "No message of desired type")
|
||||
__BIONIC_ERRDEF(EIDRM, "Identifier removed")
|
||||
__BIONIC_ERRDEF(ECHRNG, "Channel number out of range")
|
||||
__BIONIC_ERRDEF(EL2NSYNC, "Level 2 not synchronized")
|
||||
__BIONIC_ERRDEF(EL3HLT, "Level 3 halted")
|
||||
__BIONIC_ERRDEF(EL3RST, "Level 3 reset")
|
||||
__BIONIC_ERRDEF(ELNRNG, "Link number out of range")
|
||||
__BIONIC_ERRDEF(EUNATCH, "Protocol driver not attached")
|
||||
__BIONIC_ERRDEF(ENOCSI, "No CSI structure available")
|
||||
__BIONIC_ERRDEF(EL2HLT, "Level 2 halted")
|
||||
__BIONIC_ERRDEF(EBADE, "Invalid exchange")
|
||||
__BIONIC_ERRDEF(EBADR, "Invalid request descriptor")
|
||||
__BIONIC_ERRDEF(EXFULL, "Exchange full")
|
||||
__BIONIC_ERRDEF(ENOANO, "No anode")
|
||||
__BIONIC_ERRDEF(EBADRQC, "Invalid request code")
|
||||
__BIONIC_ERRDEF(EBADSLT, "Invalid slot")
|
||||
__BIONIC_ERRDEF(EBFONT, "Bad font file format")
|
||||
__BIONIC_ERRDEF(ENOSTR, "Device not a stream")
|
||||
__BIONIC_ERRDEF(ENODATA, "No data available")
|
||||
__BIONIC_ERRDEF(ETIME, "Timer expired")
|
||||
__BIONIC_ERRDEF(ENOSR, "Out of streams resources")
|
||||
__BIONIC_ERRDEF(ENONET, "Machine is not on the network")
|
||||
__BIONIC_ERRDEF(ENOPKG, "Package not installed")
|
||||
__BIONIC_ERRDEF(EREMOTE, "Object is remote")
|
||||
__BIONIC_ERRDEF(ENOLINK, "Link has been severed")
|
||||
__BIONIC_ERRDEF(EADV, "Advertise error")
|
||||
__BIONIC_ERRDEF(ESRMNT, "Srmount error")
|
||||
__BIONIC_ERRDEF(ECOMM, "Communication error on send")
|
||||
__BIONIC_ERRDEF(EPROTO, "Protocol error")
|
||||
__BIONIC_ERRDEF(EMULTIHOP, "Multihop attempted")
|
||||
__BIONIC_ERRDEF(EDOTDOT, "RFS specific error")
|
||||
__BIONIC_ERRDEF(EBADMSG, "Not a data message")
|
||||
__BIONIC_ERRDEF(EOVERFLOW, "Value too large for defined data type")
|
||||
__BIONIC_ERRDEF(ENOTUNIQ, "Name not unique on network")
|
||||
__BIONIC_ERRDEF(EBADFD, "File descriptor in bad state")
|
||||
__BIONIC_ERRDEF(EREMCHG, "Remote address changed")
|
||||
__BIONIC_ERRDEF(ELIBACC, "Can not access a needed shared library")
|
||||
__BIONIC_ERRDEF(ELIBBAD, "Accessing a corrupted shared library")
|
||||
__BIONIC_ERRDEF(ELIBSCN, ".lib section in a.out corrupted")
|
||||
__BIONIC_ERRDEF(ELIBMAX, "Attempting to link in too many shared libraries")
|
||||
__BIONIC_ERRDEF(ELIBEXEC, "Cannot exec a shared library directly")
|
||||
__BIONIC_ERRDEF(EILSEQ, "Illegal byte sequence")
|
||||
__BIONIC_ERRDEF(ERESTART, "Interrupted system call should be restarted")
|
||||
__BIONIC_ERRDEF(ESTRPIPE, "Streams pipe error")
|
||||
__BIONIC_ERRDEF(EUSERS, "Too many users")
|
||||
__BIONIC_ERRDEF(ENOTSOCK, "Socket operation on non-socket")
|
||||
__BIONIC_ERRDEF(EDESTADDRREQ, "Destination address required")
|
||||
__BIONIC_ERRDEF(EMSGSIZE, "Message too long")
|
||||
__BIONIC_ERRDEF(EPROTOTYPE, "Protocol wrong type for socket")
|
||||
__BIONIC_ERRDEF(ENOPROTOOPT, "Protocol not available")
|
||||
__BIONIC_ERRDEF(EPROTONOSUPPORT, "Protocol not supported")
|
||||
__BIONIC_ERRDEF(ESOCKTNOSUPPORT, "Socket type not supported")
|
||||
__BIONIC_ERRDEF(EOPNOTSUPP, "Operation not supported on transport endpoint")
|
||||
__BIONIC_ERRDEF(EPFNOSUPPORT, "Protocol family not supported")
|
||||
__BIONIC_ERRDEF(EAFNOSUPPORT, "Address family not supported by protocol")
|
||||
__BIONIC_ERRDEF(EADDRINUSE, "Address already in use")
|
||||
__BIONIC_ERRDEF(EADDRNOTAVAIL, "Cannot assign requested address")
|
||||
__BIONIC_ERRDEF(ENETDOWN, "Network is down")
|
||||
__BIONIC_ERRDEF(ENETUNREACH, "Network is unreachable")
|
||||
__BIONIC_ERRDEF(ENETRESET, "Network dropped connection because of reset")
|
||||
__BIONIC_ERRDEF(ECONNABORTED, "Software caused connection abort")
|
||||
__BIONIC_ERRDEF(ECONNRESET, "Connection reset by peer")
|
||||
__BIONIC_ERRDEF(ENOBUFS, "No buffer space available")
|
||||
__BIONIC_ERRDEF(EISCONN, "Transport endpoint is already connected")
|
||||
__BIONIC_ERRDEF(ENOTCONN, "Transport endpoint is not connected")
|
||||
__BIONIC_ERRDEF(ESHUTDOWN, "Cannot send after transport endpoint shutdown")
|
||||
__BIONIC_ERRDEF(ETOOMANYREFS, "Too many references: cannot splice")
|
||||
__BIONIC_ERRDEF(ETIMEDOUT, "Connection timed out")
|
||||
__BIONIC_ERRDEF(ECONNREFUSED, "Connection refused")
|
||||
__BIONIC_ERRDEF(EHOSTDOWN, "Host is down")
|
||||
__BIONIC_ERRDEF(EHOSTUNREACH, "No route to host")
|
||||
__BIONIC_ERRDEF(EALREADY, "Operation already in progress")
|
||||
__BIONIC_ERRDEF(EINPROGRESS, "Operation now in progress")
|
||||
__BIONIC_ERRDEF(ESTALE, "Stale NFS file handle")
|
||||
__BIONIC_ERRDEF(EUCLEAN, "Structure needs cleaning")
|
||||
__BIONIC_ERRDEF(ENOTNAM, "Not a XENIX named type file")
|
||||
__BIONIC_ERRDEF(ENAVAIL, "No XENIX semaphores available")
|
||||
__BIONIC_ERRDEF(EISNAM, "Is a named type file")
|
||||
__BIONIC_ERRDEF(EREMOTEIO, "Remote I/O error")
|
||||
__BIONIC_ERRDEF(EDQUOT, "Quota exceeded")
|
||||
__BIONIC_ERRDEF(ENOMEDIUM, "No medium found")
|
||||
__BIONIC_ERRDEF(EMEDIUMTYPE, "Wrong medium type")
|
||||
__BIONIC_ERRDEF(ECANCELED, "Operation Canceled")
|
||||
__BIONIC_ERRDEF(ENOKEY, "Required key not available")
|
||||
__BIONIC_ERRDEF(EKEYEXPIRED, "Key has expired")
|
||||
__BIONIC_ERRDEF(EKEYREVOKED, "Key has been revoked")
|
||||
__BIONIC_ERRDEF(EKEYREJECTED, "Key was rejected by service")
|
||||
__BIONIC_ERRDEF(EOWNERDEAD, "Owner died")
|
||||
__BIONIC_ERRDEF(ENOTRECOVERABLE, "State not recoverable")
|
||||
__BIONIC_ERRDEF(ERFKILL, "Operation not possible due to RF-kill")
|
||||
__BIONIC_ERRDEF(EHWPOISON, "Memory page has hardware error")
|
||||
|
||||
#undef __BIONIC_ERRDEF
|
100
bionic/strerror.cpp
Normal file
100
bionic/strerror.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/*
|
||||
* Copyright (C) 2012 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
// -std=gnu++XX automatically defines _GNU_SOURCE, which then means that <string.h>
|
||||
// gives us the GNU variant, which is not what we're defining here.
|
||||
#undef _GNU_SOURCE
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "private/ErrnoRestorer.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
|
||||
// The arraysize(arr) macro returns the # of elements in an array arr.
|
||||
// The expression is a compile-time constant, and therefore can be
|
||||
// used in defining new arrays, for example. If you use arraysize on
|
||||
// a pointer by mistake, you will get a compile-time error.
|
||||
//
|
||||
// One caveat is that arraysize() doesn't accept any array of an
|
||||
// anonymous type or a type defined inside a function.
|
||||
//
|
||||
// This template function declaration is used in defining arraysize.
|
||||
// Note that the function doesn't need an implementation, as we only
|
||||
// use its type.
|
||||
template <typename T, size_t N>
|
||||
char (&ArraySizeHelper(T (&array)[N]))[N]; // NOLINT(readability/casting)
|
||||
|
||||
#define arraysize(array) (sizeof(ArraySizeHelper(array)))
|
||||
|
||||
static const char* __sys_error_descriptions[] = {
|
||||
#define __BIONIC_ERRDEF(error_number, error_description) [error_number] = error_description,
|
||||
#include "private/bionic_errdefs.h"
|
||||
};
|
||||
|
||||
static inline const char* __strerror_lookup(int error_number) {
|
||||
if (error_number < 0 || error_number >= static_cast<int>(arraysize(__sys_error_descriptions))) {
|
||||
return nullptr;
|
||||
}
|
||||
return __sys_error_descriptions[error_number];
|
||||
}
|
||||
|
||||
int strerror_r(int error_number, char* buf, size_t buf_len) {
|
||||
ErrnoRestorer errno_restorer;
|
||||
size_t length;
|
||||
|
||||
const char* error_name = __strerror_lookup(error_number);
|
||||
if (error_name != nullptr) {
|
||||
length = strlcpy(buf, error_name, buf_len);
|
||||
} else {
|
||||
length = snprintf(buf, buf_len, "Unknown error %d", error_number);
|
||||
}
|
||||
if (length >= buf_len) {
|
||||
return ERANGE;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
char* strerror(int error_number) {
|
||||
static char strerror_buf[NL_TEXTMAX];
|
||||
|
||||
// Just return the original constant in the easy cases.
|
||||
char* result = const_cast<char*>(__strerror_lookup(error_number));
|
||||
if (result != nullptr) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = strerror_buf;
|
||||
strerror_r(error_number, result, sizeof(strerror_buf));
|
||||
return result;
|
||||
}
|
51
bionic/syscall-arm.S
Normal file
51
bionic/syscall-arm.S
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "private/bionic_asm.h"
|
||||
|
||||
ENTRY(syscall)
|
||||
mov ip, sp
|
||||
stmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 16
|
||||
.cfi_rel_offset r4, 0
|
||||
.cfi_rel_offset r5, 4
|
||||
.cfi_rel_offset r6, 8
|
||||
.cfi_rel_offset r7, 12
|
||||
mov r7, r0
|
||||
mov r0, r1
|
||||
mov r1, r2
|
||||
mov r2, r3
|
||||
ldmfd ip, {r3, r4, r5, r6}
|
||||
swi #0
|
||||
ldmfd sp!, {r4, r5, r6, r7}
|
||||
.cfi_def_cfa_offset 0
|
||||
cmn r0, #(MAX_ERRNO + 1)
|
||||
bxls lr
|
||||
neg r0, r0
|
||||
b __set_errno_internal
|
||||
END(syscall)
|
51
bionic/syscall-arm64.S
Normal file
51
bionic/syscall-arm64.S
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "private/bionic_asm.h"
|
||||
|
||||
ENTRY(syscall)
|
||||
/* Move syscall No. from x0 to x8 */
|
||||
mov x8, x0
|
||||
/* Move syscall parameters from x1 thru x6 to x0 thru x5 */
|
||||
mov x0, x1
|
||||
mov x1, x2
|
||||
mov x2, x3
|
||||
mov x3, x4
|
||||
mov x4, x5
|
||||
mov x5, x6
|
||||
svc #0
|
||||
|
||||
/* check if syscall returned successfully */
|
||||
cmn x0, #(MAX_ERRNO + 1)
|
||||
cneg x0, x0, hi
|
||||
b.hi __set_errno_internal
|
||||
|
||||
ret
|
||||
END(syscall)
|
||||
|
||||
NOTE_GNU_PROPERTY()
|
66
bionic/syscall-x86.S
Normal file
66
bionic/syscall-x86.S
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Generic syscall call.
|
||||
* Upon entry:
|
||||
* %eax: system call number - caller save
|
||||
* %ebx: arg0 to system call - callee save
|
||||
* %ecx: arg1 - caller save
|
||||
* %edx: arg2 - caller save
|
||||
* %esi: arg3 - callee save
|
||||
* %edi: arg4 - callee save
|
||||
* %ebp: arg5 - callee save
|
||||
*/
|
||||
|
||||
#include "private/bionic_asm.h"
|
||||
|
||||
ENTRY(syscall)
|
||||
# Push the callee save registers.
|
||||
push %ebx
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset ebx, 0
|
||||
push %esi
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset esi, 0
|
||||
push %edi
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset edi, 0
|
||||
push %ebp
|
||||
.cfi_adjust_cfa_offset 4
|
||||
.cfi_rel_offset ebp, 0
|
||||
|
||||
# Load all the arguments from the calling frame.
|
||||
# (Not all will be valid, depending on the syscall.)
|
||||
mov 20(%esp),%eax
|
||||
mov 24(%esp),%ebx
|
||||
mov 28(%esp),%ecx
|
||||
mov 32(%esp),%edx
|
||||
mov 36(%esp),%esi
|
||||
mov 40(%esp),%edi
|
||||
mov 44(%esp),%ebp
|
||||
|
||||
# Make the system call.
|
||||
int $0x80
|
||||
|
||||
# Error?
|
||||
cmpl $-MAX_ERRNO, %eax
|
||||
jb 1f
|
||||
# Yes, so set errno.
|
||||
negl %eax
|
||||
pushl %eax
|
||||
call __set_errno_internal
|
||||
addl $4, %esp
|
||||
1:
|
||||
# Restore the callee save registers.
|
||||
pop %ebp
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebp
|
||||
pop %edi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore edi
|
||||
pop %esi
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore esi
|
||||
pop %ebx
|
||||
.cfi_adjust_cfa_offset -4
|
||||
.cfi_restore ebx
|
||||
ret
|
||||
END(syscall)
|
63
bionic/syscall-x86_64.S
Normal file
63
bionic/syscall-x86_64.S
Normal file
@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (C) 2013 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Generic syscall call.
|
||||
* Upon entry:
|
||||
* %rax: system call number
|
||||
* %rdi: arg0 to system call
|
||||
* %rsi: arg1
|
||||
* %rdx: arg2
|
||||
* %rcx: arg3 - syscall expects it at %r10
|
||||
* %r8: arg4
|
||||
* %r9: arg5
|
||||
*/
|
||||
|
||||
#include "private/bionic_asm.h"
|
||||
|
||||
ENTRY(syscall)
|
||||
# All arguments are passed via registers.
|
||||
# (Not all will be valid, depending on the syscall.)
|
||||
mov %edi, %eax
|
||||
mov %rsi, %rdi
|
||||
mov %rdx, %rsi
|
||||
mov %rcx, %rdx
|
||||
mov %r8, %r10
|
||||
mov %r9, %r8
|
||||
mov 8(%rsp), %r9
|
||||
|
||||
# Make the system call.
|
||||
syscall
|
||||
cmpq $-MAX_ERRNO, %rax
|
||||
jb 1f
|
||||
negl %eax
|
||||
movl %eax, %edi
|
||||
call __set_errno_internal
|
||||
1:
|
||||
ret
|
||||
END(syscall)
|
6291
dlmalloc/malloc.c
Normal file
6291
dlmalloc/malloc.c
Normal file
File diff suppressed because it is too large
Load Diff
637
dlmalloc/malloc.h
Normal file
637
dlmalloc/malloc.h
Normal file
@ -0,0 +1,637 @@
|
||||
/*
|
||||
Copyright 2023 Doug Lea
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
Default header file for malloc-2.8.x
|
||||
Re-licensed 25 Sep 2023 with MIT-0 replacing obsolete CC0
|
||||
See https://opensource.org/license/mit-0/
|
||||
|
||||
This header is for ANSI C/C++ only. You can set any of
|
||||
the following #defines before including:
|
||||
|
||||
* If USE_DL_PREFIX is defined, it is assumed that malloc.c
|
||||
was also compiled with this option, so all routines
|
||||
have names starting with "dl".
|
||||
|
||||
* If HAVE_USR_INCLUDE_MALLOC_H is defined, it is assumed that this
|
||||
file will be #included AFTER <malloc.h>. This is needed only if
|
||||
your system defines a struct mallinfo that is incompatible with the
|
||||
standard one declared here. Otherwise, you can include this file
|
||||
INSTEAD of your system system <malloc.h>. At least on ANSI, all
|
||||
declarations should be compatible with system versions
|
||||
|
||||
* If MSPACES is defined, declarations for mspace versions are included.
|
||||
*/
|
||||
|
||||
#ifndef MALLOC_280_H
|
||||
#define MALLOC_280_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stddef.h> /* for size_t */
|
||||
|
||||
#ifndef ONLY_MSPACES
|
||||
#define ONLY_MSPACES 0 /* define to a value */
|
||||
#elif ONLY_MSPACES != 0
|
||||
#define ONLY_MSPACES 1
|
||||
#endif /* ONLY_MSPACES */
|
||||
#ifndef NO_MALLINFO
|
||||
#define NO_MALLINFO 0
|
||||
#endif /* NO_MALLINFO */
|
||||
|
||||
#ifndef MSPACES
|
||||
#if ONLY_MSPACES
|
||||
#define MSPACES 1
|
||||
#else /* ONLY_MSPACES */
|
||||
#define MSPACES 0
|
||||
#endif /* ONLY_MSPACES */
|
||||
#endif /* MSPACES */
|
||||
|
||||
#if !ONLY_MSPACES
|
||||
|
||||
#ifndef USE_DL_PREFIX
|
||||
#define dlcalloc calloc
|
||||
#define dlfree free
|
||||
#define dlmalloc malloc
|
||||
#define dlmemalign memalign
|
||||
#define dlposix_memalign posix_memalign
|
||||
#define dlrealloc realloc
|
||||
#define dlvalloc valloc
|
||||
#define dlpvalloc pvalloc
|
||||
#define dlmallinfo mallinfo
|
||||
#define dlmallopt mallopt
|
||||
#define dlmalloc_trim malloc_trim
|
||||
#define dlmalloc_stats malloc_stats
|
||||
#define dlmalloc_usable_size malloc_usable_size
|
||||
#define dlmalloc_footprint malloc_footprint
|
||||
#define dlmalloc_max_footprint malloc_max_footprint
|
||||
#define dlmalloc_footprint_limit malloc_footprint_limit
|
||||
#define dlmalloc_set_footprint_limit malloc_set_footprint_limit
|
||||
#define dlmalloc_inspect_all malloc_inspect_all
|
||||
#define dlindependent_calloc independent_calloc
|
||||
#define dlindependent_comalloc independent_comalloc
|
||||
#define dlbulk_free bulk_free
|
||||
#endif /* USE_DL_PREFIX */
|
||||
|
||||
#if !NO_MALLINFO
|
||||
#ifndef HAVE_USR_INCLUDE_MALLOC_H
|
||||
#ifndef _MALLOC_H
|
||||
#ifndef MALLINFO_FIELD_TYPE
|
||||
#define MALLINFO_FIELD_TYPE size_t
|
||||
#endif /* MALLINFO_FIELD_TYPE */
|
||||
#ifndef STRUCT_MALLINFO_DECLARED
|
||||
#define STRUCT_MALLINFO_DECLARED 1
|
||||
struct mallinfo {
|
||||
MALLINFO_FIELD_TYPE arena; /* non-mmapped space allocated from system */
|
||||
MALLINFO_FIELD_TYPE ordblks; /* number of free chunks */
|
||||
MALLINFO_FIELD_TYPE smblks; /* always 0 */
|
||||
MALLINFO_FIELD_TYPE hblks; /* always 0 */
|
||||
MALLINFO_FIELD_TYPE hblkhd; /* space in mmapped regions */
|
||||
MALLINFO_FIELD_TYPE usmblks; /* maximum total allocated space */
|
||||
MALLINFO_FIELD_TYPE fsmblks; /* always 0 */
|
||||
MALLINFO_FIELD_TYPE uordblks; /* total allocated space */
|
||||
MALLINFO_FIELD_TYPE fordblks; /* total free space */
|
||||
MALLINFO_FIELD_TYPE keepcost; /* releasable (via malloc_trim) space */
|
||||
};
|
||||
#endif /* STRUCT_MALLINFO_DECLARED */
|
||||
#endif /* _MALLOC_H */
|
||||
#endif /* HAVE_USR_INCLUDE_MALLOC_H */
|
||||
#endif /* !NO_MALLINFO */
|
||||
|
||||
/*
|
||||
malloc(size_t n)
|
||||
Returns a pointer to a newly allocated chunk of at least n bytes, or
|
||||
null if no space is available, in which case errno is set to ENOMEM
|
||||
on ANSI C systems.
|
||||
|
||||
If n is zero, malloc returns a minimum-sized chunk. (The minimum
|
||||
size is 16 bytes on most 32bit systems, and 32 bytes on 64bit
|
||||
systems.) Note that size_t is an unsigned type, so calls with
|
||||
arguments that would be negative if signed are interpreted as
|
||||
requests for huge amounts of space, which will often fail. The
|
||||
maximum supported value of n differs across systems, but is in all
|
||||
cases less than the maximum representable value of a size_t.
|
||||
*/
|
||||
void* dlmalloc(size_t);
|
||||
|
||||
/*
|
||||
free(void* p)
|
||||
Releases the chunk of memory pointed to by p, that had been previously
|
||||
allocated using malloc or a related routine such as realloc.
|
||||
It has no effect if p is null. If p was not malloced or already
|
||||
freed, free(p) will by default cuase the current program to abort.
|
||||
*/
|
||||
void dlfree(void*);
|
||||
|
||||
/*
|
||||
calloc(size_t n_elements, size_t element_size);
|
||||
Returns a pointer to n_elements * element_size bytes, with all locations
|
||||
set to zero.
|
||||
*/
|
||||
void* dlcalloc(size_t, size_t);
|
||||
|
||||
/*
|
||||
realloc(void* p, size_t n)
|
||||
Returns a pointer to a chunk of size n that contains the same data
|
||||
as does chunk p up to the minimum of (n, p's size) bytes, or null
|
||||
if no space is available.
|
||||
|
||||
The returned pointer may or may not be the same as p. The algorithm
|
||||
prefers extending p in most cases when possible, otherwise it
|
||||
employs the equivalent of a malloc-copy-free sequence.
|
||||
|
||||
If p is null, realloc is equivalent to malloc.
|
||||
|
||||
If space is not available, realloc returns null, errno is set (if on
|
||||
ANSI) and p is NOT freed.
|
||||
|
||||
if n is for fewer bytes than already held by p, the newly unused
|
||||
space is lopped off and freed if possible. realloc with a size
|
||||
argument of zero (re)allocates a minimum-sized chunk.
|
||||
|
||||
The old unix realloc convention of allowing the last-free'd chunk
|
||||
to be used as an argument to realloc is not supported.
|
||||
*/
|
||||
void* dlrealloc(void*, size_t);
|
||||
|
||||
/*
|
||||
realloc_in_place(void* p, size_t n)
|
||||
Resizes the space allocated for p to size n, only if this can be
|
||||
done without moving p (i.e., only if there is adjacent space
|
||||
available if n is greater than p's current allocated size, or n is
|
||||
less than or equal to p's size). This may be used instead of plain
|
||||
realloc if an alternative allocation strategy is needed upon failure
|
||||
to expand space; for example, reallocation of a buffer that must be
|
||||
memory-aligned or cleared. You can use realloc_in_place to trigger
|
||||
these alternatives only when needed.
|
||||
|
||||
Returns p if successful; otherwise null.
|
||||
*/
|
||||
void* dlrealloc_in_place(void*, size_t);
|
||||
|
||||
/*
|
||||
memalign(size_t alignment, size_t n);
|
||||
Returns a pointer to a newly allocated chunk of n bytes, aligned
|
||||
in accord with the alignment argument.
|
||||
|
||||
The alignment argument should be a power of two. If the argument is
|
||||
not a power of two, the nearest greater power is used.
|
||||
8-byte alignment is guaranteed by normal malloc calls, so don't
|
||||
bother calling memalign with an argument of 8 or less.
|
||||
|
||||
Overreliance on memalign is a sure way to fragment space.
|
||||
*/
|
||||
void* dlmemalign(size_t, size_t);
|
||||
|
||||
/*
|
||||
int posix_memalign(void** pp, size_t alignment, size_t n);
|
||||
Allocates a chunk of n bytes, aligned in accord with the alignment
|
||||
argument. Differs from memalign only in that it (1) assigns the
|
||||
allocated memory to *pp rather than returning it, (2) fails and
|
||||
returns EINVAL if the alignment is not a power of two (3) fails and
|
||||
returns ENOMEM if memory cannot be allocated.
|
||||
*/
|
||||
int dlposix_memalign(void**, size_t, size_t);
|
||||
|
||||
/*
|
||||
valloc(size_t n);
|
||||
Equivalent to memalign(pagesize, n), where pagesize is the page
|
||||
size of the system. If the pagesize is unknown, 4096 is used.
|
||||
*/
|
||||
void* dlvalloc(size_t);
|
||||
|
||||
/*
|
||||
mallopt(int parameter_number, int parameter_value)
|
||||
Sets tunable parameters The format is to provide a
|
||||
(parameter-number, parameter-value) pair. mallopt then sets the
|
||||
corresponding parameter to the argument value if it can (i.e., so
|
||||
long as the value is meaningful), and returns 1 if successful else
|
||||
0. SVID/XPG/ANSI defines four standard param numbers for mallopt,
|
||||
normally defined in malloc.h. None of these are use in this malloc,
|
||||
so setting them has no effect. But this malloc also supports other
|
||||
options in mallopt:
|
||||
|
||||
Symbol param # default allowed param values
|
||||
M_TRIM_THRESHOLD -1 2*1024*1024 any (-1U disables trimming)
|
||||
M_GRANULARITY -2 page size any power of 2 >= page size
|
||||
M_MMAP_THRESHOLD -3 256*1024 any (or 0 if no MMAP support)
|
||||
*/
|
||||
int dlmallopt(int, int);
|
||||
|
||||
#define M_TRIM_THRESHOLD (-1)
|
||||
#define M_GRANULARITY (-2)
|
||||
#define M_MMAP_THRESHOLD (-3)
|
||||
|
||||
|
||||
/*
|
||||
malloc_footprint();
|
||||
Returns the number of bytes obtained from the system. The total
|
||||
number of bytes allocated by malloc, realloc etc., is less than this
|
||||
value. Unlike mallinfo, this function returns only a precomputed
|
||||
result, so can be called frequently to monitor memory consumption.
|
||||
Even if locks are otherwise defined, this function does not use them,
|
||||
so results might not be up to date.
|
||||
*/
|
||||
size_t dlmalloc_footprint(void);
|
||||
|
||||
/*
|
||||
malloc_max_footprint();
|
||||
Returns the maximum number of bytes obtained from the system. This
|
||||
value will be greater than current footprint if deallocated space
|
||||
has been reclaimed by the system. The peak number of bytes allocated
|
||||
by malloc, realloc etc., is less than this value. Unlike mallinfo,
|
||||
this function returns only a precomputed result, so can be called
|
||||
frequently to monitor memory consumption. Even if locks are
|
||||
otherwise defined, this function does not use them, so results might
|
||||
not be up to date.
|
||||
*/
|
||||
size_t dlmalloc_max_footprint(void);
|
||||
|
||||
/*
|
||||
malloc_footprint_limit();
|
||||
Returns the number of bytes that the heap is allowed to obtain from
|
||||
the system, returning the last value returned by
|
||||
malloc_set_footprint_limit, or the maximum size_t value if
|
||||
never set. The returned value reflects a permission. There is no
|
||||
guarantee that this number of bytes can actually be obtained from
|
||||
the system.
|
||||
*/
|
||||
size_t dlmalloc_footprint_limit(void);
|
||||
|
||||
/*
|
||||
malloc_set_footprint_limit();
|
||||
Sets the maximum number of bytes to obtain from the system, causing
|
||||
failure returns from malloc and related functions upon attempts to
|
||||
exceed this value. The argument value may be subject to page
|
||||
rounding to an enforceable limit; this actual value is returned.
|
||||
Using an argument of the maximum possible size_t effectively
|
||||
disables checks. If the argument is less than or equal to the
|
||||
current malloc_footprint, then all future allocations that require
|
||||
additional system memory will fail. However, invocation cannot
|
||||
retroactively deallocate existing used memory.
|
||||
*/
|
||||
size_t dlmalloc_set_footprint_limit(size_t bytes);
|
||||
|
||||
/*
|
||||
malloc_inspect_all(void(*handler)(void *start,
|
||||
void *end,
|
||||
size_t used_bytes,
|
||||
void* callback_arg),
|
||||
void* arg);
|
||||
Traverses the heap and calls the given handler for each managed
|
||||
region, skipping all bytes that are (or may be) used for bookkeeping
|
||||
purposes. Traversal does not include include chunks that have been
|
||||
directly memory mapped. Each reported region begins at the start
|
||||
address, and continues up to but not including the end address. The
|
||||
first used_bytes of the region contain allocated data. If
|
||||
used_bytes is zero, the region is unallocated. The handler is
|
||||
invoked with the given callback argument. If locks are defined, they
|
||||
are held during the entire traversal. It is a bad idea to invoke
|
||||
other malloc functions from within the handler.
|
||||
|
||||
For example, to count the number of in-use chunks with size greater
|
||||
than 1000, you could write:
|
||||
static int count = 0;
|
||||
void count_chunks(void* start, void* end, size_t used, void* arg) {
|
||||
if (used >= 1000) ++count;
|
||||
}
|
||||
then:
|
||||
malloc_inspect_all(count_chunks, NULL);
|
||||
|
||||
malloc_inspect_all is compiled only if MALLOC_INSPECT_ALL is defined.
|
||||
*/
|
||||
void dlmalloc_inspect_all(void(*handler)(void*, void *, size_t, void*),
|
||||
void* arg);
|
||||
|
||||
#if !NO_MALLINFO
|
||||
/*
|
||||
mallinfo()
|
||||
Returns (by copy) a struct containing various summary statistics:
|
||||
|
||||
arena: current total non-mmapped bytes allocated from system
|
||||
ordblks: the number of free chunks
|
||||
smblks: always zero.
|
||||
hblks: current number of mmapped regions
|
||||
hblkhd: total bytes held in mmapped regions
|
||||
usmblks: the maximum total allocated space. This will be greater
|
||||
than current total if trimming has occurred.
|
||||
fsmblks: always zero
|
||||
uordblks: current total allocated space (normal or mmapped)
|
||||
fordblks: total free space
|
||||
keepcost: the maximum number of bytes that could ideally be released
|
||||
back to system via malloc_trim. ("ideally" means that
|
||||
it ignores page restrictions etc.)
|
||||
|
||||
Because these fields are ints, but internal bookkeeping may
|
||||
be kept as longs, the reported values may wrap around zero and
|
||||
thus be inaccurate.
|
||||
*/
|
||||
|
||||
struct mallinfo dlmallinfo(void);
|
||||
#endif /* NO_MALLINFO */
|
||||
|
||||
/*
|
||||
independent_calloc(size_t n_elements, size_t element_size, void* chunks[]);
|
||||
|
||||
independent_calloc is similar to calloc, but instead of returning a
|
||||
single cleared space, it returns an array of pointers to n_elements
|
||||
independent elements that can hold contents of size elem_size, each
|
||||
of which starts out cleared, and can be independently freed,
|
||||
realloc'ed etc. The elements are guaranteed to be adjacently
|
||||
allocated (this is not guaranteed to occur with multiple callocs or
|
||||
mallocs), which may also improve cache locality in some
|
||||
applications.
|
||||
|
||||
The "chunks" argument is optional (i.e., may be null, which is
|
||||
probably the most typical usage). If it is null, the returned array
|
||||
is itself dynamically allocated and should also be freed when it is
|
||||
no longer needed. Otherwise, the chunks array must be of at least
|
||||
n_elements in length. It is filled in with the pointers to the
|
||||
chunks.
|
||||
|
||||
In either case, independent_calloc returns this pointer array, or
|
||||
null if the allocation failed. If n_elements is zero and "chunks"
|
||||
is null, it returns a chunk representing an array with zero elements
|
||||
(which should be freed if not wanted).
|
||||
|
||||
Each element must be freed when it is no longer needed. This can be
|
||||
done all at once using bulk_free.
|
||||
|
||||
independent_calloc simplifies and speeds up implementations of many
|
||||
kinds of pools. It may also be useful when constructing large data
|
||||
structures that initially have a fixed number of fixed-sized nodes,
|
||||
but the number is not known at compile time, and some of the nodes
|
||||
may later need to be freed. For example:
|
||||
|
||||
struct Node { int item; struct Node* next; };
|
||||
|
||||
struct Node* build_list() {
|
||||
struct Node** pool;
|
||||
int n = read_number_of_nodes_needed();
|
||||
if (n <= 0) return 0;
|
||||
pool = (struct Node**)(independent_calloc(n, sizeof(struct Node), 0);
|
||||
if (pool == 0) die();
|
||||
// organize into a linked list...
|
||||
struct Node* first = pool[0];
|
||||
for (i = 0; i < n-1; ++i)
|
||||
pool[i]->next = pool[i+1];
|
||||
free(pool); // Can now free the array (or not, if it is needed later)
|
||||
return first;
|
||||
}
|
||||
*/
|
||||
void** dlindependent_calloc(size_t, size_t, void**);
|
||||
|
||||
/*
|
||||
independent_comalloc(size_t n_elements, size_t sizes[], void* chunks[]);
|
||||
|
||||
independent_comalloc allocates, all at once, a set of n_elements
|
||||
chunks with sizes indicated in the "sizes" array. It returns
|
||||
an array of pointers to these elements, each of which can be
|
||||
independently freed, realloc'ed etc. The elements are guaranteed to
|
||||
be adjacently allocated (this is not guaranteed to occur with
|
||||
multiple callocs or mallocs), which may also improve cache locality
|
||||
in some applications.
|
||||
|
||||
The "chunks" argument is optional (i.e., may be null). If it is null
|
||||
the returned array is itself dynamically allocated and should also
|
||||
be freed when it is no longer needed. Otherwise, the chunks array
|
||||
must be of at least n_elements in length. It is filled in with the
|
||||
pointers to the chunks.
|
||||
|
||||
In either case, independent_comalloc returns this pointer array, or
|
||||
null if the allocation failed. If n_elements is zero and chunks is
|
||||
null, it returns a chunk representing an array with zero elements
|
||||
(which should be freed if not wanted).
|
||||
|
||||
Each element must be freed when it is no longer needed. This can be
|
||||
done all at once using bulk_free.
|
||||
|
||||
independent_comallac differs from independent_calloc in that each
|
||||
element may have a different size, and also that it does not
|
||||
automatically clear elements.
|
||||
|
||||
independent_comalloc can be used to speed up allocation in cases
|
||||
where several structs or objects must always be allocated at the
|
||||
same time. For example:
|
||||
|
||||
struct Head { ... }
|
||||
struct Foot { ... }
|
||||
|
||||
void send_message(char* msg) {
|
||||
int msglen = strlen(msg);
|
||||
size_t sizes[3] = { sizeof(struct Head), msglen, sizeof(struct Foot) };
|
||||
void* chunks[3];
|
||||
if (independent_comalloc(3, sizes, chunks) == 0)
|
||||
die();
|
||||
struct Head* head = (struct Head*)(chunks[0]);
|
||||
char* body = (char*)(chunks[1]);
|
||||
struct Foot* foot = (struct Foot*)(chunks[2]);
|
||||
// ...
|
||||
}
|
||||
|
||||
In general though, independent_comalloc is worth using only for
|
||||
larger values of n_elements. For small values, you probably won't
|
||||
detect enough difference from series of malloc calls to bother.
|
||||
|
||||
Overuse of independent_comalloc can increase overall memory usage,
|
||||
since it cannot reuse existing noncontiguous small chunks that
|
||||
might be available for some of the elements.
|
||||
*/
|
||||
void** dlindependent_comalloc(size_t, size_t*, void**);
|
||||
|
||||
/*
|
||||
bulk_free(void* array[], size_t n_elements)
|
||||
Frees and clears (sets to null) each non-null pointer in the given
|
||||
array. This is likely to be faster than freeing them one-by-one.
|
||||
If footers are used, pointers that have been allocated in different
|
||||
mspaces are not freed or cleared, and the count of all such pointers
|
||||
is returned. For large arrays of pointers with poor locality, it
|
||||
may be worthwhile to sort this array before calling bulk_free.
|
||||
*/
|
||||
size_t dlbulk_free(void**, size_t n_elements);
|
||||
|
||||
/*
|
||||
pvalloc(size_t n);
|
||||
Equivalent to valloc(minimum-page-that-holds(n)), that is,
|
||||
round up n to nearest pagesize.
|
||||
*/
|
||||
void* dlpvalloc(size_t);
|
||||
|
||||
/*
|
||||
malloc_trim(size_t pad);
|
||||
|
||||
If possible, gives memory back to the system (via negative arguments
|
||||
to sbrk) if there is unused memory at the `high' end of the malloc
|
||||
pool or in unused MMAP segments. You can call this after freeing
|
||||
large blocks of memory to potentially reduce the system-level memory
|
||||
requirements of a program. However, it cannot guarantee to reduce
|
||||
memory. Under some allocation patterns, some large free blocks of
|
||||
memory will be locked between two used chunks, so they cannot be
|
||||
given back to the system.
|
||||
|
||||
The `pad' argument to malloc_trim represents the amount of free
|
||||
trailing space to leave untrimmed. If this argument is zero, only
|
||||
the minimum amount of memory to maintain internal data structures
|
||||
will be left. Non-zero arguments can be supplied to maintain enough
|
||||
trailing space to service future expected allocations without having
|
||||
to re-obtain memory from the system.
|
||||
|
||||
Malloc_trim returns 1 if it actually released any memory, else 0.
|
||||
*/
|
||||
int dlmalloc_trim(size_t);
|
||||
|
||||
/*
|
||||
malloc_stats();
|
||||
Prints on stderr the amount of space obtained from the system (both
|
||||
via sbrk and mmap), the maximum amount (which may be more than
|
||||
current if malloc_trim and/or munmap got called), and the current
|
||||
number of bytes allocated via malloc (or realloc, etc) but not yet
|
||||
freed. Note that this is the number of bytes allocated, not the
|
||||
number requested. It will be larger than the number requested
|
||||
because of alignment and bookkeeping overhead. Because it includes
|
||||
alignment wastage as being in use, this figure may be greater than
|
||||
zero even when no user-level chunks are allocated.
|
||||
|
||||
The reported current and maximum system memory can be inaccurate if
|
||||
a program makes other calls to system memory allocation functions
|
||||
(normally sbrk) outside of malloc.
|
||||
|
||||
malloc_stats prints only the most commonly interesting statistics.
|
||||
More information can be obtained by calling mallinfo.
|
||||
|
||||
malloc_stats is not compiled if NO_MALLOC_STATS is defined.
|
||||
*/
|
||||
void dlmalloc_stats(void);
|
||||
|
||||
#endif /* !ONLY_MSPACES */
|
||||
|
||||
/*
|
||||
malloc_usable_size(void* p);
|
||||
|
||||
Returns the number of bytes you can actually use in
|
||||
an allocated chunk, which may be more than you requested (although
|
||||
often not) due to alignment and minimum size constraints.
|
||||
You can use this many bytes without worrying about
|
||||
overwriting other allocated objects. This is not a particularly great
|
||||
programming practice. malloc_usable_size can be more useful in
|
||||
debugging and assertions, for example:
|
||||
|
||||
p = malloc(n);
|
||||
assert(malloc_usable_size(p) >= 256);
|
||||
*/
|
||||
size_t dlmalloc_usable_size(const void*);
|
||||
|
||||
#if MSPACES
|
||||
|
||||
/*
|
||||
mspace is an opaque type representing an independent
|
||||
region of space that supports mspace_malloc, etc.
|
||||
*/
|
||||
typedef void* mspace;
|
||||
|
||||
/*
|
||||
create_mspace creates and returns a new independent space with the
|
||||
given initial capacity, or, if 0, the default granularity size. It
|
||||
returns null if there is no system memory available to create the
|
||||
space. If argument locked is non-zero, the space uses a separate
|
||||
lock to control access. The capacity of the space will grow
|
||||
dynamically as needed to service mspace_malloc requests. You can
|
||||
control the sizes of incremental increases of this space by
|
||||
compiling with a different DEFAULT_GRANULARITY or dynamically
|
||||
setting with mallopt(M_GRANULARITY, value).
|
||||
*/
|
||||
mspace create_mspace(size_t capacity, int locked);
|
||||
|
||||
/*
|
||||
destroy_mspace destroys the given space, and attempts to return all
|
||||
of its memory back to the system, returning the total number of
|
||||
bytes freed. After destruction, the results of access to all memory
|
||||
used by the space become undefined.
|
||||
*/
|
||||
size_t destroy_mspace(mspace msp);
|
||||
|
||||
/*
|
||||
create_mspace_with_base uses the memory supplied as the initial base
|
||||
of a new mspace. Part (less than 128*sizeof(size_t) bytes) of this
|
||||
space is used for bookkeeping, so the capacity must be at least this
|
||||
large. (Otherwise 0 is returned.) When this initial space is
|
||||
exhausted, additional memory will be obtained from the system.
|
||||
Destroying this space will deallocate all additionally allocated
|
||||
space (if possible) but not the initial base.
|
||||
*/
|
||||
mspace create_mspace_with_base(void* base, size_t capacity, int locked);
|
||||
|
||||
/*
|
||||
mspace_track_large_chunks controls whether requests for large chunks
|
||||
are allocated in their own untracked mmapped regions, separate from
|
||||
others in this mspace. By default large chunks are not tracked,
|
||||
which reduces fragmentation. However, such chunks are not
|
||||
necessarily released to the system upon destroy_mspace. Enabling
|
||||
tracking by setting to true may increase fragmentation, but avoids
|
||||
leakage when relying on destroy_mspace to release all memory
|
||||
allocated using this space. The function returns the previous
|
||||
setting.
|
||||
*/
|
||||
int mspace_track_large_chunks(mspace msp, int enable);
|
||||
|
||||
#if !NO_MALLINFO
|
||||
/*
|
||||
mspace_mallinfo behaves as mallinfo, but reports properties of
|
||||
the given space.
|
||||
*/
|
||||
struct mallinfo mspace_mallinfo(mspace msp);
|
||||
#endif /* NO_MALLINFO */
|
||||
|
||||
/*
|
||||
An alias for mallopt.
|
||||
*/
|
||||
int mspace_mallopt(int, int);
|
||||
|
||||
/*
|
||||
The following operate identically to their malloc counterparts
|
||||
but operate only for the given mspace argument
|
||||
*/
|
||||
void* mspace_malloc(mspace msp, size_t bytes);
|
||||
void mspace_free(mspace msp, void* mem);
|
||||
void* mspace_calloc(mspace msp, size_t n_elements, size_t elem_size);
|
||||
void* mspace_realloc(mspace msp, void* mem, size_t newsize);
|
||||
void* mspace_realloc_in_place(mspace msp, void* mem, size_t newsize);
|
||||
void* mspace_memalign(mspace msp, size_t alignment, size_t bytes);
|
||||
void** mspace_independent_calloc(mspace msp, size_t n_elements,
|
||||
size_t elem_size, void* chunks[]);
|
||||
void** mspace_independent_comalloc(mspace msp, size_t n_elements,
|
||||
size_t sizes[], void* chunks[]);
|
||||
size_t mspace_bulk_free(mspace msp, void**, size_t n_elements);
|
||||
size_t mspace_usable_size(const void* mem);
|
||||
void mspace_malloc_stats(mspace msp);
|
||||
int mspace_trim(mspace msp, size_t pad);
|
||||
size_t mspace_footprint(mspace msp);
|
||||
size_t mspace_max_footprint(mspace msp);
|
||||
size_t mspace_footprint_limit(mspace msp);
|
||||
size_t mspace_set_footprint_limit(mspace msp, size_t bytes);
|
||||
void mspace_inspect_all(mspace msp,
|
||||
void(*handler)(void *, void *, size_t, void*),
|
||||
void* arg);
|
||||
#endif /* MSPACES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
}; /* end of extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* MALLOC_280_H */
|
5375
linux_syscall_support.h
Normal file
5375
linux_syscall_support.h
Normal file
File diff suppressed because it is too large
Load Diff
16
malloc.c
Normal file
16
malloc.c
Normal file
@ -0,0 +1,16 @@
|
||||
// Configure dlmalloc
|
||||
|
||||
#define USE_LOCKS 0
|
||||
#define INSECURE 1
|
||||
#define HAVE_MORECORE 0
|
||||
#define NO_MALLINFO 1
|
||||
#define NO_MALLOC_STATS 1
|
||||
#define LACKS_TIME_H 1
|
||||
#define malloc_getpagesize 4096
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-but-set-variable"
|
||||
|
||||
#include "dlmalloc/malloc.c"
|
||||
|
||||
#pragma clang diagnostic pop
|
361
mem.c
Normal file
361
mem.c
Normal file
@ -0,0 +1,361 @@
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
|
||||
void *memset(void *dst, int ch, size_t n) {
|
||||
uint8_t *d = dst;
|
||||
uint8_t c = ch;
|
||||
while (n--)
|
||||
(*d++) = c;
|
||||
return dst;
|
||||
}
|
||||
|
||||
void *memmove(void *dst, const void *src, size_t n) {
|
||||
return memcpy(dst, src, n);
|
||||
}
|
||||
|
||||
void *memcpy(void *dst, const void *src, size_t n) {
|
||||
uint8_t *d = dst;
|
||||
const uint8_t *s = src;
|
||||
while (n--)
|
||||
*d++ = *s++;
|
||||
return dst;
|
||||
}
|
||||
|
||||
int memcmp(const void *lhs, const void *rhs, size_t n) {
|
||||
const uint8_t *l = lhs;
|
||||
const uint8_t *r = rhs;
|
||||
while (n--) {
|
||||
if (*l != *r) {
|
||||
return *l - *r;
|
||||
} else {
|
||||
l++;
|
||||
r++;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *memchr(const void *ptr, int ch, size_t n) {
|
||||
const uint8_t *p = ptr;
|
||||
uint8_t c = ch;
|
||||
while (n--) {
|
||||
if (*p != c)
|
||||
++p;
|
||||
else
|
||||
return (void *) p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *strchr(const char *s, int ch) {
|
||||
char c = ch;
|
||||
while (*s != c)
|
||||
if (!*s++)
|
||||
return NULL;
|
||||
return (char *) s;
|
||||
}
|
||||
|
||||
int strcmp(const char *lhs, const char *rhs) {
|
||||
while (*lhs && (*lhs == *rhs)) {
|
||||
++lhs;
|
||||
++rhs;
|
||||
}
|
||||
return *(uint8_t *)lhs - *(uint8_t *)rhs;
|
||||
}
|
||||
|
||||
size_t strlen(const char *str) {
|
||||
size_t l = 0;
|
||||
while (str[l])
|
||||
++l;
|
||||
return l;
|
||||
}
|
||||
|
||||
char *strcpy(char *restrict dest, const char *restrict src) {
|
||||
char *ret = dest;
|
||||
while ((*dest++ = *src++)) {}
|
||||
return ret;
|
||||
}
|
||||
|
||||
char *strdup(const char *str) {
|
||||
size_t siz;
|
||||
char *copy;
|
||||
siz = strlen(str) + 1;
|
||||
if ((copy = malloc(siz)) == NULL)
|
||||
return NULL;
|
||||
memcpy(copy, str, siz);
|
||||
return copy;
|
||||
}
|
||||
|
||||
// memmem source: bionic/libc/upstream-openbsd/lib/libc/string/memmem.c
|
||||
|
||||
static char *twobyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) {
|
||||
uint16_t nw = n[0]<<8 | n[1], hw = h[0]<<8 | h[1];
|
||||
for (h+=2, k-=2; k; k--, hw = hw<<8 | *h++)
|
||||
if (hw == nw) return (char *)h-2;
|
||||
return hw == nw ? (char *)h-2 : 0;
|
||||
}
|
||||
|
||||
static char *threebyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) {
|
||||
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8;
|
||||
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8;
|
||||
for (h+=3, k-=3; k; k--, hw = (hw|*h++)<<8)
|
||||
if (hw == nw) return (char *)h-3;
|
||||
return hw == nw ? (char *)h-3 : 0;
|
||||
}
|
||||
|
||||
static char *fourbyte_memmem(const unsigned char *h, size_t k, const unsigned char *n) {
|
||||
uint32_t nw = n[0]<<24 | n[1]<<16 | n[2]<<8 | n[3];
|
||||
uint32_t hw = h[0]<<24 | h[1]<<16 | h[2]<<8 | h[3];
|
||||
for (h+=4, k-=4; k; k--, hw = hw<<8 | *h++)
|
||||
if (hw == nw) return (char *)h-4;
|
||||
return hw == nw ? (char *)h-4 : 0;
|
||||
}
|
||||
|
||||
#define MAX(a,b) ((a)>(b)?(a):(b))
|
||||
#define MIN(a,b) ((a)<(b)?(a):(b))
|
||||
|
||||
#define BITOP(a,b,op) \
|
||||
((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
|
||||
|
||||
/*
|
||||
* Maxime Crochemore and Dominique Perrin, Two-way string-matching,
|
||||
* Journal of the ACM, 38(3):651-675, July 1991.
|
||||
*
|
||||
*/
|
||||
static char *twoway_memmem(
|
||||
const unsigned char *h, const unsigned char *z, const unsigned char *n, size_t l) {
|
||||
size_t i, ip, jp, k, p, ms, p0, mem, mem0;
|
||||
size_t byteset[32 / sizeof(size_t)] = { 0 };
|
||||
size_t shift[256];
|
||||
|
||||
/* Computing length of needle and fill shift table */
|
||||
for (i=0; i<l; i++)
|
||||
BITOP(byteset, n[i], |=), shift[n[i]] = i+1;
|
||||
|
||||
/* Compute maximal suffix */
|
||||
ip = -1; jp = 0; k = p = 1;
|
||||
while (jp+k<l) {
|
||||
if (n[ip+k] == n[jp+k]) {
|
||||
if (k == p) {
|
||||
jp += p;
|
||||
k = 1;
|
||||
} else k++;
|
||||
} else if (n[ip+k] > n[jp+k]) {
|
||||
jp += k;
|
||||
k = 1;
|
||||
p = jp - ip;
|
||||
} else {
|
||||
ip = jp++;
|
||||
k = p = 1;
|
||||
}
|
||||
}
|
||||
ms = ip;
|
||||
p0 = p;
|
||||
|
||||
/* And with the opposite comparison */
|
||||
ip = -1; jp = 0; k = p = 1;
|
||||
while (jp+k<l) {
|
||||
if (n[ip+k] == n[jp+k]) {
|
||||
if (k == p) {
|
||||
jp += p;
|
||||
k = 1;
|
||||
} else k++;
|
||||
} else if (n[ip+k] < n[jp+k]) {
|
||||
jp += k;
|
||||
k = 1;
|
||||
p = jp - ip;
|
||||
} else {
|
||||
ip = jp++;
|
||||
k = p = 1;
|
||||
}
|
||||
}
|
||||
if (ip+1 > ms+1) ms = ip;
|
||||
else p = p0;
|
||||
|
||||
/* Periodic needle? */
|
||||
if (memcmp(n, n+p, ms+1)) {
|
||||
mem0 = 0;
|
||||
p = MAX(ms, l-ms-1) + 1;
|
||||
} else mem0 = l-p;
|
||||
mem = 0;
|
||||
|
||||
/* Search loop */
|
||||
for (;;) {
|
||||
/* If remainder of haystack is shorter than needle, done */
|
||||
if (z-h < l) return 0;
|
||||
|
||||
/* Check last byte first; advance by shift on mismatch */
|
||||
if (BITOP(byteset, h[l-1], &)) {
|
||||
k = l-shift[h[l-1]];
|
||||
if (k) {
|
||||
if (k < mem) k = mem;
|
||||
h += k;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
h += l;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Compare right half */
|
||||
for (k=MAX(ms+1,mem); k<l && n[k] == h[k]; k++);
|
||||
if (k < l) {
|
||||
h += k-ms;
|
||||
mem = 0;
|
||||
continue;
|
||||
}
|
||||
/* Compare left half */
|
||||
for (k=ms+1; k>mem && n[k-1] == h[k-1]; k--);
|
||||
if (k <= mem) return (char *)h;
|
||||
h += p;
|
||||
mem = mem0;
|
||||
}
|
||||
}
|
||||
|
||||
void *memmem(const void *h0, size_t k, const void *n0, size_t l) {
|
||||
const unsigned char *h = h0, *n = n0;
|
||||
|
||||
/* Return immediately on empty needle */
|
||||
if (!l) return (void *)h;
|
||||
|
||||
/* Return immediately when needle is longer than haystack */
|
||||
if (k<l) return 0;
|
||||
|
||||
/* Use faster algorithms for short needles */
|
||||
h = memchr(h0, *n, k);
|
||||
if (!h || l==1) return (void *)h;
|
||||
k -= h - (const unsigned char *)h0;
|
||||
if (k<l) return 0;
|
||||
if (l==2) return twobyte_memmem(h, k, n);
|
||||
if (l==3) return threebyte_memmem(h, k, n);
|
||||
if (l==4) return fourbyte_memmem(h, k, n);
|
||||
|
||||
return twoway_memmem(h, h+k, n, l);
|
||||
}
|
||||
|
||||
// Source: bionic/libc/upstream-openbsd/lib/libc/string/strlcpy.c
|
||||
size_t strlcpy(char *dst, const char *src, size_t dsize) {
|
||||
const char *osrc = src;
|
||||
size_t nleft = dsize;
|
||||
|
||||
/* Copy as many bytes as will fit. */
|
||||
if (nleft != 0) {
|
||||
while (--nleft != 0) {
|
||||
if ((*dst++ = *src++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src. */
|
||||
if (nleft == 0) {
|
||||
if (dsize != 0)
|
||||
*dst = '\0'; /* NUL-terminate dst */
|
||||
while (*src++)
|
||||
;
|
||||
}
|
||||
|
||||
return(src - osrc - 1); /* count does not include NUL */
|
||||
}
|
||||
|
||||
// Source: bionic/libc/upstream-openbsd/lib/libc/string/strtok.c
|
||||
char *strtok_r(char *s, const char *delim, char **last) {
|
||||
const char *spanp;
|
||||
int c, sc;
|
||||
char *tok;
|
||||
|
||||
if (s == NULL && (s = *last) == NULL)
|
||||
return (NULL);
|
||||
|
||||
/*
|
||||
* Skip (span) leading delimiters (s += strspn(s, delim), sort of).
|
||||
*/
|
||||
cont:
|
||||
c = *s++;
|
||||
for (spanp = delim; (sc = *spanp++) != 0;) {
|
||||
if (c == sc)
|
||||
goto cont;
|
||||
}
|
||||
|
||||
if (c == 0) { /* no non-delimiter characters */
|
||||
*last = NULL;
|
||||
return (NULL);
|
||||
}
|
||||
tok = s - 1;
|
||||
|
||||
/*
|
||||
* Scan token (scan for delimiters: s += strcspn(s, delim), sort of).
|
||||
* Note that delim must have one NUL; we stop if we see that, too.
|
||||
*/
|
||||
for (;;) {
|
||||
c = *s++;
|
||||
spanp = delim;
|
||||
do {
|
||||
if ((sc = *spanp++) == c) {
|
||||
if (c == 0)
|
||||
s = NULL;
|
||||
else
|
||||
s[-1] = '\0';
|
||||
*last = s;
|
||||
return (tok);
|
||||
}
|
||||
} while (sc != 0);
|
||||
}
|
||||
/* NOTREACHED */
|
||||
}
|
||||
|
||||
// strcasecmp source: bionic/libc/upstream-openbsd/lib/libc/string/strcasecmp.c
|
||||
|
||||
typedef unsigned char u_char;
|
||||
|
||||
/*
|
||||
* This array is designed for mapping upper and lower case letter
|
||||
* together for a case independent comparison. The mappings are
|
||||
* based upon ascii character sequences.
|
||||
*/
|
||||
static const u_char charmap[] = {
|
||||
'\000', '\001', '\002', '\003', '\004', '\005', '\006', '\007',
|
||||
'\010', '\011', '\012', '\013', '\014', '\015', '\016', '\017',
|
||||
'\020', '\021', '\022', '\023', '\024', '\025', '\026', '\027',
|
||||
'\030', '\031', '\032', '\033', '\034', '\035', '\036', '\037',
|
||||
'\040', '\041', '\042', '\043', '\044', '\045', '\046', '\047',
|
||||
'\050', '\051', '\052', '\053', '\054', '\055', '\056', '\057',
|
||||
'\060', '\061', '\062', '\063', '\064', '\065', '\066', '\067',
|
||||
'\070', '\071', '\072', '\073', '\074', '\075', '\076', '\077',
|
||||
'\100', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
|
||||
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
|
||||
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
|
||||
'\170', '\171', '\172', '\133', '\134', '\135', '\136', '\137',
|
||||
'\140', '\141', '\142', '\143', '\144', '\145', '\146', '\147',
|
||||
'\150', '\151', '\152', '\153', '\154', '\155', '\156', '\157',
|
||||
'\160', '\161', '\162', '\163', '\164', '\165', '\166', '\167',
|
||||
'\170', '\171', '\172', '\173', '\174', '\175', '\176', '\177',
|
||||
'\200', '\201', '\202', '\203', '\204', '\205', '\206', '\207',
|
||||
'\210', '\211', '\212', '\213', '\214', '\215', '\216', '\217',
|
||||
'\220', '\221', '\222', '\223', '\224', '\225', '\226', '\227',
|
||||
'\230', '\231', '\232', '\233', '\234', '\235', '\236', '\237',
|
||||
'\240', '\241', '\242', '\243', '\244', '\245', '\246', '\247',
|
||||
'\250', '\251', '\252', '\253', '\254', '\255', '\256', '\257',
|
||||
'\260', '\261', '\262', '\263', '\264', '\265', '\266', '\267',
|
||||
'\270', '\271', '\272', '\273', '\274', '\275', '\276', '\277',
|
||||
'\300', '\301', '\302', '\303', '\304', '\305', '\306', '\307',
|
||||
'\310', '\311', '\312', '\313', '\314', '\315', '\316', '\317',
|
||||
'\320', '\321', '\322', '\323', '\324', '\325', '\326', '\327',
|
||||
'\330', '\331', '\332', '\333', '\334', '\335', '\336', '\337',
|
||||
'\340', '\341', '\342', '\343', '\344', '\345', '\346', '\347',
|
||||
'\350', '\351', '\352', '\353', '\354', '\355', '\356', '\357',
|
||||
'\360', '\361', '\362', '\363', '\364', '\365', '\366', '\367',
|
||||
'\370', '\371', '\372', '\373', '\374', '\375', '\376', '\377',
|
||||
};
|
||||
|
||||
int strcasecmp(const char *s1, const char *s2) {
|
||||
const u_char *cm = charmap;
|
||||
const u_char *us1 = (const u_char *)s1;
|
||||
const u_char *us2 = (const u_char *)s2;
|
||||
|
||||
while (cm[*us1] == cm[*us2++])
|
||||
if (*us1++ == '\0')
|
||||
return (0);
|
||||
return (cm[*us1] - cm[*--us2]);
|
||||
}
|
201
misc.c
Normal file
201
misc.c
Normal file
@ -0,0 +1,201 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <libgen.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
// Source: bionic/libc/upstream-openbsd/lib/libc/stdlib/getenv.c
|
||||
static char *__findenv(const char *name, int len, int *offset) {
|
||||
int i;
|
||||
const char *np;
|
||||
char **p, *cp;
|
||||
|
||||
if (name == NULL || environ == NULL)
|
||||
return (NULL);
|
||||
for (p = environ + *offset; (cp = *p) != NULL; ++p) {
|
||||
for (np = name, i = len; i && *cp; i--)
|
||||
if (*cp++ != *np++)
|
||||
break;
|
||||
if (i == 0 && *cp++ == '=') {
|
||||
*offset = p - environ;
|
||||
return (cp);
|
||||
}
|
||||
}
|
||||
return (NULL);
|
||||
}
|
||||
|
||||
// Source: bionic/libc/upstream-openbsd/lib/libc/stdlib/setenv.c
|
||||
int setenv(const char *name, const char *value, int rewrite) {
|
||||
static char **lastenv;
|
||||
|
||||
char *C, **P;
|
||||
const char *np;
|
||||
int l_value, offset = 0;
|
||||
|
||||
if (!name || !*name) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
for (np = name; *np && *np != '='; ++np)
|
||||
;
|
||||
if (*np) {
|
||||
errno = EINVAL;
|
||||
return (-1); /* has `=' in name */
|
||||
}
|
||||
|
||||
l_value = strlen(value);
|
||||
if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) {
|
||||
int tmpoff = offset + 1;
|
||||
if (!rewrite)
|
||||
return (0);
|
||||
#if 0 /* XXX - existing entry may not be writable */
|
||||
if (strlen(C) >= l_value) { /* old larger; copy over */
|
||||
while ((*C++ = *value++))
|
||||
;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
/* could be set multiple times */
|
||||
while (__findenv(name, (int)(np - name), &tmpoff)) {
|
||||
for (P = &environ[tmpoff];; ++P)
|
||||
if (!(*P = *(P + 1)))
|
||||
break;
|
||||
}
|
||||
} else { /* create new slot */
|
||||
size_t cnt = 0;
|
||||
|
||||
if (environ != NULL) {
|
||||
for (P = environ; *P != NULL; P++)
|
||||
;
|
||||
cnt = P - environ;
|
||||
}
|
||||
size_t new_size;
|
||||
if (__builtin_mul_overflow(cnt + 2, sizeof(char *), &new_size)) {
|
||||
errno = ENOMEM;
|
||||
return (-1);
|
||||
}
|
||||
P = realloc(lastenv, new_size);
|
||||
if (!P)
|
||||
return (-1);
|
||||
if (lastenv != environ && environ != NULL)
|
||||
memcpy(P, environ, cnt * sizeof(char *));
|
||||
lastenv = environ = P;
|
||||
offset = cnt;
|
||||
environ[cnt + 1] = NULL;
|
||||
}
|
||||
if (!(environ[offset] = /* name + `=' + value */
|
||||
malloc((int)(np - name) + l_value + 2)))
|
||||
return (-1);
|
||||
for (C = environ[offset]; (*C = *name++) && *C != '='; ++C)
|
||||
;
|
||||
for (*C++ = '='; (*C++ = *value++); )
|
||||
;
|
||||
return (0);
|
||||
}
|
||||
|
||||
// Source: bionic/libc/bionic/libgen.cpp
|
||||
static int __basename_r(const char *path, char* buffer, size_t buffer_size) {
|
||||
const char *startp = NULL;
|
||||
const char *endp = NULL;
|
||||
int len;
|
||||
int result;
|
||||
|
||||
// Empty or NULL string gets treated as ".".
|
||||
if (path == NULL || *path == '\0') {
|
||||
startp = ".";
|
||||
len = 1;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Strip trailing slashes.
|
||||
endp = path + strlen(path) - 1;
|
||||
while (endp > path && *endp == '/') {
|
||||
endp--;
|
||||
}
|
||||
|
||||
// All slashes becomes "/".
|
||||
if (endp == path && *endp == '/') {
|
||||
startp = "/";
|
||||
len = 1;
|
||||
goto Exit;
|
||||
}
|
||||
|
||||
// Find the start of the base.
|
||||
startp = endp;
|
||||
while (startp > path && *(startp - 1) != '/') {
|
||||
startp--;
|
||||
}
|
||||
|
||||
len = endp - startp +1;
|
||||
|
||||
Exit:
|
||||
result = len;
|
||||
if (buffer == NULL) {
|
||||
return result;
|
||||
}
|
||||
if (len > (int) buffer_size - 1) {
|
||||
len = buffer_size - 1;
|
||||
result = -1;
|
||||
errno = ERANGE;
|
||||
}
|
||||
|
||||
if (len >= 0) {
|
||||
memcpy(buffer, startp, len);
|
||||
buffer[len] = 0;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
char *basename(const char *path) {
|
||||
static char buf[4069];
|
||||
int rc = __basename_r(path, buf, sizeof(buf));
|
||||
return (rc < 0) ? NULL : buf;
|
||||
}
|
||||
|
||||
// Simply just abort when abort_message is called
|
||||
void __wrap_abort_message(const char* format, ...) {
|
||||
abort();
|
||||
}
|
||||
|
||||
// Don't care about C++ global destructors
|
||||
int __cxa_atexit(void (*func) (void *), void * arg, void * dso_handle) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Emulate pthread functions
|
||||
|
||||
static pthread_key_t g_counter = 0;
|
||||
static void **g_key_values = NULL;
|
||||
|
||||
int pthread_key_create(pthread_key_t *key_ptr, void (*dtor)(void*)) {
|
||||
*key_ptr = g_counter++;
|
||||
g_key_values = realloc(g_key_values, g_counter * sizeof(void*));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_key_delete(pthread_key_t key) {
|
||||
if (key < g_counter) {
|
||||
g_key_values[key] = NULL;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void *pthread_getspecific(pthread_key_t key) {
|
||||
return key < g_counter ? g_key_values[key] : NULL;
|
||||
}
|
||||
|
||||
int pthread_setspecific(pthread_key_t key, const void *value) {
|
||||
if (key < g_counter) {
|
||||
g_key_values[key] = (void *) value;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Workaround LTO bug: https://github.com/llvm/llvm-project/issues/61101
|
||||
#if defined(__i386__)
|
||||
extern long *_GLOBAL_OFFSET_TABLE_;
|
||||
long unused() {
|
||||
return *_GLOBAL_OFFSET_TABLE_;
|
||||
}
|
||||
#endif
|
15
nolibc.c
Normal file
15
nolibc.c
Normal file
@ -0,0 +1,15 @@
|
||||
#include "nolibc/crt.h"
|
||||
#include "nolibc/arch.h"
|
||||
|
||||
// errno
|
||||
|
||||
static int g_errno = 0;
|
||||
|
||||
int *__errno(void) {
|
||||
return &g_errno;
|
||||
}
|
||||
|
||||
long __set_errno_internal(int n) {
|
||||
g_errno = n;
|
||||
return -1;
|
||||
}
|
159
nolibc/arch-aarch64.h
Normal file
159
nolibc/arch-aarch64.h
Normal file
@ -0,0 +1,159 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* AARCH64 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_AARCH64_H
|
||||
#define _NOLIBC_ARCH_AARCH64_H
|
||||
|
||||
/* Syscalls for AARCH64 :
|
||||
* - registers are 64-bit
|
||||
* - stack is 16-byte aligned
|
||||
* - syscall number is passed in x8
|
||||
* - arguments are in x0, x1, x2, x3, x4, x5
|
||||
* - the system call is performed by calling svc 0
|
||||
* - syscall return comes in x0.
|
||||
* - the arguments are cast to long and assigned into the target registers
|
||||
* which are then simply passed as registers to the asm code, so that we
|
||||
* don't have to experience issues with register constraints.
|
||||
*
|
||||
* On aarch64, select() is not implemented so we have to use pselect6().
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_PSELECT6
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0"); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
: "r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
: "r"(_arg1), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("x1") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("x1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("x2") = (long)(arg3); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("x1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("x2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("x3") = (long)(arg4); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r"(_arg1) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("x1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("x2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("x3") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("x4") = (long)(arg5); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r" (_arg1) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
register long _num __asm__ ("x8") = (num); \
|
||||
register long _arg1 __asm__ ("x0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("x1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("x2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("x3") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("x4") = (long)(arg5); \
|
||||
register long _arg6 __asm__ ("x5") = (long)(arg6); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"svc #0\n" \
|
||||
: "=r" (_arg1) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_arg6), "r"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((noreturn)) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"mov x0, sp\n" /* save stack pointer to x0, as arg1 of _start_c */
|
||||
"and sp, x0, -16\n" /* sp must be 16-byte aligned in the callee */
|
||||
"bl _start_c\n" /* transfer to c runtime */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_AARCH64_H */
|
200
nolibc/arch-arm.h
Normal file
200
nolibc/arch-arm.h
Normal file
@ -0,0 +1,200 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* ARM specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_ARM_H
|
||||
#define _NOLIBC_ARCH_ARM_H
|
||||
|
||||
/* Syscalls for ARM in ARM or Thumb modes :
|
||||
* - registers are 32-bit
|
||||
* - stack is 8-byte aligned
|
||||
* ( http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka4127.html)
|
||||
* - syscall number is passed in r7
|
||||
* - arguments are in r0, r1, r2, r3, r4, r5
|
||||
* - the system call is performed by calling svc #0
|
||||
* - syscall return comes in r0.
|
||||
* - only lr is clobbered.
|
||||
* - the arguments are cast to long and assigned into the target registers
|
||||
* which are then simply passed as registers to the asm code, so that we
|
||||
* don't have to experience issues with register constraints.
|
||||
* - the syscall number is always specified last in order to allow to force
|
||||
* some registers before (gcc refuses a %-register at the last position).
|
||||
* - in thumb mode without -fomit-frame-pointer, r7 is also used to store the
|
||||
* frame pointer, and we cannot directly assign it as a register variable,
|
||||
* nor can we clobber it. Instead we assign the r6 register and swap it
|
||||
* with r7 before calling svc, and r6 is marked as clobbered.
|
||||
* We're just using any regular register which we assign to r7 after saving
|
||||
* it.
|
||||
*
|
||||
* Also, ARM supports the old_select syscall if newselect is not available
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_OLD_SELECT
|
||||
|
||||
#if (defined(__THUMBEB__) || defined(__THUMBEL__)) && \
|
||||
!defined(NOLIBC_OMIT_FRAME_POINTER)
|
||||
/* swap r6,r7 needed in Thumb mode since we can't use nor clobber r7 */
|
||||
#define _NOLIBC_SYSCALL_REG "r6"
|
||||
#define _NOLIBC_THUMB_SET_R7 "eor r7, r6\neor r6, r7\neor r7, r6\n"
|
||||
#define _NOLIBC_THUMB_RESTORE_R7 "mov r7, r6\n"
|
||||
|
||||
#else /* we're in ARM mode */
|
||||
/* in Arm mode we can directly use r7 */
|
||||
#define _NOLIBC_SYSCALL_REG "r7"
|
||||
#define _NOLIBC_THUMB_SET_R7 ""
|
||||
#define _NOLIBC_THUMB_RESTORE_R7 ""
|
||||
|
||||
#endif /* end THUMB */
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0"); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r"(_num) \
|
||||
: "r"(_arg1), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r2") = (long)(arg3); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r3") = (long)(arg4); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r3") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r4") = (long)(arg5); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
register long _num __asm__(_NOLIBC_SYSCALL_REG) = (num); \
|
||||
register long _arg1 __asm__ ("r0") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("r1") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("r2") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r3") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r4") = (long)(arg5); \
|
||||
register long _arg6 __asm__ ("r5") = (long)(arg6); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
_NOLIBC_THUMB_SET_R7 \
|
||||
"svc #0\n" \
|
||||
_NOLIBC_THUMB_RESTORE_R7 \
|
||||
: "=r"(_arg1), "=r" (_num) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_arg6), "r"(_num) \
|
||||
: "memory", "cc", "lr" \
|
||||
); \
|
||||
_arg1; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* startup code */
|
||||
void __attribute__((noreturn)) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"mov r0, sp\n" /* save stack pointer to %r0, as arg1 of _start_c */
|
||||
"and ip, r0, #-8\n" /* sp must be 8-byte aligned in the callee */
|
||||
"mov sp, ip\n"
|
||||
"bl _start_c\n" /* transfer to c runtime */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_ARM_H */
|
179
nolibc/arch-i386.h
Normal file
179
nolibc/arch-i386.h
Normal file
@ -0,0 +1,179 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* i386 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_I386_H
|
||||
#define _NOLIBC_ARCH_I386_H
|
||||
|
||||
/* Syscalls for i386 :
|
||||
* - mostly similar to x86_64
|
||||
* - registers are 32-bit
|
||||
* - syscall number is passed in eax
|
||||
* - arguments are in ebx, ecx, edx, esi, edi, ebp respectively
|
||||
* - all registers are preserved (except eax of course)
|
||||
* - the system call is performed by calling int $0x80
|
||||
* - syscall return comes in eax
|
||||
* - the arguments are cast to long and assigned into the target registers
|
||||
* which are then simply passed as registers to the asm code, so that we
|
||||
* don't have to experience issues with register constraints.
|
||||
* - the syscall number is always specified last in order to allow to force
|
||||
* some registers before (gcc refuses a %-register at the last position).
|
||||
*
|
||||
* Also, i386 supports the old_select syscall if newselect is not available
|
||||
*/
|
||||
#define __ARCH_WANT_SYS_OLD_SELECT
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "r"(_arg1), \
|
||||
"0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("edx") = (long)(arg3); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("edx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("esi") = (long)(arg4); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("eax") = (num); \
|
||||
register long _arg1 __asm__ ("ebx") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("ecx") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("edx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("esi") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("edi") = (long)(arg5); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"int $0x80\n" \
|
||||
: "=a" (_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"0"(_num) \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
long _eax = (long)(num); \
|
||||
long _arg6 = (long)(arg6); /* Always in memory */ \
|
||||
__asm__ volatile ( \
|
||||
"pushl %[_arg6]\n\t" \
|
||||
"pushl %%ebp\n\t" \
|
||||
"movl 4(%%esp),%%ebp\n\t" \
|
||||
"int $0x80\n\t" \
|
||||
"popl %%ebp\n\t" \
|
||||
"addl $4,%%esp\n\t" \
|
||||
: "+a"(_eax) /* %eax */ \
|
||||
: "b"(arg1), /* %ebx */ \
|
||||
"c"(arg2), /* %ecx */ \
|
||||
"d"(arg3), /* %edx */ \
|
||||
"S"(arg4), /* %esi */ \
|
||||
"D"(arg5), /* %edi */ \
|
||||
[_arg6]"m"(_arg6) /* memory */ \
|
||||
: "memory", "cc" \
|
||||
); \
|
||||
_eax; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* i386 System V ABI mandates:
|
||||
* 1) last pushed argument must be 16-byte aligned.
|
||||
* 2) The deepest stack frame should be set to zero
|
||||
*
|
||||
*/
|
||||
void __attribute__((noreturn)) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"xor %ebp, %ebp\n" /* zero the stack frame */
|
||||
"mov %esp, %eax\n" /* save stack pointer to %eax, as arg1 of _start_c */
|
||||
"and $-16, %esp\n" /* last pushed argument must be 16-byte aligned */
|
||||
"push %eax\n" /* push arg1 on stack to support plain stack modes too */
|
||||
"call _start_c\n" /* transfer to c runtime */
|
||||
"hlt\n" /* ensure it does not return */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_I386_H */
|
177
nolibc/arch-x86_64.h
Normal file
177
nolibc/arch-x86_64.h
Normal file
@ -0,0 +1,177 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* x86_64 specific definitions for NOLIBC
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_X86_64_H
|
||||
#define _NOLIBC_ARCH_X86_64_H
|
||||
|
||||
/* Syscalls for x86_64 :
|
||||
* - registers are 64-bit
|
||||
* - syscall number is passed in rax
|
||||
* - arguments are in rdi, rsi, rdx, r10, r8, r9 respectively
|
||||
* - the system call is performed by calling the syscall instruction
|
||||
* - syscall return comes in rax
|
||||
* - rcx and r11 are clobbered, others are preserved.
|
||||
* - the arguments are cast to long and assigned into the target registers
|
||||
* which are then simply passed as registers to the asm code, so that we
|
||||
* don't have to experience issues with register constraints.
|
||||
* - the syscall number is always specified last in order to allow to force
|
||||
* some registers before (gcc refuses a %-register at the last position).
|
||||
* - see also x86-64 ABI section A.2 AMD64 Linux Kernel Conventions, A.2.1
|
||||
* Calling Conventions.
|
||||
*
|
||||
* Link x86-64 ABI: https://gitlab.com/x86-psABIs/x86-64-ABI/-/wikis/home
|
||||
*
|
||||
*/
|
||||
|
||||
#define my_syscall0(num) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall1(num, arg1) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall2(num, arg1, arg2) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall3(num, arg1, arg2, arg3) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall4(num, arg1, arg2, arg3, arg4) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r10") = (long)(arg4); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall5(num, arg1, arg2, arg3, arg4, arg5) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r10") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r8") = (long)(arg5); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#define my_syscall6(num, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
long _ret; \
|
||||
register long _num __asm__ ("rax") = (num); \
|
||||
register long _arg1 __asm__ ("rdi") = (long)(arg1); \
|
||||
register long _arg2 __asm__ ("rsi") = (long)(arg2); \
|
||||
register long _arg3 __asm__ ("rdx") = (long)(arg3); \
|
||||
register long _arg4 __asm__ ("r10") = (long)(arg4); \
|
||||
register long _arg5 __asm__ ("r8") = (long)(arg5); \
|
||||
register long _arg6 __asm__ ("r9") = (long)(arg6); \
|
||||
\
|
||||
__asm__ volatile ( \
|
||||
"syscall\n" \
|
||||
: "=a"(_ret) \
|
||||
: "r"(_arg1), "r"(_arg2), "r"(_arg3), "r"(_arg4), "r"(_arg5), \
|
||||
"r"(_arg6), "0"(_num) \
|
||||
: "rcx", "r11", "memory", "cc" \
|
||||
); \
|
||||
_ret; \
|
||||
})
|
||||
|
||||
#ifdef _NOLIBC_CRT_H
|
||||
|
||||
/* startup code */
|
||||
/*
|
||||
* x86-64 System V ABI mandates:
|
||||
* 1) %rsp must be 16-byte aligned right before the function call.
|
||||
* 2) The deepest stack frame should be zero (the %rbp).
|
||||
*
|
||||
*/
|
||||
void __attribute__((noreturn)) _start(void)
|
||||
{
|
||||
__asm__ volatile (
|
||||
"xor %ebp, %ebp\n" /* zero the stack frame */
|
||||
"mov %rsp, %rdi\n" /* save stack pointer to %rdi, as arg1 of _start_c */
|
||||
"and $-16, %rsp\n" /* %rsp must be 16-byte aligned before call */
|
||||
"call _start_c\n" /* transfer to c runtime */
|
||||
"hlt\n" /* ensure it does not return */
|
||||
);
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
||||
|
||||
#endif /* _NOLIBC_ARCH_X86_64_H */
|
28
nolibc/arch.h
Normal file
28
nolibc/arch.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* Copyright (C) 2017-2022 Willy Tarreau <w@1wt.eu>
|
||||
*/
|
||||
|
||||
/* Below comes the architecture-specific code. For each architecture, we have
|
||||
* the syscall declarations and the _start code definition. This is the only
|
||||
* global part. On all architectures the kernel puts everything in the stack
|
||||
* before jumping to _start just above us, without any return address (_start
|
||||
* is not a function but an entry point). So at the stack pointer we find argc.
|
||||
* Then argv[] begins, and ends at the first NULL. Then we have envp which
|
||||
* starts and ends with a NULL as well. So envp=argv+argc+1.
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_ARCH_H
|
||||
#define _NOLIBC_ARCH_H
|
||||
|
||||
#if defined(__x86_64__)
|
||||
#include "arch-x86_64.h"
|
||||
#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__)
|
||||
#include "arch-i386.h"
|
||||
#elif defined(__ARM_EABI__)
|
||||
#include "arch-arm.h"
|
||||
#elif defined(__aarch64__)
|
||||
#include "arch-aarch64.h"
|
||||
#endif
|
||||
|
||||
#endif /* _NOLIBC_ARCH_H */
|
80
nolibc/crt.h
Normal file
80
nolibc/crt.h
Normal file
@ -0,0 +1,80 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1 OR MIT */
|
||||
/*
|
||||
* C Run Time support for NOLIBC
|
||||
* Copyright (C) 2023 Zhangjin Wu <falcon@tinylab.org>
|
||||
*/
|
||||
|
||||
#ifndef _NOLIBC_CRT_H
|
||||
#define _NOLIBC_CRT_H
|
||||
|
||||
char **environ;
|
||||
const unsigned long *_auxv;
|
||||
void _exit(int);
|
||||
void __init_stdio(void);
|
||||
|
||||
typedef void init_func_t(int, char*[], char*[]);
|
||||
typedef void fini_func_t(void);
|
||||
|
||||
extern init_func_t *__preinit_array_start[];
|
||||
extern init_func_t *__preinit_array_end[];
|
||||
extern init_func_t *__init_array_start[];
|
||||
extern init_func_t *__init_array_end[];
|
||||
extern fini_func_t *__fini_array_start[];
|
||||
extern fini_func_t *__fini_array_end[];
|
||||
|
||||
static void call_array(init_func_t **start, init_func_t **end, int argc, char *argv[], char *envp[]) {
|
||||
unsigned long count = end - start;
|
||||
while (count-- > 0) {
|
||||
init_func_t* function = *start++;
|
||||
(*function)(argc, argv, envp);
|
||||
}
|
||||
}
|
||||
|
||||
void __attribute__((used)) _start_c(long *sp)
|
||||
{
|
||||
long argc;
|
||||
char **argv;
|
||||
char **envp;
|
||||
const unsigned long *auxv;
|
||||
/* silence potential warning: conflicting types for 'main' */
|
||||
int _nolibc_main(int, char **, char **) __asm__ ("main");
|
||||
|
||||
/*
|
||||
* sp : argc <-- argument count, required by main()
|
||||
* argv: argv[0] <-- argument vector, required by main()
|
||||
* argv[1]
|
||||
* ...
|
||||
* argv[argc-1]
|
||||
* null
|
||||
* environ: environ[0] <-- environment variables, required by main() and getenv()
|
||||
* environ[1]
|
||||
* ...
|
||||
* null
|
||||
* _auxv: _auxv[0] <-- auxiliary vector, required by getauxval()
|
||||
* _auxv[1]
|
||||
* ...
|
||||
* null
|
||||
*/
|
||||
|
||||
/* assign argc and argv */
|
||||
argc = *sp;
|
||||
argv = (void *)(sp + 1);
|
||||
|
||||
/* find environ */
|
||||
environ = envp = argv + argc + 1;
|
||||
|
||||
/* find _auxv */
|
||||
for (auxv = (void *)envp; *auxv++;)
|
||||
;
|
||||
_auxv = auxv;
|
||||
|
||||
/* call preinit and init */
|
||||
__init_stdio();
|
||||
call_array(__preinit_array_start, __preinit_array_end, argc, argv, envp);
|
||||
call_array(__init_array_start, __init_array_end, argc, argv, envp);
|
||||
|
||||
/* go to application */
|
||||
_exit(_nolibc_main(argc, argv, envp));
|
||||
}
|
||||
|
||||
#endif /* _NOLIBC_CRT_H */
|
222
stdio.c
Normal file
222
stdio.c
Normal file
@ -0,0 +1,222 @@
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct file_ptr_t {
|
||||
int fd;
|
||||
void *cookie;
|
||||
int (*read_fn)(void*, char*, int);
|
||||
int (*write_fn)(void*, const char*, int);
|
||||
int (*close_fn)(void*);
|
||||
} file_ptr_t;
|
||||
|
||||
static int fp_read_fn(void *p, char *buf, int sz) {
|
||||
intptr_t fd = (intptr_t) p;
|
||||
return read(fd, buf, sz);
|
||||
}
|
||||
|
||||
static int fp_write_fn(void *p, const char *buf, int sz) {
|
||||
intptr_t fd = (intptr_t) p;
|
||||
return write(fd, buf, sz);
|
||||
}
|
||||
|
||||
static int fp_close_fn(void *p) {
|
||||
intptr_t fd = (intptr_t) p;
|
||||
return close(fd);
|
||||
}
|
||||
|
||||
static void set_fp_fd(file_ptr_t *fp, int fd) {
|
||||
fp->fd = fd;
|
||||
fp->cookie = NULL;
|
||||
fp->read_fn = fp_read_fn;
|
||||
fp->write_fn = fp_write_fn;
|
||||
fp->close_fn = fp_close_fn;
|
||||
}
|
||||
|
||||
static file_ptr_t __stdio_fp[3];
|
||||
|
||||
FILE* stdin = (FILE *) &__stdio_fp[0];
|
||||
FILE* stdout = (FILE *) &__stdio_fp[1];
|
||||
FILE* stderr = (FILE *) &__stdio_fp[2];
|
||||
|
||||
void __init_stdio(void) {
|
||||
set_fp_fd((file_ptr_t *) stdin, 0);
|
||||
set_fp_fd((file_ptr_t *) stdout, 1);
|
||||
set_fp_fd((file_ptr_t *) stderr, 2);
|
||||
}
|
||||
|
||||
FILE *fdopen(int fd, const char *mode __attribute__((unused))) {
|
||||
file_ptr_t *fp = malloc(sizeof(file_ptr_t));
|
||||
set_fp_fd(fp, fd);
|
||||
return (FILE *) fp;
|
||||
}
|
||||
|
||||
FILE *funopen(const void* cookie,
|
||||
int (*read_fn)(void*, char*, int),
|
||||
int (*write_fn)(void*, const char*, int),
|
||||
fpos_t (*seek_fn)(void*, fpos_t, int),
|
||||
int (*close_fn)(void*)) {
|
||||
file_ptr_t *fp = malloc(sizeof(file_ptr_t));
|
||||
fp->fd = -1;
|
||||
fp->cookie = (void *) cookie;
|
||||
fp->read_fn = read_fn;
|
||||
fp->write_fn = write_fn;
|
||||
fp->close_fn = close_fn;
|
||||
return (FILE *) fp;
|
||||
}
|
||||
|
||||
#define fn_arg (fp->fd < 0 ? fp->cookie : ((void*)(intptr_t) fp->fd))
|
||||
|
||||
int fclose(FILE *stream) {
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
int ret = fp->close_fn(fn_arg);
|
||||
free(fp);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fileno(FILE *stream) {
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
return fp->fd;
|
||||
}
|
||||
|
||||
int fputc(int ch, FILE *stream) {
|
||||
char c = ch;
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
return fp->write_fn(fn_arg, &c, 1) >= 0 ? 0 : EOF;
|
||||
}
|
||||
|
||||
size_t fwrite(const void* buf, size_t size, size_t count, FILE* stream) {
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
int len = size * count;
|
||||
int ret = fp->write_fn(fn_arg, buf, len);
|
||||
return ret == len ? count : 0;
|
||||
}
|
||||
|
||||
int fputs(const char* s, FILE* stream) {
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
size_t length = strlen(s);
|
||||
return fp->write_fn(fn_arg, s, length) == length ? 0 : EOF;
|
||||
}
|
||||
|
||||
int fgetc(FILE *stream) {
|
||||
char ch;
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
if (fp->read_fn(fn_arg, &ch, 1) == 1) {
|
||||
return ch;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
size_t fread(void *buf, size_t size, size_t count, FILE* stream) {
|
||||
file_ptr_t *fp = (file_ptr_t *) stream;
|
||||
int len = size * count;
|
||||
int ret = fp->read_fn(fn_arg, buf, len);
|
||||
return ret == len ? count : 0;
|
||||
}
|
||||
|
||||
void setbuf(FILE* fp, char* buf) {}
|
||||
|
||||
#include "tinystdio/tinystdio.c"
|
||||
|
||||
struct file_putp {
|
||||
FILE *fp;
|
||||
int len;
|
||||
};
|
||||
|
||||
static void file_putc(void *data, char ch) {
|
||||
struct file_putp *putp = data;
|
||||
int r = write(fileno(putp->fp), &ch, 1);
|
||||
if (r >= 0)
|
||||
putp->len += r;
|
||||
}
|
||||
|
||||
int vfprintf(FILE *stream, const char *format, va_list arg) {
|
||||
struct file_putp data;
|
||||
data.fp = stream;
|
||||
data.len = 0;
|
||||
tfp_format(&data, &file_putc, format, arg);
|
||||
return data.len;
|
||||
}
|
||||
|
||||
int vasprintf(char **strp, const char *fmt, va_list ap) {
|
||||
int size = vsnprintf(NULL, 0, fmt, ap);
|
||||
if (size >= 0) {
|
||||
*strp = malloc(size + 1);
|
||||
vsnprintf(*strp, size, fmt, ap);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
int vprintf(const char *fmt, va_list args) {
|
||||
return vfprintf(stdout, fmt, args);
|
||||
}
|
||||
|
||||
int fprintf(FILE *stream, const char *fmt, ...) {
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vfprintf(stream, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int printf(const char *fmt, ...) {
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, fmt);
|
||||
ret = vfprintf(stdout, fmt, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int sscanf(const char *str, const char *format, ...) {
|
||||
va_list ap;
|
||||
int retval;
|
||||
|
||||
va_start(ap, format);
|
||||
retval = tfp_vsscanf(str, format, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
// Original source: https://github.com/freebsd/freebsd/blob/master/contrib/file/src/getline.c
|
||||
// License: BSD, full copyright notice please check original source
|
||||
ssize_t getdelim(char **buf, size_t *bufsiz, int delimiter, FILE *fp) {
|
||||
char *ptr, *eptr;
|
||||
|
||||
if (*buf == NULL || *bufsiz == 0) {
|
||||
*bufsiz = BUFSIZ;
|
||||
if ((*buf = (char *) malloc(*bufsiz)) == NULL)
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (ptr = *buf, eptr = *buf + *bufsiz;;) {
|
||||
int c = fgetc(fp);
|
||||
if (c == -1) {
|
||||
return ptr == *buf ? -1 : ptr - *buf;
|
||||
}
|
||||
*ptr++ = c;
|
||||
if (c == delimiter) {
|
||||
*ptr = '\0';
|
||||
return ptr - *buf;
|
||||
}
|
||||
if (ptr + 2 >= eptr) {
|
||||
char *nbuf;
|
||||
size_t nbufsiz = *bufsiz * 2;
|
||||
ssize_t d = ptr - *buf;
|
||||
if ((nbuf = (char *) realloc(*buf, nbufsiz)) == NULL)
|
||||
return -1;
|
||||
*buf = nbuf;
|
||||
*bufsiz = nbufsiz;
|
||||
eptr = nbuf + nbufsiz;
|
||||
ptr = nbuf + d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ssize_t getline(char **buf, size_t *bufsiz, FILE *fp) {
|
||||
return getdelim(buf, bufsiz, '\n', fp);
|
||||
}
|
221
syscall.c
Normal file
221
syscall.c
Normal file
@ -0,0 +1,221 @@
|
||||
#define SYS_INLINE
|
||||
|
||||
#include "linux_syscall_support.h"
|
||||
|
||||
// Some missing declarations
|
||||
static inline _syscall3(int, faccessat, int, f, const char *, p, int, m)
|
||||
_syscall2(int, umount2, const char *, t, int, f)
|
||||
_syscall4(int, renameat, int, o, const char *, op, int, n, const char *, np)
|
||||
_syscall1(mode_t, umask, mode_t, mask)
|
||||
_syscall1(int, chroot, const char *, path)
|
||||
_syscall2(int, nanosleep, const struct kernel_timespec *, req, struct kernel_timespec *, rem)
|
||||
_syscall5(int, mount, const char *, s, const char *, t,
|
||||
const char *, fs, unsigned long, f, const void *, d)
|
||||
_syscall3(int, symlinkat, const char *, t, int, fd, const char *, l)
|
||||
_syscall3(int, mkdirat, int, dirfd, const char *, pathname, mode_t, mode)
|
||||
_syscall4(ssize_t, sendfile, int, out_fd, int, in_fd, off_t *, offset, size_t, count)
|
||||
_syscall5(int, linkat, int, o, const char *, op, int, n, const char *, np, int, f)
|
||||
_syscall4(int, mknodat, int, dirfd, const char *, pathname, mode_t, mode, dev_t, dev)
|
||||
_syscall2(int, fchmod, int, fd, mode_t, mode)
|
||||
_syscall4(int, fchmodat, int, dirfd, const char *, pathname, mode_t, mode, int, flags)
|
||||
_syscall5(int, fchownat, int, dirfd, const char *, p, uid_t, owner, gid_t, group, int, flags)
|
||||
_syscall3(ssize_t, readv, int, fd, const struct kernel_iovec*, v, size_t, c)
|
||||
|
||||
#define SYMBOL_ALIAS(from, to) \
|
||||
__asm__(".global " #from " \n " #from " = " #to)
|
||||
|
||||
#define EXPORT_SYMBOL(name) \
|
||||
SYMBOL_ALIAS(name, sys_##name)
|
||||
|
||||
EXPORT_SYMBOL(_exit);
|
||||
EXPORT_SYMBOL(openat);
|
||||
EXPORT_SYMBOL(close);
|
||||
EXPORT_SYMBOL(read);
|
||||
EXPORT_SYMBOL(symlink);
|
||||
EXPORT_SYMBOL(write);
|
||||
EXPORT_SYMBOL(writev);
|
||||
EXPORT_SYMBOL(unlink);
|
||||
EXPORT_SYMBOL(mmap);
|
||||
EXPORT_SYMBOL(munmap);
|
||||
EXPORT_SYMBOL(mremap);
|
||||
EXPORT_SYMBOL(readlink);
|
||||
EXPORT_SYMBOL(unlinkat);
|
||||
EXPORT_SYMBOL(getpid);
|
||||
EXPORT_SYMBOL(chdir);
|
||||
EXPORT_SYMBOL(umount2);
|
||||
EXPORT_SYMBOL(readlinkat);
|
||||
EXPORT_SYMBOL(renameat);
|
||||
EXPORT_SYMBOL(umask);
|
||||
EXPORT_SYMBOL(chroot);
|
||||
EXPORT_SYMBOL(mount);
|
||||
EXPORT_SYMBOL(symlinkat);
|
||||
EXPORT_SYMBOL(stat);
|
||||
EXPORT_SYMBOL(lstat);
|
||||
EXPORT_SYMBOL(statfs);
|
||||
EXPORT_SYMBOL(mkdirat);
|
||||
EXPORT_SYMBOL(ioctl);
|
||||
EXPORT_SYMBOL(fork);
|
||||
EXPORT_SYMBOL(sendfile);
|
||||
EXPORT_SYMBOL(ftruncate);
|
||||
EXPORT_SYMBOL(linkat);
|
||||
EXPORT_SYMBOL(mknodat);
|
||||
EXPORT_SYMBOL(fchmod);
|
||||
EXPORT_SYMBOL(fchmodat);
|
||||
EXPORT_SYMBOL(fchownat);
|
||||
EXPORT_SYMBOL(readv);
|
||||
EXPORT_SYMBOL(lseek);
|
||||
EXPORT_SYMBOL(execve);
|
||||
EXPORT_SYMBOL(getdents64);
|
||||
|
||||
SYMBOL_ALIAS(exit, _exit);
|
||||
|
||||
#if defined(__LP64__)
|
||||
|
||||
EXPORT_SYMBOL(fstat);
|
||||
EXPORT_SYMBOL(newfstatat);
|
||||
SYMBOL_ALIAS(fstatat, newfstatat);
|
||||
|
||||
#else
|
||||
|
||||
EXPORT_SYMBOL(fstat64);
|
||||
EXPORT_SYMBOL(fstatat64);
|
||||
SYMBOL_ALIAS(fstat, fstat64);
|
||||
SYMBOL_ALIAS(fstatat, fstatat64);
|
||||
|
||||
#endif
|
||||
|
||||
int fchown(int fd, uid_t owner, gid_t group) {
|
||||
return fchownat(fd, "", owner, group, AT_EMPTY_PATH);
|
||||
}
|
||||
|
||||
int lchown(const char* path, uid_t uid, gid_t gid) {
|
||||
return fchownat(AT_FDCWD, path, uid, gid, AT_SYMLINK_NOFOLLOW);
|
||||
}
|
||||
|
||||
int chown(const char* path, uid_t uid, gid_t gid) {
|
||||
return fchownat(AT_FDCWD, path, uid, gid, 0);
|
||||
}
|
||||
|
||||
int chmod(const char* path, mode_t mode) {
|
||||
return sys_fchmodat(AT_FDCWD, path, mode, 0);
|
||||
}
|
||||
|
||||
int mkfifoat(int fd, const char* path, mode_t mode) {
|
||||
return sys_mknodat(fd, path, (mode & ~S_IFMT) | S_IFIFO, 0);
|
||||
}
|
||||
|
||||
int mkfifo(const char* path, mode_t mode) {
|
||||
return mkfifoat(AT_FDCWD, path, mode);
|
||||
}
|
||||
|
||||
int mknod(const char* path, mode_t mode, dev_t dev) {
|
||||
return sys_mknodat(AT_FDCWD, path, mode, dev);
|
||||
}
|
||||
|
||||
int link(const char *oldpath, const char *newpath) {
|
||||
return sys_linkat(AT_FDCWD, oldpath, AT_FDCWD, newpath, 0);
|
||||
}
|
||||
|
||||
int rmdir(const char *path) {
|
||||
return sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
||||
}
|
||||
|
||||
int mkdir(const char *pathname, mode_t mode) {
|
||||
return sys_mkdirat(AT_FDCWD, pathname, mode);
|
||||
}
|
||||
|
||||
int symlink(const char *target, const char *linkpath) {
|
||||
return sys_symlinkat(target, AT_FDCWD, linkpath);
|
||||
}
|
||||
|
||||
int rename(const char *oldpath, const char *newpath) {
|
||||
return sys_renameat(AT_FDCWD, oldpath, AT_FDCWD, newpath);
|
||||
}
|
||||
|
||||
int access(const char* path, int mode) {
|
||||
return faccessat(AT_FDCWD, path, mode, 0);
|
||||
}
|
||||
|
||||
int remove(const char *path) {
|
||||
int r = sys_unlinkat(AT_FDCWD, path, 0);
|
||||
if (r < 0 && errno == EISDIR) {
|
||||
r = sys_unlinkat(AT_FDCWD, path, AT_REMOVEDIR);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
// Source: bionic/libc/bionic/abort.cpp
|
||||
void abort() {
|
||||
// Don't block SIGABRT to give any signal handler a chance; we ignore
|
||||
// any errors -- X311J doesn't allow abort to return anyway.
|
||||
struct kernel_sigset_t mask;
|
||||
sys_sigfillset(&mask);
|
||||
sys_sigdelset(&mask, SIGABRT);
|
||||
|
||||
sys_sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
sys_raise(SIGABRT);
|
||||
|
||||
// If SIGABRT is ignored or it's caught and the handler returns,
|
||||
// remove the SIGABRT signal handler and raise SIGABRT again.
|
||||
struct kernel_sigaction sa = { .sa_handler_ = SIG_DFL, .sa_flags = SA_RESTART };
|
||||
sys_sigaction(SIGABRT, &sa, NULL);
|
||||
|
||||
sys_sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||
sys_raise(SIGABRT);
|
||||
|
||||
// If we get this far, just exit.
|
||||
_exit(127);
|
||||
}
|
||||
|
||||
// Source: bionic/libc/bionic/usleep.cpp
|
||||
int usleep(useconds_t us) {
|
||||
struct kernel_timespec ts;
|
||||
ts.tv_sec = us / 1000000;
|
||||
ts.tv_nsec = (us % 1000000) * 1000;
|
||||
return sys_nanosleep(&ts, NULL);
|
||||
}
|
||||
|
||||
// Source: bionic/libc/bionic/faccessat.cpp
|
||||
int faccessat(int dirfd, const char *pathname, int mode, int flags) {
|
||||
// "The mode specifies the accessibility check(s) to be performed,
|
||||
// and is either the value F_OK, or a mask consisting of the
|
||||
// bitwise OR of one or more of R_OK, W_OK, and X_OK."
|
||||
if ((mode != F_OK) && ((mode & ~(R_OK | W_OK | X_OK)) != 0) &&
|
||||
((mode & (R_OK | W_OK | X_OK)) == 0)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (flags != 0) {
|
||||
// We deliberately don't support AT_SYMLINK_NOFOLLOW, a glibc
|
||||
// only feature which is error prone and dangerous.
|
||||
// More details at http://permalink.gmane.org/gmane.linux.lib.musl.general/6952
|
||||
//
|
||||
// AT_EACCESS isn't supported either. Android doesn't have setuid
|
||||
// programs, and never runs code with euid!=uid.
|
||||
//
|
||||
// We could use faccessat2(2) from Linux 5.8, but since we don't want the
|
||||
// first feature and don't need the second, we just reject such requests.
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sys_faccessat(dirfd, pathname, mode);
|
||||
}
|
||||
|
||||
int open(const char *pathname, int flags, ...) {
|
||||
int mode = 0;
|
||||
|
||||
if (((flags & O_CREAT) == O_CREAT) || ((flags & O_TMPFILE) == O_TMPFILE)) {
|
||||
va_list args;
|
||||
va_start(args, flags);
|
||||
mode = va_arg(args, int);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#if !defined(__LP64__)
|
||||
flags |= O_LARGEFILE;
|
||||
#endif
|
||||
|
||||
return sys_openat(AT_FDCWD, pathname, flags, mode);
|
||||
}
|
834
tinystdio/tinystdio.c
Normal file
834
tinystdio/tinystdio.c
Normal file
@ -0,0 +1,834 @@
|
||||
/*
|
||||
File: tinyprintf.c
|
||||
|
||||
Copyright (C) 2004 Kustaa Nyholm
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "tinystdio.h"
|
||||
|
||||
|
||||
/*
|
||||
* Configuration
|
||||
*/
|
||||
|
||||
/* Enable long int support */
|
||||
#define PRINTF_LONG_SUPPORT
|
||||
|
||||
/* Enable long long int support (implies long int support) */
|
||||
#define PRINTF_LONG_LONG_SUPPORT
|
||||
|
||||
/* Enable %z (size_t) support */
|
||||
#define PRINTF_SIZE_T_SUPPORT
|
||||
|
||||
|
||||
/*
|
||||
* Configuration adjustments
|
||||
*/
|
||||
#ifdef PRINTF_SIZE_T_SUPPORT
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
# define PRINTF_LONG_SUPPORT
|
||||
#endif
|
||||
|
||||
/* __SIZEOF_<type>__ defined at least by gcc */
|
||||
#ifdef __SIZEOF_POINTER__
|
||||
# define SIZEOF_POINTER __SIZEOF_POINTER__
|
||||
#endif
|
||||
#ifdef __SIZEOF_LONG_LONG__
|
||||
# define SIZEOF_LONG_LONG __SIZEOF_LONG_LONG__
|
||||
#endif
|
||||
#ifdef __SIZEOF_LONG__
|
||||
# define SIZEOF_LONG __SIZEOF_LONG__
|
||||
#endif
|
||||
#ifdef __SIZEOF_INT__
|
||||
# define SIZEOF_INT __SIZEOF_INT__
|
||||
#endif
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define _TFP_GCC_NO_INLINE_ __attribute__ ((noinline))
|
||||
#else
|
||||
# define _TFP_GCC_NO_INLINE_
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Implementation
|
||||
*/
|
||||
struct param {
|
||||
bool lz; /**< Leading zeros */
|
||||
bool alt; /**< alternate form */
|
||||
bool uc; /**< Upper case (for base16 only) */
|
||||
bool align_left; /**< 0 == align right (default), 1 == align left */
|
||||
int width; /**< field width */
|
||||
char sign; /**< The sign to display (if any) */
|
||||
unsigned int base; /**< number base (e.g.: 8, 10, 16) */
|
||||
char *bf; /**< Buffer to output */
|
||||
char prec; /**< Floating point precision */
|
||||
};
|
||||
|
||||
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
static void _TFP_GCC_NO_INLINE_ ulli2a(
|
||||
unsigned long long int num, struct param *p)
|
||||
{
|
||||
int n = 0;
|
||||
unsigned long long int d = 1;
|
||||
char *bf = p->bf;
|
||||
while (num / d >= p->base)
|
||||
d *= p->base;
|
||||
while (d != 0) {
|
||||
int dgt = num / d;
|
||||
num %= d;
|
||||
d /= p->base;
|
||||
if (n || dgt > 0 || d == 0) {
|
||||
*bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*bf = 0;
|
||||
}
|
||||
|
||||
static void lli2a(long long int num, struct param *p)
|
||||
{
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
p->sign = '-';
|
||||
}
|
||||
ulli2a(num, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
static void uli2a(unsigned long int num, struct param *p)
|
||||
{
|
||||
int n = 0;
|
||||
unsigned long int d = 1;
|
||||
char *bf = p->bf;
|
||||
while (num / d >= p->base)
|
||||
d *= p->base;
|
||||
while (d != 0) {
|
||||
int dgt = num / d;
|
||||
num %= d;
|
||||
d /= p->base;
|
||||
if (n || dgt > 0 || d == 0) {
|
||||
*bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*bf = 0;
|
||||
}
|
||||
|
||||
static void li2a(long num, struct param *p)
|
||||
{
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
p->sign = '-';
|
||||
}
|
||||
uli2a(num, p);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void ui2a(unsigned int num, struct param *p)
|
||||
{
|
||||
int n = 0;
|
||||
unsigned int d = 1;
|
||||
char *bf = p->bf;
|
||||
while (num / d >= p->base)
|
||||
d *= p->base;
|
||||
while (d != 0) {
|
||||
int dgt = num / d;
|
||||
num %= d;
|
||||
d /= p->base;
|
||||
if (n || dgt > 0 || d == 0) {
|
||||
*bf++ = dgt + (dgt < 10 ? '0' : (p->uc ? 'A' : 'a') - 10);
|
||||
++n;
|
||||
}
|
||||
}
|
||||
*bf = 0;
|
||||
}
|
||||
|
||||
static void i2a(int num, struct param *p)
|
||||
{
|
||||
if (num < 0) {
|
||||
num = -num;
|
||||
p->sign = '-';
|
||||
}
|
||||
ui2a(num, p);
|
||||
}
|
||||
|
||||
static int a2d(char ch)
|
||||
{
|
||||
if (ch >= '0' && ch <= '9')
|
||||
return ch - '0';
|
||||
else if (ch >= 'a' && ch <= 'f')
|
||||
return ch - 'a' + 10;
|
||||
else if (ch >= 'A' && ch <= 'F')
|
||||
return ch - 'A' + 10;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
|
||||
static char a2u(char ch, const char **src, int base, int *nump)
|
||||
{
|
||||
const char *p = *src;
|
||||
int num = 0;
|
||||
int digit;
|
||||
while ((digit = a2d(ch)) >= 0) {
|
||||
if (digit > base)
|
||||
break;
|
||||
num = num * base + digit;
|
||||
ch = *p++;
|
||||
}
|
||||
*src = p;
|
||||
*nump = num;
|
||||
return ch;
|
||||
}
|
||||
|
||||
static void putchw(void *putp, putcf putf, struct param *p)
|
||||
{
|
||||
char ch;
|
||||
int n = p->width;
|
||||
char *bf = p->bf;
|
||||
|
||||
/* Number of filling characters */
|
||||
while (*bf++ && n > 0)
|
||||
n--;
|
||||
if (p->sign)
|
||||
n--;
|
||||
if (p->alt && p->base == 16)
|
||||
n -= 2;
|
||||
else if (p->alt && p->base == 8)
|
||||
n--;
|
||||
|
||||
/* Fill with space to align to the right, before alternate or sign */
|
||||
if (!p->lz && !p->align_left) {
|
||||
while (n-- > 0)
|
||||
putf(putp, ' ');
|
||||
}
|
||||
|
||||
/* print sign */
|
||||
if (p->sign)
|
||||
putf(putp, p->sign);
|
||||
|
||||
/* Alternate */
|
||||
if (p->alt && p->base == 16) {
|
||||
putf(putp, '0');
|
||||
putf(putp, (p->uc ? 'X' : 'x'));
|
||||
} else if (p->alt && p->base == 8) {
|
||||
putf(putp, '0');
|
||||
}
|
||||
|
||||
/* Fill with zeros, after alternate or sign */
|
||||
if (p->lz) {
|
||||
while (n-- > 0)
|
||||
putf(putp, '0');
|
||||
}
|
||||
|
||||
/* Put actual buffer */
|
||||
bf = p->bf;
|
||||
while ((ch = *bf++))
|
||||
putf(putp, ch);
|
||||
|
||||
/* Fill with space to align to the left, after string */
|
||||
if (!p->lz && p->align_left) {
|
||||
while (n-- > 0)
|
||||
putf(putp, ' ');
|
||||
}
|
||||
}
|
||||
|
||||
void tfp_format(void *putp, putcf putf, const char *fmt, va_list va)
|
||||
{
|
||||
struct param p;
|
||||
double fval;
|
||||
int temp_buffer[16];
|
||||
int fpart;
|
||||
int fiter;
|
||||
int ffactor;
|
||||
int sign;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
char bf[23]; /* long = 64b on some architectures */
|
||||
#else
|
||||
char bf[12]; /* int = 32b on some architectures */
|
||||
#endif
|
||||
char ch;
|
||||
p.bf = bf;
|
||||
|
||||
while ((ch = *(fmt++))) {
|
||||
if (ch != '%') {
|
||||
putf(putp, ch);
|
||||
} else {
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
char lng = 0; /* 1 for long, 2 for long long */
|
||||
#endif
|
||||
/* Init parameter struct */
|
||||
p.lz = 0;
|
||||
p.alt = 0;
|
||||
p.width = 0;
|
||||
p.align_left = 0;
|
||||
p.sign = 0;
|
||||
p.prec = TINY_PRINTF_FP_PRECISION;
|
||||
|
||||
/* Flags */
|
||||
while ((ch = *(fmt++))) {
|
||||
switch (ch) {
|
||||
case '-':
|
||||
p.align_left = 1;
|
||||
continue;
|
||||
case '0':
|
||||
p.lz = 1;
|
||||
continue;
|
||||
case '#':
|
||||
p.alt = 1;
|
||||
continue;
|
||||
case '+':
|
||||
p.sign = 1;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Width */
|
||||
if (ch >= '0' && ch <= '9') {
|
||||
ch = a2u(ch, &fmt, 10, &(p.width));
|
||||
}
|
||||
|
||||
/* We accept 'x.y' format but don't support it completely:
|
||||
* we ignore the 'y' digit => this ignores 0-fill
|
||||
* size and makes it == width (ie. 'x') */
|
||||
if (ch == '.') {
|
||||
//p.lz = 1; /* zero-padding */
|
||||
/* ignore actual 0-fill size: */
|
||||
ch = *(fmt++);
|
||||
if (ch >= '0' && ch <= '9')
|
||||
p.prec = ch - '0';
|
||||
do
|
||||
{
|
||||
ch = *(fmt++);
|
||||
} while (ch >= '0' && ch <= '9');
|
||||
|
||||
}
|
||||
|
||||
#ifdef PRINTF_SIZE_T_SUPPORT
|
||||
# ifdef PRINTF_LONG_SUPPORT
|
||||
if (ch == 'z') {
|
||||
ch = *(fmt++);
|
||||
if (sizeof(size_t) == sizeof(unsigned long int))
|
||||
lng = 1;
|
||||
# ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
else if (sizeof(size_t) == sizeof(unsigned long long int))
|
||||
lng = 2;
|
||||
# endif
|
||||
} else
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
if (ch == 'l') {
|
||||
ch = *(fmt++);
|
||||
lng = 1;
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (ch == 'l') {
|
||||
ch = *(fmt++);
|
||||
lng = 2;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
switch (ch) {
|
||||
case 0:
|
||||
goto abort;
|
||||
case 'u':
|
||||
p.base = 10;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (2 == lng)
|
||||
ulli2a(va_arg(va, unsigned long long int), &p);
|
||||
else
|
||||
#endif
|
||||
if (1 == lng)
|
||||
uli2a(va_arg(va, unsigned long int), &p);
|
||||
else
|
||||
#endif
|
||||
ui2a(va_arg(va, unsigned int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
case 'd':
|
||||
case 'i':
|
||||
p.base = 10;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (2 == lng)
|
||||
lli2a(va_arg(va, long long int), &p);
|
||||
else
|
||||
#endif
|
||||
if (1 == lng)
|
||||
li2a(va_arg(va, long int), &p);
|
||||
else
|
||||
#endif
|
||||
i2a(va_arg(va, int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
#ifdef SIZEOF_POINTER
|
||||
case 'p':
|
||||
p.alt = 1;
|
||||
# if defined(SIZEOF_INT) && SIZEOF_POINTER <= SIZEOF_INT
|
||||
lng = 0;
|
||||
# elif defined(SIZEOF_LONG) && SIZEOF_POINTER <= SIZEOF_LONG
|
||||
lng = 1;
|
||||
# elif defined(SIZEOF_LONG_LONG) && SIZEOF_POINTER <= SIZEOF_LONG_LONG
|
||||
lng = 2;
|
||||
# endif
|
||||
#endif
|
||||
case 'x':
|
||||
case 'X':
|
||||
p.base = 16;
|
||||
p.uc = (ch == 'X')?1:0;
|
||||
#ifdef PRINTF_LONG_SUPPORT
|
||||
#ifdef PRINTF_LONG_LONG_SUPPORT
|
||||
if (2 == lng)
|
||||
ulli2a(va_arg(va, unsigned long long int), &p);
|
||||
else
|
||||
#endif
|
||||
if (1 == lng)
|
||||
uli2a(va_arg(va, unsigned long int), &p);
|
||||
else
|
||||
#endif
|
||||
ui2a(va_arg(va, unsigned int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
case 'o':
|
||||
p.base = 8;
|
||||
ui2a(va_arg(va, unsigned int), &p);
|
||||
putchw(putp, putf, &p);
|
||||
break;
|
||||
case 'c':
|
||||
putf(putp, (char)(va_arg(va, int)));
|
||||
break;
|
||||
case 's':
|
||||
p.bf = va_arg(va, char *);
|
||||
putchw(putp, putf, &p);
|
||||
p.bf = bf;
|
||||
break;
|
||||
case '%':
|
||||
putf(putp, ch);
|
||||
break;
|
||||
case 'f':
|
||||
case 'F':
|
||||
fval = va_arg(va, double);
|
||||
sign = 0;
|
||||
if (fval < 0)
|
||||
{
|
||||
sign = 1;
|
||||
p.width--;
|
||||
fval = - fval;
|
||||
}
|
||||
else if (p.sign) {
|
||||
sign = 2;
|
||||
p.width--;
|
||||
}
|
||||
|
||||
fpart = (int)fval;
|
||||
|
||||
fiter = 0;
|
||||
while (fpart != 0)
|
||||
{
|
||||
temp_buffer[fiter++] = fpart % 10;
|
||||
fpart = fpart / 10;
|
||||
|
||||
}
|
||||
fiter--;
|
||||
if (fiter == -1)
|
||||
p.width--;
|
||||
/* Leading zeros */
|
||||
if (p.lz) {
|
||||
|
||||
if (sign == 1)
|
||||
putf(putp, '-');
|
||||
else if (sign == 2)
|
||||
putf(putp, '+');
|
||||
|
||||
while (p.width-- > p.prec + fiter + 2)
|
||||
{
|
||||
putf(putp, '0');
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
while (p.width-- > p.prec + fiter + 2)
|
||||
{
|
||||
putf(putp, ' ');
|
||||
}
|
||||
|
||||
if (sign == 1)
|
||||
putf(putp, '-');
|
||||
else if (sign == 2)
|
||||
putf(putp, '+');
|
||||
|
||||
}
|
||||
|
||||
if (fiter == -1)
|
||||
putf(putp, '0');
|
||||
while (fiter > -1)
|
||||
{
|
||||
putf(putp, '0' + (temp_buffer[fiter--]));
|
||||
}
|
||||
|
||||
putf(putp, '.');
|
||||
ffactor = 1;
|
||||
while (p.prec-- > 0)
|
||||
{
|
||||
ffactor *= 10;
|
||||
fpart = (int)((fval - (int)fval)*ffactor);
|
||||
if (fpart == 0)
|
||||
putf(putp, '0');
|
||||
}
|
||||
fiter = 0;
|
||||
while (fpart != 0)
|
||||
{
|
||||
temp_buffer[fiter++] = fpart % 10;
|
||||
fpart = fpart / 10;
|
||||
|
||||
}
|
||||
fiter--;
|
||||
while (fiter > -1)
|
||||
{
|
||||
putf(putp, '0' + (temp_buffer[fiter--]));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
abort:;
|
||||
}
|
||||
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_PRINTF
|
||||
static putcf stdout_putf;
|
||||
static void *stdout_putp;
|
||||
|
||||
void init_printf(void *putp, putcf putf)
|
||||
{
|
||||
stdout_putf = putf;
|
||||
stdout_putp = putp;
|
||||
}
|
||||
|
||||
void tfp_printf(char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
tfp_format(stdout_putp, stdout_putf, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
struct _vsnprintf_putcf_data
|
||||
{
|
||||
size_t dest_capacity;
|
||||
char *dest;
|
||||
size_t num_chars;
|
||||
};
|
||||
|
||||
static void _vsnprintf_putcf(void *p, char c)
|
||||
{
|
||||
struct _vsnprintf_putcf_data *data = (struct _vsnprintf_putcf_data*)p;
|
||||
if (data->num_chars < data->dest_capacity)
|
||||
data->dest[data->num_chars] = c;
|
||||
data->num_chars ++;
|
||||
}
|
||||
|
||||
int tfp_vsnprintf(char *str, size_t size, const char *format, va_list ap)
|
||||
{
|
||||
struct _vsnprintf_putcf_data data;
|
||||
|
||||
data.dest = str;
|
||||
data.dest_capacity = size ? size - 1 : 0;
|
||||
data.num_chars = 0;
|
||||
tfp_format(&data, _vsnprintf_putcf, format, ap);
|
||||
|
||||
if (data.num_chars < data.dest_capacity)
|
||||
data.dest[data.num_chars] = '\0';
|
||||
else if (size)
|
||||
data.dest[data.dest_capacity] = '\0';
|
||||
|
||||
return data.num_chars;
|
||||
}
|
||||
|
||||
int tfp_snprintf(char *str, size_t size, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int retval;
|
||||
|
||||
va_start(ap, format);
|
||||
retval = tfp_vsnprintf(str, size, format, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
struct _vsprintf_putcf_data
|
||||
{
|
||||
char *dest;
|
||||
size_t num_chars;
|
||||
};
|
||||
|
||||
static void _vsprintf_putcf(void *p, char c)
|
||||
{
|
||||
struct _vsprintf_putcf_data *data = (struct _vsprintf_putcf_data*)p;
|
||||
data->dest[data->num_chars++] = c;
|
||||
}
|
||||
|
||||
int tfp_vsprintf(char *str, const char *format, va_list ap)
|
||||
{
|
||||
struct _vsprintf_putcf_data data;
|
||||
data.dest = str;
|
||||
data.num_chars = 0;
|
||||
tfp_format(&data, _vsprintf_putcf, format, ap);
|
||||
data.dest[data.num_chars] = '\0';
|
||||
return data.num_chars;
|
||||
}
|
||||
|
||||
int tfp_sprintf(char *str, const char *format, ...)
|
||||
{
|
||||
va_list ap;
|
||||
int retval;
|
||||
|
||||
va_start(ap, format);
|
||||
retval = tfp_vsprintf(str, format, ap);
|
||||
va_end(ap);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int tfp_vsscanf(const char* str, const char* format, va_list ap)
|
||||
{
|
||||
int value, tmp;
|
||||
float fvalue;
|
||||
double Fvalue;
|
||||
int count = 0;
|
||||
int pos;
|
||||
char neg, fmt_code;
|
||||
|
||||
for (count = 0; *format != 0 && *str != 0; format++, str++)
|
||||
{
|
||||
while (*format == ' ' && *format != 0) format++;
|
||||
|
||||
if (*format == 0)
|
||||
break;
|
||||
|
||||
while (*str == ' ' && *str != 0) str++;
|
||||
|
||||
if (*str == 0)
|
||||
break;
|
||||
|
||||
if (*format == '%')
|
||||
{
|
||||
format++;
|
||||
if (*format == 'n')
|
||||
{
|
||||
if (str[0] == '0' && (str[1] == 'x' || str[1] == 'X'))
|
||||
{
|
||||
fmt_code = 'x';
|
||||
str += 2;
|
||||
}
|
||||
else
|
||||
if (str[0] == 'b')
|
||||
{
|
||||
fmt_code = 'b';
|
||||
str++;
|
||||
}
|
||||
else
|
||||
fmt_code = 'd';
|
||||
}
|
||||
else
|
||||
fmt_code = *format;
|
||||
|
||||
switch (fmt_code)
|
||||
{
|
||||
case 'x':
|
||||
case 'X':
|
||||
for (value = 0, pos = 0; *str != 0; str++, pos++)
|
||||
{
|
||||
if ('0' <= *str && *str <= '9')
|
||||
tmp = *str - '0';
|
||||
else
|
||||
if ('a' <= *str && *str <= 'f')
|
||||
tmp = *str - 'a' + 10;
|
||||
else
|
||||
if ('A' <= *str && *str <= 'F')
|
||||
tmp = *str - 'A' + 10;
|
||||
else
|
||||
break;
|
||||
|
||||
value *= 16;
|
||||
value += tmp;
|
||||
}
|
||||
if (pos == 0)
|
||||
return count;
|
||||
*(va_arg(ap, int*)) = value;
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 'b':
|
||||
for (value = 0, pos = 0; *str != 0; str++, pos++)
|
||||
{
|
||||
if (*str != '0' && *str != '1')
|
||||
break;
|
||||
|
||||
value *= 2;
|
||||
value += *str - '0';
|
||||
}
|
||||
|
||||
if (pos == 0)
|
||||
return count;
|
||||
|
||||
*(va_arg(ap, int*)) = value;
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (*str == '-')
|
||||
{
|
||||
neg = 1;
|
||||
str++;
|
||||
}
|
||||
else
|
||||
neg = 0;
|
||||
for (value = 0, pos = 0; *str != 0; str++, pos++)
|
||||
{
|
||||
if ('0' <= *str && *str <= '9')
|
||||
value = value*10 + (int)(*str - '0');
|
||||
else
|
||||
break;
|
||||
}
|
||||
if (pos == 0)
|
||||
return count;
|
||||
*(va_arg(ap, int*)) = neg ? -value : value;
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 'f':
|
||||
if (*str == '-')
|
||||
{
|
||||
neg = 1;
|
||||
str++;
|
||||
}
|
||||
else
|
||||
neg = 0;
|
||||
|
||||
int point_flag = 0;
|
||||
int exp = 0;
|
||||
for (fvalue = 0, pos = 0; *str != 0 ; str++, pos++)
|
||||
{
|
||||
if (*str == '.')
|
||||
{
|
||||
point_flag = 1;
|
||||
str++;
|
||||
}
|
||||
if ('0' <= *str && *str <= '9')
|
||||
fvalue = fvalue*10 + (int)(*str - '0');
|
||||
else
|
||||
break;
|
||||
|
||||
if (point_flag == 1)
|
||||
exp++;
|
||||
|
||||
}
|
||||
|
||||
if (pos == 0)
|
||||
return count;
|
||||
|
||||
for (pos = 0; pos < exp; pos++)
|
||||
fvalue = fvalue/10.0;
|
||||
|
||||
*(va_arg(ap, float*)) = neg ? -fvalue : fvalue;
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 'F':
|
||||
if (*str == '-')
|
||||
{
|
||||
neg = 1;
|
||||
str++;
|
||||
}
|
||||
else
|
||||
neg = 0;
|
||||
|
||||
int Fpoint_flag = 0;
|
||||
int Fexp = 0;
|
||||
for (Fvalue = 0, pos = 0; *str != 0 ; str++, pos++)
|
||||
{
|
||||
|
||||
if (*str == '.')
|
||||
{
|
||||
Fpoint_flag = 1;
|
||||
str++;
|
||||
}
|
||||
if ('0' <= *str && *str <= '9')
|
||||
Fvalue = Fvalue*10 + (int)(*str - '0');
|
||||
else
|
||||
break;
|
||||
|
||||
if (Fpoint_flag == 1)
|
||||
Fexp++;
|
||||
|
||||
}
|
||||
|
||||
if (pos == 0)
|
||||
return count;
|
||||
for (pos = 0; pos < Fexp; pos++)
|
||||
Fvalue = Fvalue/10.0;
|
||||
*(va_arg(ap, double*)) = neg ? -Fvalue : Fvalue;
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 'c':
|
||||
*(va_arg(ap, char*)) = *str;
|
||||
count++;
|
||||
break;
|
||||
|
||||
case 's':
|
||||
pos = 0;
|
||||
char* tab = va_arg(ap, char*);
|
||||
while (*str != ' ' && *str != 0)
|
||||
*(tab++) = *str++;
|
||||
*tab = 0;
|
||||
count++;
|
||||
break;
|
||||
|
||||
default:
|
||||
return count;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*format != *str)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
204
tinystdio/tinystdio.h
Normal file
204
tinystdio/tinystdio.h
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
File: tinyprintf.h
|
||||
|
||||
Copyright (C) 2004 Kustaa Nyholm
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
This library is really just two files: 'tinyprintf.h' and 'tinyprintf.c'.
|
||||
|
||||
They provide a simple and small (+400 loc) printf functionality to
|
||||
be used in embedded systems.
|
||||
|
||||
I've found them so useful in debugging that I do not bother with a
|
||||
debugger at all.
|
||||
|
||||
They are distributed in source form, so to use them, just compile them
|
||||
into your project.
|
||||
|
||||
Two printf variants are provided: printf and the 'sprintf' family of
|
||||
functions ('snprintf', 'sprintf', 'vsnprintf', 'vsprintf').
|
||||
|
||||
The formats supported by this implementation are:
|
||||
'c' 'd' 'i' 'o' 'p' 'u' 's' 'x' 'X'.
|
||||
|
||||
Zero padding and field width are also supported.
|
||||
|
||||
If the library is compiled with 'PRINTF_SUPPORT_LONG' defined, then
|
||||
the long specifier is also supported. Note that this will pull in some
|
||||
long math routines (pun intended!) and thus make your executable
|
||||
noticeably longer. Likewise with 'PRINTF_LONG_LONG_SUPPORT' for the
|
||||
long long specifier, and with 'PRINTF_SIZE_T_SUPPORT' for the size_t
|
||||
specifier.
|
||||
|
||||
The memory footprint of course depends on the target CPU, compiler and
|
||||
compiler options, but a rough guesstimate (based on a H8S target) is about
|
||||
1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.
|
||||
Not too bad. Your mileage may vary. By hacking the source code you can
|
||||
get rid of some hundred bytes, I'm sure, but personally I feel the balance of
|
||||
functionality and flexibility versus code size is close to optimal for
|
||||
many embedded systems.
|
||||
|
||||
To use the printf, you need to supply your own character output function,
|
||||
something like :
|
||||
|
||||
void putc ( void* p, char c)
|
||||
{
|
||||
while (!SERIAL_PORT_EMPTY) ;
|
||||
SERIAL_PORT_TX_REGISTER = c;
|
||||
}
|
||||
|
||||
Before you can call printf, you need to initialize it to use your
|
||||
character output function with something like:
|
||||
|
||||
init_printf(NULL,putc);
|
||||
|
||||
Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',
|
||||
the NULL (or any pointer) you pass into the 'init_printf' will eventually be
|
||||
passed to your 'putc' routine. This allows you to pass some storage space (or
|
||||
anything really) to the character output function, if necessary.
|
||||
This is not often needed but it was implemented like that because it made
|
||||
implementing the sprintf function so neat (look at the source code).
|
||||
|
||||
The code is re-entrant, except for the 'init_printf' function, so it is safe
|
||||
to call it from interrupts too, although this may result in mixed output.
|
||||
If you rely on re-entrancy, take care that your 'putc' function is re-entrant!
|
||||
|
||||
The printf and sprintf functions are actually macros that translate to
|
||||
'tfp_printf' and 'tfp_sprintf' when 'TINYPRINTF_OVERRIDE_LIBC' is set
|
||||
(default). Setting it to 0 makes it possible to use them along with
|
||||
'stdio.h' printf's in a single source file. When
|
||||
'TINYPRINTF_OVERRIDE_LIBC' is set, please note that printf/sprintf are
|
||||
not function-like macros, so if you have variables or struct members
|
||||
with these names, things will explode in your face. Without variadic
|
||||
macros this is the best we can do to wrap these function. If it is a
|
||||
problem, just give up the macros and use the functions directly, or
|
||||
rename them.
|
||||
|
||||
It is also possible to avoid defining tfp_printf and/or tfp_sprintf by
|
||||
clearing 'TINYPRINTF_DEFINE_TFP_PRINTF' and/or
|
||||
'TINYPRINTF_DEFINE_TFP_SPRINTF' to 0. This allows for example to
|
||||
export only tfp_format, which is at the core of all the other
|
||||
functions.
|
||||
|
||||
For further details see source code.
|
||||
|
||||
regs Kusti, 23.10.2004
|
||||
|
||||
|
||||
31.01.2015
|
||||
Update from Cebotari Vladislav
|
||||
cebotari.vladislav@gmail.com
|
||||
|
||||
- Added floating point support with different precision in x.y format
|
||||
also with leading zeros possibility (like standard printf function).
|
||||
Floating point printf is tested on tiva launchpad (tm4c123gh6pm TI mcu)
|
||||
- Also vsscanf for floats and double %f - float, %F - double
|
||||
|
||||
*/
|
||||
|
||||
#ifndef __TFP_PRINTF__
|
||||
#define __TFP_PRINTF__
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Global configuration */
|
||||
|
||||
|
||||
/* Set this to 0 if you do not want to provide tfp_printf */
|
||||
#ifndef TINYPRINTF_DEFINE_TFP_PRINTF
|
||||
# define TINYPRINTF_DEFINE_TFP_PRINTF 0
|
||||
#endif
|
||||
|
||||
/* Set this to 0 if you do not want to provide
|
||||
tfp_sprintf/snprintf/vsprintf/vsnprintf */
|
||||
#ifndef TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
# define TINYPRINTF_DEFINE_TFP_SPRINTF 1
|
||||
#endif
|
||||
|
||||
/* Set this to 0 if you do not want tfp_printf and
|
||||
tfp_{vsn,sn,vs,s}printf to be also available as
|
||||
printf/{vsn,sn,vs,s}printf */
|
||||
#ifndef TINYPRINTF_OVERRIDE_LIBC
|
||||
# define TINYPRINTF_OVERRIDE_LIBC 1
|
||||
#endif
|
||||
|
||||
# define TINY_PRINTF_FP_PRECISION 6
|
||||
|
||||
/* Optional external types dependencies */
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
# include <sys/types.h> /* size_t */
|
||||
#endif
|
||||
|
||||
/* Declarations */
|
||||
|
||||
#ifdef __GNUC__
|
||||
# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx) \
|
||||
__attribute__((format (printf, fmt_idx, arg1_idx)))
|
||||
#else
|
||||
# define _TFP_SPECIFY_PRINTF_FMT(fmt_idx,arg1_idx)
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef void (*putcf) (void *, char);
|
||||
|
||||
/*
|
||||
'tfp_format' really is the central function for all tinyprintf. For
|
||||
each output character after formatting, the 'putf' callback is
|
||||
called with 2 args:
|
||||
- an arbitrary void* 'putp' param defined by the user and
|
||||
passed unmodified from 'tfp_format',
|
||||
- the character.
|
||||
The 'tfp_printf' and 'tfp_sprintf' functions simply define their own
|
||||
callback and pass to it the right 'putp' it is expecting.
|
||||
*/
|
||||
void tfp_format(void *putp, putcf putf, const char *fmt, va_list va);
|
||||
# if TINYPRINTF_OVERRIDE_LIBC
|
||||
# define tfp_vsscanf vsscanf
|
||||
# endif
|
||||
int tfp_vsscanf(const char* str, const char* format, va_list va);
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_SPRINTF
|
||||
# if TINYPRINTF_OVERRIDE_LIBC
|
||||
# define tfp_vsnprintf vsnprintf
|
||||
# define tfp_snprintf snprintf
|
||||
# define tfp_vsprintf vsprintf
|
||||
# define tfp_sprintf sprintf
|
||||
# endif
|
||||
int tfp_vsnprintf(char *str, size_t size, const char *fmt, va_list ap);
|
||||
int tfp_snprintf(char *str, size_t size, const char *fmt, ...) \
|
||||
_TFP_SPECIFY_PRINTF_FMT(3, 4);
|
||||
int tfp_vsprintf(char *str, const char *fmt, va_list ap);
|
||||
int tfp_sprintf(char *str, const char *fmt, ...) \
|
||||
_TFP_SPECIFY_PRINTF_FMT(2, 3);
|
||||
#endif
|
||||
|
||||
#if TINYPRINTF_DEFINE_TFP_PRINTF
|
||||
# if TINYPRINTF_OVERRIDE_LIBC
|
||||
# define tfp_printf printf
|
||||
# endif
|
||||
void init_printf(void *putp, putcf putf);
|
||||
void tfp_printf(char *fmt, ...) _TFP_SPECIFY_PRINTF_FMT(1, 2);
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user