- 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