- Replace global errno variable with __errno_location function - Add complete strerror implementation for standard error codes - Implement perror function for error message output - Move strlen implementation to separate string.c file - Update getcwd to use new errno macro instead of direct variable - Mark getcwd as weak symbol to allow overriding - Remove unimplemented strerror stub from assembly file - Add 128-bit integer helpers from compiler-rt builtins - Update third-party dependencies with detailed documentation - Improve curl download scripts with silentmaster
parent
78d6d2b67b
commit
ce13f7d2c7
24 changed files with 236 additions and 454 deletions
@ -0,0 +1,47 @@ |
|||||||
|
#include <errno.h> |
||||||
|
#include <stddef.h> |
||||||
|
#include <stdio.h> |
||||||
|
#include <string.h> |
||||||
|
#include <unistd.h> |
||||||
|
|
||||||
|
static int typephp_os_errno; |
||||||
|
static char unknown_error[] = "Unknown error"; |
||||||
|
|
||||||
|
int *__errno_location(void) |
||||||
|
{ |
||||||
|
return &typephp_os_errno; |
||||||
|
} |
||||||
|
|
||||||
|
char *strerror(int error) |
||||||
|
{ |
||||||
|
switch (error) { |
||||||
|
case ENOENT: return "No such file or directory"; |
||||||
|
case EIO: return "Input/output error"; |
||||||
|
case ENOEXEC: return "Exec format error"; |
||||||
|
case EBADF: return "Bad file descriptor"; |
||||||
|
case ENOMEM: return "Cannot allocate memory"; |
||||||
|
case EACCES: return "Permission denied"; |
||||||
|
case EFAULT: return "Bad address"; |
||||||
|
case EEXIST: return "File exists"; |
||||||
|
case ENOTDIR: return "Not a directory"; |
||||||
|
case EISDIR: return "Is a directory"; |
||||||
|
case EINVAL: return "Invalid argument"; |
||||||
|
case EMFILE: return "Too many open files"; |
||||||
|
case EROFS: return "Read-only file system"; |
||||||
|
case ERANGE: return "Numerical result out of range"; |
||||||
|
case ENAMETOOLONG: return "File name too long"; |
||||||
|
case ENOSYS: return "Function not implemented"; |
||||||
|
case ENOTEMPTY: return "Directory not empty"; |
||||||
|
default: return unknown_error; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void perror(const char *prefix) |
||||||
|
{ |
||||||
|
if (prefix != NULL && prefix[0] != '\0') { |
||||||
|
(void) write(STDERR_FILENO, prefix, strlen(prefix)); |
||||||
|
(void) write(STDERR_FILENO, ": ", 2); |
||||||
|
} |
||||||
|
(void) write(STDERR_FILENO, strerror(errno), strlen(strerror(errno))); |
||||||
|
(void) write(STDERR_FILENO, "\n", 1); |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
#include <stddef.h> |
||||||
|
|
||||||
|
size_t strlen(const char *string) |
||||||
|
{ |
||||||
|
const char *end = string; |
||||||
|
while (*end != '\0') { |
||||||
|
++end; |
||||||
|
} |
||||||
|
return (size_t) (end - string); |
||||||
|
} |
||||||
@ -1,23 +0,0 @@ |
|||||||
.section .text |
|
||||||
.code64 |
|
||||||
|
|
||||||
.global _start
|
|
||||||
.type _start, @function
|
|
||||||
.extern main
|
|
||||||
.extern _exit
|
|
||||||
_start: |
|
||||||
# Linux-compatible process entry stack: |
|
||||||
# argc, argv[], NULL, envp[], NULL, auxv[] |
|
||||||
xor %ebp, %ebp |
|
||||||
mov (%rsp), %rdi |
|
||||||
lea 8(%rsp), %rsi |
|
||||||
lea 16(%rsp,%rdi,8), %rdx |
|
||||||
and $-16, %rsp |
|
||||||
call main |
|
||||||
|
|
||||||
mov %eax, %edi |
|
||||||
call _exit |
|
||||||
ud2 |
|
||||||
.size _start, . - _start |
|
||||||
|
|
||||||
.section .note.GNU-stack, "", @progbits
|
|
||||||
@ -1,295 +0,0 @@ |
|||||||
#include <errno.h> |
|
||||||
#include <fcntl.h> |
|
||||||
#include <stddef.h> |
|
||||||
#include <stdarg.h> |
|
||||||
#include <stdio.h> |
|
||||||
#include <string.h> |
|
||||||
#include <sys/syscall.h> |
|
||||||
#include <sys/stat.h> |
|
||||||
#include <sys/mman.h> |
|
||||||
#include <sys/time.h> |
|
||||||
#include <sys/utsname.h> |
|
||||||
#include <time.h> |
|
||||||
#include <unistd.h> |
|
||||||
|
|
||||||
int errno; |
|
||||||
|
|
||||||
static char unknown_error[] = "Unknown error"; |
|
||||||
|
|
||||||
size_t strlen(const char *string) |
|
||||||
{ |
|
||||||
size_t length = 0; |
|
||||||
while (string[length] != '\0') { |
|
||||||
++length; |
|
||||||
} |
|
||||||
return length; |
|
||||||
} |
|
||||||
|
|
||||||
char *strerror(int error) |
|
||||||
{ |
|
||||||
switch (error) { |
|
||||||
case ENOENT: return "No such file or directory"; |
|
||||||
case EIO: return "Input/output error"; |
|
||||||
case ENOEXEC: return "Exec format error"; |
|
||||||
case EBADF: return "Bad file descriptor"; |
|
||||||
case ENOMEM: return "Cannot allocate memory"; |
|
||||||
case EACCES: return "Permission denied"; |
|
||||||
case EFAULT: return "Bad address"; |
|
||||||
case EEXIST: return "File exists"; |
|
||||||
case ENOTDIR: return "Not a directory"; |
|
||||||
case EISDIR: return "Is a directory"; |
|
||||||
case EINVAL: return "Invalid argument"; |
|
||||||
case EMFILE: return "Too many open files"; |
|
||||||
case EROFS: return "Read-only file system"; |
|
||||||
case ERANGE: return "Numerical result out of range"; |
|
||||||
case ENAMETOOLONG: return "File name too long"; |
|
||||||
case ENOSYS: return "Function not implemented"; |
|
||||||
case ENOTEMPTY: return "Directory not empty"; |
|
||||||
default: return unknown_error; |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
void perror(const char *prefix) |
|
||||||
{ |
|
||||||
if (prefix != NULL && prefix[0] != '\0') { |
|
||||||
(void) write(STDERR_FILENO, prefix, strlen(prefix)); |
|
||||||
(void) write(STDERR_FILENO, ": ", 2); |
|
||||||
} |
|
||||||
(void) write(STDERR_FILENO, strerror(errno), strlen(strerror(errno))); |
|
||||||
(void) write(STDERR_FILENO, "\n", 1); |
|
||||||
} |
|
||||||
|
|
||||||
ssize_t read(int fd, void *buffer, size_t count) |
|
||||||
{ |
|
||||||
return (ssize_t) syscall(SYS_read, fd, buffer, count); |
|
||||||
} |
|
||||||
|
|
||||||
ssize_t write(int fd, const void *buffer, size_t count) |
|
||||||
{ |
|
||||||
return (ssize_t) syscall(SYS_write, fd, buffer, count); |
|
||||||
} |
|
||||||
|
|
||||||
int close(int fd) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_close, fd); |
|
||||||
} |
|
||||||
|
|
||||||
off_t lseek(int fd, off_t offset, int whence) |
|
||||||
{ |
|
||||||
return (off_t) syscall(SYS_lseek, fd, offset, whence); |
|
||||||
} |
|
||||||
|
|
||||||
int openat(int directory_fd, const char *path, int flags, ...) |
|
||||||
{ |
|
||||||
int mode = 0; |
|
||||||
if ((flags & O_CREAT) != 0) { |
|
||||||
va_list arguments; |
|
||||||
va_start(arguments, flags); |
|
||||||
mode = va_arg(arguments, int); |
|
||||||
va_end(arguments); |
|
||||||
} |
|
||||||
return (int) syscall(SYS_openat, directory_fd, path, flags, mode); |
|
||||||
} |
|
||||||
|
|
||||||
int open(const char *path, int flags, ...) |
|
||||||
{ |
|
||||||
int mode = 0; |
|
||||||
if ((flags & O_CREAT) != 0) { |
|
||||||
va_list arguments; |
|
||||||
va_start(arguments, flags); |
|
||||||
mode = va_arg(arguments, int); |
|
||||||
va_end(arguments); |
|
||||||
} |
|
||||||
return openat(AT_FDCWD, path, flags, mode); |
|
||||||
} |
|
||||||
|
|
||||||
int chdir(const char *path) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_chdir, path); |
|
||||||
} |
|
||||||
|
|
||||||
int mkdir(const char *path, mode_t mode) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_mkdir, path, mode); |
|
||||||
} |
|
||||||
|
|
||||||
int unlink(const char *path) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_unlink, path); |
|
||||||
} |
|
||||||
|
|
||||||
int rmdir(const char *path) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_rmdir, path); |
|
||||||
} |
|
||||||
|
|
||||||
int rename(const char *old_path, const char *new_path) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_typephp_rename, old_path, new_path); |
|
||||||
} |
|
||||||
|
|
||||||
int access(const char *path, int mode) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_access, path, mode); |
|
||||||
} |
|
||||||
|
|
||||||
int stat(const char *path, struct stat *value) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_stat, path, value); |
|
||||||
} |
|
||||||
|
|
||||||
int lstat(const char *path, struct stat *value) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_lstat, path, value); |
|
||||||
} |
|
||||||
|
|
||||||
int fstat(int fd, struct stat *value) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_fstat, fd, value); |
|
||||||
} |
|
||||||
|
|
||||||
int fstatat(int directory_fd, const char *path, struct stat *value, int flags) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_newfstatat, directory_fd, path, value, flags); |
|
||||||
} |
|
||||||
|
|
||||||
int faccessat(int directory_fd, const char *path, int mode, int flags) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_faccessat, directory_fd, path, mode, flags); |
|
||||||
} |
|
||||||
|
|
||||||
int fsync(int fd) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_fsync, fd); |
|
||||||
} |
|
||||||
|
|
||||||
int fdatasync(int fd) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_fdatasync, fd); |
|
||||||
} |
|
||||||
|
|
||||||
int truncate(const char *path, off_t length) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_truncate, path, length); |
|
||||||
} |
|
||||||
|
|
||||||
int ftruncate(int fd, off_t length) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_ftruncate, fd, length); |
|
||||||
} |
|
||||||
|
|
||||||
int brk(void *address) |
|
||||||
{ |
|
||||||
long result = syscall(SYS_brk, address); |
|
||||||
if ((void *) result != address) { |
|
||||||
errno = ENOMEM; |
|
||||||
return -1; |
|
||||||
} |
|
||||||
return 0; |
|
||||||
} |
|
||||||
|
|
||||||
void *sbrk(intptr_t increment) |
|
||||||
{ |
|
||||||
intptr_t current = syscall(SYS_brk, 0); |
|
||||||
intptr_t requested; |
|
||||||
if ((increment > 0 && current > INTPTR_MAX - increment) |
|
||||||
|| (increment < 0 && current < INTPTR_MIN - increment)) { |
|
||||||
errno = ENOMEM; |
|
||||||
return (void *) -1; |
|
||||||
} |
|
||||||
requested = current + increment; |
|
||||||
if (increment != 0 && syscall(SYS_brk, requested) != requested) { |
|
||||||
errno = ENOMEM; |
|
||||||
return (void *) -1; |
|
||||||
} |
|
||||||
return (void *) current; |
|
||||||
} |
|
||||||
|
|
||||||
void *mmap(void *address, size_t length, int protection, int flags, int fd, long offset) |
|
||||||
{ |
|
||||||
return (void *) syscall(SYS_mmap, |
|
||||||
address, length, protection, flags, fd, offset); |
|
||||||
} |
|
||||||
|
|
||||||
int mprotect(void *address, size_t length, int protection) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_mprotect, address, length, protection); |
|
||||||
} |
|
||||||
|
|
||||||
int munmap(void *address, size_t length) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_munmap, address, length); |
|
||||||
} |
|
||||||
|
|
||||||
char *getcwd(char *buffer, size_t size) |
|
||||||
{ |
|
||||||
return syscall(SYS_getcwd, buffer, size) < 0 ? NULL : buffer; |
|
||||||
} |
|
||||||
|
|
||||||
time_t time(time_t *result) |
|
||||||
{ |
|
||||||
return (time_t) syscall(SYS_time, result); |
|
||||||
} |
|
||||||
|
|
||||||
int gettimeofday(struct timeval *value, void *timezone) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_gettimeofday, value, timezone); |
|
||||||
} |
|
||||||
|
|
||||||
int clock_gettime(clockid_t clock_id, struct timespec *value) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_clock_gettime, clock_id, value); |
|
||||||
} |
|
||||||
|
|
||||||
int clock_getres(clockid_t clock_id, struct timespec *value) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_clock_getres, clock_id, value); |
|
||||||
} |
|
||||||
|
|
||||||
pid_t getpid(void) |
|
||||||
{ |
|
||||||
return (pid_t) syscall(SYS_getpid); |
|
||||||
} |
|
||||||
|
|
||||||
pid_t getppid(void) |
|
||||||
{ |
|
||||||
return (pid_t) syscall(SYS_getppid); |
|
||||||
} |
|
||||||
|
|
||||||
pid_t gettid(void) |
|
||||||
{ |
|
||||||
return (pid_t) syscall(SYS_gettid); |
|
||||||
} |
|
||||||
|
|
||||||
uid_t getuid(void) |
|
||||||
{ |
|
||||||
return (uid_t) syscall(SYS_getuid); |
|
||||||
} |
|
||||||
|
|
||||||
uid_t geteuid(void) |
|
||||||
{ |
|
||||||
return (uid_t) syscall(SYS_geteuid); |
|
||||||
} |
|
||||||
|
|
||||||
gid_t getgid(void) |
|
||||||
{ |
|
||||||
return (gid_t) syscall(SYS_getgid); |
|
||||||
} |
|
||||||
|
|
||||||
gid_t getegid(void) |
|
||||||
{ |
|
||||||
return (gid_t) syscall(SYS_getegid); |
|
||||||
} |
|
||||||
|
|
||||||
int uname(struct utsname *value) |
|
||||||
{ |
|
||||||
return (int) syscall(SYS_uname, value); |
|
||||||
} |
|
||||||
|
|
||||||
void _exit(int status) |
|
||||||
{ |
|
||||||
(void) syscall(SYS_exit_group, status); |
|
||||||
for (;;) { |
|
||||||
__asm__ volatile("pause"); |
|
||||||
} |
|
||||||
} |
|
||||||
@ -1,24 +0,0 @@ |
|||||||
OUTPUT_FORMAT(elf64-x86-64) |
|
||||||
OUTPUT_ARCH(i386:x86-64) |
|
||||||
ENTRY(_start) |
|
||||||
|
|
||||||
PHDRS |
|
||||||
{ |
|
||||||
text PT_LOAD FILEHDR PHDRS FLAGS(5); |
|
||||||
data PT_LOAD FLAGS(6); |
|
||||||
stack PT_GNU_STACK FLAGS(6); |
|
||||||
} |
|
||||||
|
|
||||||
SECTIONS |
|
||||||
{ |
|
||||||
. = USER_BASE + SIZEOF_HEADERS; |
|
||||||
|
|
||||||
.text : { *(.text .text.*) } :text |
|
||||||
.rodata : { *(.rodata .rodata.*) } :text |
|
||||||
|
|
||||||
. = ALIGN(4K); |
|
||||||
.data : { *(.data .data.*) } :data |
|
||||||
.bss (NOLOAD) : { *(COMMON) *(.bss .bss.*) } :data |
|
||||||
|
|
||||||
/DISCARD/ : { *(.comment) *(.eh_frame*) *(.note*) } |
|
||||||
} |
|
||||||
@ -1,28 +0,0 @@ |
|||||||
.section .text |
|
||||||
.code64 |
|
||||||
|
|
||||||
.global syscall
|
|
||||||
.type syscall, @function
|
|
||||||
syscall: |
|
||||||
# Translate the System V function-call ABI used by glibc's syscall(2) |
|
||||||
# wrapper into the Linux x86-64 syscall register ABI. The temporary |
|
||||||
# kernel entry is int 0x80; replacing it with `syscall` will not change
|
|
||||||
# the C-visible contract. |
|
||||||
mov %rdi, %rax |
|
||||||
mov %rsi, %rdi |
|
||||||
mov %rdx, %rsi |
|
||||||
mov %rcx, %rdx |
|
||||||
mov %r8, %r10 |
|
||||||
mov %r9, %r8 |
|
||||||
mov 8(%rsp), %r9 |
|
||||||
int $0x80 |
|
||||||
cmp $-4095, %rax |
|
||||||
jb 1f |
|
||||||
neg %eax |
|
||||||
mov %eax, errno(%rip) |
|
||||||
mov $-1, %rax |
|
||||||
1: |
|
||||||
ret |
|
||||||
.size syscall, . - syscall |
|
||||||
|
|
||||||
.section .note.GNU-stack, "", @progbits
|
|
||||||
Loading…
Reference in new issue