mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-06-28 07:18:30 +00:00
Add x86_64-linux-gnu emulator
I wanted a tiny scriptable meltdown proof way to run userspace programs and visualize how program execution impacts memory. It helps to explain how things like Actually Portable Executable works. It can show you how the GCC generated code is going about manipulating matrices and more. I didn't feel fully comfortable with Qemu and Bochs because I'm not smart enough to understand them. I wanted something like gVisor but with much stronger levels of assurances. I wanted a single binary that'll run, on all major operating systems with an embedded GPL barrier ZIP filesystem that is tiny enough to transpile to JavaScript and run in browsers too. https://justine.storage.googleapis.com/emulator625.mp4
This commit is contained in:
parent
467504308a
commit
f4f4caab0e
1052 changed files with 65667 additions and 7825 deletions
|
@ -48,7 +48,3 @@ OVERVIEW
|
|||
be compared to something more along the lines of, "the Russians
|
||||
just used a pencil to write in space", versus spending millions
|
||||
researching a pen like NASA.
|
||||
|
||||
One cost worth noting, concerning stateless API translation, is
|
||||
file descriptors needed to change from `int` to `int64_t`, thus
|
||||
requiring a certain degree of added care when porting software.
|
||||
|
|
|
@ -18,9 +18,8 @@ void qsort(void *, size_t, size_t, int (*)(const void *, const void *))
|
|||
void qsort_r(void *, size_t, size_t,
|
||||
int cmp(const void *, const void *, void *), void *arg)
|
||||
paramsnonnull((1, 4));
|
||||
int tarjan(uint32_t, const uint32_t (*)[2], uint32_t, uint32_t[], uint32_t[],
|
||||
uint32_t *) paramsnonnull((2, 4)) nocallback nothrow;
|
||||
void heapsortcar(int32_t (*)[2], unsigned) paramsnonnull() nocallback nothrow;
|
||||
int tarjan(int, const int (*)[2], int, int[], int[], int *)
|
||||
paramsnonnull((2, 4)) nocallback nothrow;
|
||||
|
||||
void *memmem(const void *, size_t, const void *, size_t)
|
||||
paramsnonnull() nothrow nocallback nosideeffect;
|
||||
|
|
|
@ -19,6 +19,11 @@ COSMOPOLITAN_C_START_
|
|||
size_t SizE = sizeof(*Item); \
|
||||
size_t Count = (COUNT); \
|
||||
ssize_t Entry = -1; \
|
||||
/* NOTE: We use `<` to guarantee one additional slot */ \
|
||||
/* grow() will memset(0) extended memory, thus */ \
|
||||
/* you get a nul-terminator for free sometimes */ \
|
||||
/* the exception is if you list.i=0 and re-use */ \
|
||||
/* so you need concat(...); list.p[list.i++]=0 */ \
|
||||
if (*ListI + Count < *ListN || grow(ListP, ListN, SizE, Count)) { \
|
||||
memcpy(&(*ListP)[*ListI], Item, (SizE) * (Count)); \
|
||||
Entry = *ListI; \
|
||||
|
|
|
@ -71,25 +71,25 @@ static void cycle(size_t width, unsigned char *ar[], size_t n) {
|
|||
|
||||
forceinline void shl(unsigned p[2], size_t n) {
|
||||
assert(n > 0);
|
||||
if (n >= 8 * sizeof(unsigned)) {
|
||||
n -= 8 * sizeof(unsigned);
|
||||
if (n >= CHAR_BIT * sizeof(unsigned)) {
|
||||
n -= CHAR_BIT * sizeof(unsigned);
|
||||
p[1] = p[0];
|
||||
p[0] = 0;
|
||||
}
|
||||
p[1] <<= n;
|
||||
p[1] |= p[0] >> (sizeof(unsigned) * 8 - n);
|
||||
p[1] |= p[0] >> (sizeof(unsigned) * CHAR_BIT - n);
|
||||
p[0] <<= n;
|
||||
}
|
||||
|
||||
forceinline void shr(unsigned p[2], size_t n) {
|
||||
assert(n > 0);
|
||||
if (n >= 8 * sizeof(unsigned)) {
|
||||
n -= 8 * sizeof(unsigned);
|
||||
if (n >= CHAR_BIT * sizeof(unsigned)) {
|
||||
n -= CHAR_BIT * sizeof(unsigned);
|
||||
p[0] = p[1];
|
||||
p[1] = 0;
|
||||
}
|
||||
p[0] >>= n;
|
||||
p[0] |= p[1] << (sizeof(unsigned) * 8 - n);
|
||||
p[0] |= p[1] << (sizeof(unsigned) * CHAR_BIT - n);
|
||||
p[1] >>= n;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,9 @@
|
|||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#undef strlen
|
||||
#undef replacestr
|
||||
#define replacestr replacestr16
|
||||
#define char char16_t
|
||||
#define strlen strlen16
|
||||
#include "libc/alg/replacestr.c"
|
||||
|
|
|
@ -19,8 +19,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/alg.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/mem/mem.h"
|
||||
|
||||
/**
|
||||
|
@ -33,79 +33,77 @@
|
|||
* topological sorting as a byproduct.” ──D.E. Knuth
|
||||
*/
|
||||
|
||||
struct Vertex {
|
||||
uint32_t Vi;
|
||||
uint32_t Ei;
|
||||
uint32_t index;
|
||||
uint32_t lowlink;
|
||||
bool onstack;
|
||||
bool selfreferential;
|
||||
};
|
||||
|
||||
struct TarjanStack {
|
||||
size_t i;
|
||||
size_t n;
|
||||
uint32_t *p;
|
||||
};
|
||||
|
||||
struct Tarjan {
|
||||
uint32_t Vn;
|
||||
uint32_t En;
|
||||
struct Vertex *V;
|
||||
const uint32_t (*E)[2];
|
||||
uint32_t *R;
|
||||
uint32_t *C;
|
||||
uint32_t Ci;
|
||||
uint32_t Ri;
|
||||
uint32_t index;
|
||||
struct TarjanStack S;
|
||||
int Vn, En, Ci, Ri, *R, *C, index;
|
||||
const int (*E)[2];
|
||||
struct Vertex {
|
||||
int Vi;
|
||||
int Ei;
|
||||
int index;
|
||||
int lowlink;
|
||||
bool onstack;
|
||||
bool selfreferential;
|
||||
} * V;
|
||||
struct TarjanStack {
|
||||
int i;
|
||||
int n;
|
||||
int *p;
|
||||
} S;
|
||||
};
|
||||
|
||||
static uint32_t TarjanPush(struct TarjanStack *st, uint32_t Vi) {
|
||||
if (st->i < st->n || grow(&st->p, &st->n, sizeof(uint32_t), 0)) {
|
||||
return (st->p[st->i++] = Vi);
|
||||
} else {
|
||||
return -1;
|
||||
static bool TarjanPush(struct Tarjan *t, int v) {
|
||||
int *q;
|
||||
assert(t->S.i >= 0);
|
||||
assert(t->S.n >= 0);
|
||||
assert(0 <= v && v < t->Vn);
|
||||
if (t->S.i == t->S.n) {
|
||||
if ((q = realloc(t->S.p, (t->S.n + (t->S.n >> 1) + 8) * sizeof(*t->S.p)))) {
|
||||
t->S.p = q;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
t->S.p[t->S.i++] = v;
|
||||
return true;
|
||||
}
|
||||
|
||||
static uint32_t TarjanPop(struct TarjanStack *st) {
|
||||
assert(st->i != 0);
|
||||
return st->p[--st->i];
|
||||
static int TarjanPop(struct Tarjan *t) {
|
||||
assert(t->S.i > 0);
|
||||
return t->S.p[--t->S.i];
|
||||
}
|
||||
|
||||
static int TarjanConnect(struct Tarjan **tj, uint32_t Vi) {
|
||||
struct Vertex *v = &(*tj)->V[Vi];
|
||||
v->index = (*tj)->index;
|
||||
v->lowlink = (*tj)->index;
|
||||
v->onstack = true;
|
||||
(*tj)->index++;
|
||||
if (TarjanPush(&(*tj)->S, Vi) == -1) return -1;
|
||||
uint32_t fs = (*tj)->V[Vi].Ei;
|
||||
static bool TarjanConnect(struct Tarjan *t, int v) {
|
||||
int fs, w, e;
|
||||
assert(0 <= v && v < t->Vn);
|
||||
t->V[v].index = t->index;
|
||||
t->V[v].lowlink = t->index;
|
||||
t->V[v].onstack = true;
|
||||
t->index++;
|
||||
if (!TarjanPush(t, v)) return false;
|
||||
fs = t->V[v].Ei;
|
||||
if (fs != -1) {
|
||||
for (uint32_t Ei = fs; Ei < (*tj)->En && Vi == (*tj)->E[Ei][0]; ++Ei) {
|
||||
struct Vertex *w = &(*tj)->V[(*tj)->E[Ei][1]];
|
||||
if (!w->index) {
|
||||
if (TarjanConnect(tj, w->Vi) == -1) return -1;
|
||||
v->lowlink = min(v->lowlink, w->lowlink);
|
||||
} else if (w->onstack) {
|
||||
v->lowlink = min(v->lowlink, w->index);
|
||||
for (e = fs; e < t->En && v == t->E[e][0]; ++e) {
|
||||
w = t->E[e][1];
|
||||
if (!t->V[w].index) {
|
||||
if (!TarjanConnect(t, t->V[w].Vi)) return false;
|
||||
t->V[v].lowlink = MIN(t->V[v].lowlink, t->V[w].lowlink);
|
||||
} else if (t->V[w].onstack) {
|
||||
t->V[v].lowlink = MIN(t->V[v].lowlink, t->V[w].index);
|
||||
}
|
||||
if (w == v) {
|
||||
w->selfreferential = true;
|
||||
t->V[w].selfreferential = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (v->lowlink == v->index) {
|
||||
struct Vertex *w;
|
||||
if (t->V[v].lowlink == t->V[v].index) {
|
||||
do {
|
||||
w = &(*tj)->V[TarjanPop(&(*tj)->S)];
|
||||
w->onstack = false;
|
||||
(*tj)->R[(*tj)->Ri++] = w->Vi;
|
||||
w = TarjanPop(t);
|
||||
t->V[w].onstack = false;
|
||||
t->R[t->Ri++] = t->V[w].Vi;
|
||||
} while (w != v);
|
||||
if ((*tj)->C) (*tj)->C[(*tj)->Ci++] = (*tj)->Ri;
|
||||
if (t->C) t->C[t->Ci++] = t->Ri;
|
||||
}
|
||||
return 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,51 +131,53 @@ static int TarjanConnect(struct Tarjan **tj, uint32_t Vi) {
|
|||
* @error ENOMEM
|
||||
* @note Tarjan's Algorithm is O(|V|+|E|)
|
||||
*/
|
||||
int tarjan(uint32_t vertex_count, const uint32_t (*edges)[2],
|
||||
uint32_t edge_count, uint32_t out_sorted[],
|
||||
uint32_t out_opt_components[], uint32_t *out_opt_componentcount) {
|
||||
assert(edge_count <= INT_MAX);
|
||||
assert(vertex_count <= INT_MAX);
|
||||
for (unsigned i = 0; i < edge_count; ++i) {
|
||||
int tarjan(int vertex_count, const int (*edges)[2], int edge_count,
|
||||
int out_sorted[], int out_opt_components[],
|
||||
int *out_opt_componentcount) {
|
||||
int i, rc, v, e;
|
||||
struct Tarjan *t;
|
||||
assert(0 <= edge_count && edge_count <= INT_MAX);
|
||||
assert(0 <= vertex_count && vertex_count <= INT_MAX);
|
||||
for (i = 0; i < edge_count; ++i) {
|
||||
if (i) assert(edges[i - 1][0] <= edges[i][0]);
|
||||
assert(edges[i][0] < vertex_count);
|
||||
assert(edges[i][1] < vertex_count);
|
||||
}
|
||||
int rc;
|
||||
struct Tarjan *tj;
|
||||
if ((tj = calloc(1, (sizeof(struct Tarjan) +
|
||||
if (!(t = calloc(1, (sizeof(struct Tarjan) +
|
||||
sizeof(struct Vertex) * vertex_count)))) {
|
||||
tj->V = (struct Vertex *)((char *)tj + sizeof(struct Tarjan));
|
||||
tj->Vn = vertex_count;
|
||||
tj->E = edges;
|
||||
tj->En = edge_count;
|
||||
tj->R = out_sorted;
|
||||
tj->C = out_opt_components;
|
||||
tj->index = 1;
|
||||
uint32_t Vi, Ei;
|
||||
for (Vi = 0; Vi < tj->Vn; ++Vi) {
|
||||
tj->V[Vi].Vi = Vi;
|
||||
tj->V[Vi].Ei = -1u;
|
||||
}
|
||||
for (Ei = 0, Vi = -1u; Ei < tj->En; ++Ei) {
|
||||
if (tj->E[Ei][0] == Vi) continue;
|
||||
Vi = tj->E[Ei][0];
|
||||
tj->V[Vi].Ei = Ei;
|
||||
}
|
||||
rc = 0;
|
||||
for (Vi = 0; Vi < tj->Vn; ++Vi) {
|
||||
if (!tj->V[Vi].index) {
|
||||
if ((rc = TarjanConnect(&tj, Vi)) == -1) {
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
t->V = (struct Vertex *)((char *)t + sizeof(struct Tarjan));
|
||||
t->Vn = vertex_count;
|
||||
t->E = edges;
|
||||
t->En = edge_count;
|
||||
t->R = out_sorted;
|
||||
t->C = out_opt_components;
|
||||
t->index = 1;
|
||||
for (v = 0; v < t->Vn; ++v) {
|
||||
t->V[v].Vi = v;
|
||||
t->V[v].Ei = -1;
|
||||
}
|
||||
for (e = 0, v = -1; e < t->En; ++e) {
|
||||
if (t->E[e][0] == v) continue;
|
||||
v = t->E[e][0];
|
||||
t->V[v].Ei = e;
|
||||
}
|
||||
rc = 0;
|
||||
for (v = 0; v < t->Vn; ++v) {
|
||||
if (!t->V[v].index) {
|
||||
if (!TarjanConnect(t, v)) {
|
||||
free(t->S.p);
|
||||
free(t);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
free(tj->S.p);
|
||||
assert(tj->Ri == vertex_count);
|
||||
if (out_opt_components) *out_opt_componentcount = tj->Ci;
|
||||
} else {
|
||||
rc = -1;
|
||||
}
|
||||
free(tj);
|
||||
if (out_opt_components) {
|
||||
*out_opt_componentcount = t->Ci;
|
||||
}
|
||||
assert(t->Ri == vertex_count);
|
||||
free(t->S.p);
|
||||
free(t);
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/bswap.h"
|
||||
|
||||
uint32_t(bitreverse32)(uint32_t x) {
|
||||
x = bswap_32(x);
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/bswap.h"
|
||||
|
||||
uint64_t bitreverse64(uint64_t x) {
|
||||
x = bswap_64(x);
|
||||
|
|
112
libc/bits/bits.h
112
libc/bits/bits.h
|
@ -13,9 +13,6 @@ extern const bool kTrue;
|
|||
extern const bool kFalse;
|
||||
extern const uint8_t kReverseBits[256];
|
||||
|
||||
uint16_t bswap_16(uint16_t) pureconst;
|
||||
uint32_t bswap_32(uint32_t) pureconst;
|
||||
uint32_t bswap_64(uint32_t) pureconst;
|
||||
uint32_t gray(uint32_t) pureconst;
|
||||
uint32_t ungray(uint32_t) pureconst;
|
||||
unsigned bcdadd(unsigned, unsigned) pureconst;
|
||||
|
@ -157,16 +154,6 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
#define ABOVEFLAG_ASM(OP) OP "\n\tseta\t%b0"
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Reads scalar from memory, offset by segment.
|
||||
*
|
||||
* @return *(MEM) relative to segment
|
||||
* @see arch_prctl()
|
||||
* @see pushpop()
|
||||
*/
|
||||
#define fs(MEM) __peek("fs", MEM)
|
||||
#define gs(MEM) __peek("gs", MEM)
|
||||
|
||||
/**
|
||||
* Reads scalar from memory w/ one operation.
|
||||
*
|
||||
|
@ -374,115 +361,16 @@ unsigned long hamming(unsigned long, unsigned long) pureconst;
|
|||
#define invlpg(MEM) \
|
||||
asm volatile("invlpg\t(%0)" : /* no outputs */ : "r"(MEM) : "memory")
|
||||
|
||||
/**
|
||||
* Teleports code fragment inside _init().
|
||||
*/
|
||||
#define INITIALIZER(PRI, NAME, CODE) \
|
||||
asm(".pushsection .init." #PRI "." #NAME ",\"ax\",@progbits\n\t" \
|
||||
"call\t" #NAME "\n\t" \
|
||||
".popsection"); \
|
||||
textstartup optimizesize void NAME(char *rdi, const char *rsi) { \
|
||||
CODE; \
|
||||
asm volatile("" : /* no outputs */ : "D"(rdi), "S"(rsi)); \
|
||||
}
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
#if __PIC__ + __code_model_medium__ + __code_model_large__ + 0 > 1
|
||||
#define __EZLEA(SYMBOL) "lea\t" SYMBOL "(%%rip),%"
|
||||
#else
|
||||
#define __EZLEA(SYMBOL) "mov\t$" SYMBOL ",%k"
|
||||
#endif
|
||||
#define weaken(symbol) ((const typeof(&(symbol)))weakaddr(#symbol))
|
||||
#define strongaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(__EZLEA(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
#define weakaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(".weak\t" symbolstr "\n\t" __EZLEA(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
#else
|
||||
#define weaken(symbol) symbol
|
||||
#define weakaddr(symbolstr) &(symbolstr)
|
||||
#endif
|
||||
|
||||
#define slowcall(fn, arg1, arg2, arg3, arg4, arg5, arg6) \
|
||||
({ \
|
||||
void *ax; \
|
||||
asm volatile("push\t%7\n\t" \
|
||||
"push\t%6\n\t" \
|
||||
"push\t%5\n\t" \
|
||||
"push\t%4\n\t" \
|
||||
"push\t%3\n\t" \
|
||||
"push\t%2\n\t" \
|
||||
"push\t%1\n\t" \
|
||||
"call\tslowcall" \
|
||||
: "=a"(ax) \
|
||||
: "g"(fn), "g"(arg1), "g"(arg2), "g"(arg3), "g"(arg4), \
|
||||
"g"(arg5), "g"(arg6) \
|
||||
: "memory"); \
|
||||
ax; \
|
||||
})
|
||||
|
||||
#define IsAddressCanonicalForm(P) \
|
||||
({ \
|
||||
intptr_t p2 = (intptr_t)(P); \
|
||||
(0xffff800000000000l <= p2 && p2 <= 0x00007fffffffffffl); \
|
||||
})
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § bits » optimizations ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#define bswap_16(U16) \
|
||||
(isconstant(U16) ? ((((U16)&0xff00) >> 010) | (((U16)&0x00ff) << 010)) : ({ \
|
||||
uint16_t Swapped16, Werd16 = (U16); \
|
||||
asm("xchg\t%b0,%h0" : "=Q"(Swapped16) : "0"(Werd16)); \
|
||||
Swapped16; \
|
||||
}))
|
||||
|
||||
#define bswap_32(U32) \
|
||||
(isconstant(U32) \
|
||||
? ((((U32)&0xff000000) >> 030) | (((U32)&0x000000ff) << 030) | \
|
||||
(((U32)&0x00ff0000) >> 010) | (((U32)&0x0000ff00) << 010)) \
|
||||
: ({ \
|
||||
uint32_t Swapped32, Werd32 = (U32); \
|
||||
asm("bswap\t%0" : "=r"(Swapped32) : "0"(Werd32)); \
|
||||
Swapped32; \
|
||||
}))
|
||||
|
||||
#define bswap_64(U64) \
|
||||
(isconstant(U64) ? ((((U64)&0xff00000000000000ul) >> 070) | \
|
||||
(((U64)&0x00000000000000fful) << 070) | \
|
||||
(((U64)&0x00ff000000000000ul) >> 050) | \
|
||||
(((U64)&0x000000000000ff00ul) << 050) | \
|
||||
(((U64)&0x0000ff0000000000ul) >> 030) | \
|
||||
(((U64)&0x0000000000ff0000ul) << 030) | \
|
||||
(((U64)&0x000000ff00000000ul) >> 010) | \
|
||||
(((U64)&0x00000000ff000000ul) << 010)) \
|
||||
: ({ \
|
||||
uint64_t Swapped64, Werd64 = (U64); \
|
||||
asm("bswap\t%0" : "=r"(Swapped64) : "0"(Werd64)); \
|
||||
Swapped64; \
|
||||
}))
|
||||
|
||||
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § bits » implementation details ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
#define __peek(SEGMENT, ADDRESS) \
|
||||
({ \
|
||||
typeof(*(ADDRESS)) Pk; \
|
||||
asm("mov\t%%" SEGMENT ":%1,%0" : "=r"(Pk) : "m"(*(ADDRESS))); \
|
||||
Pk; \
|
||||
})
|
||||
|
||||
#define __ArithmeticOp1(OP, MEM) \
|
||||
({ \
|
||||
asm(OP "%z0\t%0" : "+m"(*(MEM)) : /* no inputs */ : "cc"); \
|
||||
|
|
48
libc/bits/bswap.h
Normal file
48
libc/bits/bswap.h
Normal file
|
@ -0,0 +1,48 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_BSWAP_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_BSWAP_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
uint16_t bswap_16(uint16_t) pureconst;
|
||||
uint32_t bswap_32(uint32_t) pureconst;
|
||||
uint32_t bswap_64(uint32_t) pureconst;
|
||||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
|
||||
#define bswap_16(U16) \
|
||||
(isconstant(U16) ? ((((U16)&0xff00) >> 010) | (((U16)&0x00ff) << 010)) : ({ \
|
||||
uint16_t Swapped16, Werd16 = (U16); \
|
||||
asm("xchg\t%b0,%h0" : "=Q"(Swapped16) : "0"(Werd16)); \
|
||||
Swapped16; \
|
||||
}))
|
||||
|
||||
#define bswap_32(U32) \
|
||||
(isconstant(U32) \
|
||||
? ((((U32)&0xff000000) >> 030) | (((U32)&0x000000ff) << 030) | \
|
||||
(((U32)&0x00ff0000) >> 010) | (((U32)&0x0000ff00) << 010)) \
|
||||
: ({ \
|
||||
uint32_t Swapped32, Werd32 = (U32); \
|
||||
asm("bswap\t%0" : "=r"(Swapped32) : "0"(Werd32)); \
|
||||
Swapped32; \
|
||||
}))
|
||||
|
||||
#define bswap_64(U64) \
|
||||
(isconstant(U64) ? ((((U64)&0xff00000000000000ul) >> 070) | \
|
||||
(((U64)&0x00000000000000fful) << 070) | \
|
||||
(((U64)&0x00ff000000000000ul) >> 050) | \
|
||||
(((U64)&0x000000000000ff00ul) << 050) | \
|
||||
(((U64)&0x0000ff0000000000ul) >> 030) | \
|
||||
(((U64)&0x0000000000ff0000ul) << 030) | \
|
||||
(((U64)&0x000000ff00000000ul) >> 010) | \
|
||||
(((U64)&0x00000000ff000000ul) << 010)) \
|
||||
: ({ \
|
||||
uint64_t Swapped64, Werd64 = (U64); \
|
||||
asm("bswap\t%0" : "=r"(Swapped64) : "0"(Werd64)); \
|
||||
Swapped64; \
|
||||
}))
|
||||
|
||||
#endif /* defined(__GNUC__) && !defined(__STRICT_ANSI__) */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_BSWAP_H_ */
|
12
libc/bits/ezlea.h
Normal file
12
libc/bits/ezlea.h
Normal file
|
@ -0,0 +1,12 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_EZLEA_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_EZLEA_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
#if __pic__ + __pie__ + __code_model_medium__ + __code_model_large__ + 0 > 1
|
||||
#define ezlea(symbol) "lea\t" symbol "(%%rip),%"
|
||||
#else
|
||||
#define ezlea(symbol) "mov\t$" symbol ",%k"
|
||||
#endif
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_EZLEA_H_ */
|
18
libc/bits/initializer.h
Normal file
18
libc/bits/initializer.h
Normal file
|
@ -0,0 +1,18 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_INITIALIZER_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_INITIALIZER_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Teleports code fragment inside _init().
|
||||
*/
|
||||
#define INITIALIZER(PRI, NAME, CODE) \
|
||||
asm(".pushsection .init." #PRI "." #NAME ",\"ax\",@progbits\n\t" \
|
||||
"call\t" #NAME "\n\t" \
|
||||
".popsection"); \
|
||||
textstartup optimizesize void NAME(char *rdi, const char *rsi) { \
|
||||
CODE; \
|
||||
asm volatile("" : /* no outputs */ : "D"(rdi), "S"(rsi)); \
|
||||
}
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_INITIALIZER_H_ */
|
|
@ -19,18 +19,13 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/popcnt.h"
|
||||
|
||||
static uint32_t popcnt32(uint32_t x) {
|
||||
x -= (x >> 1) & 0x55555555;
|
||||
x = (x & 0x33333333) + ((x >> 2) & 0x33333333);
|
||||
return (((x + (x >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24;
|
||||
}
|
||||
|
||||
unsigned long(popcnt)(unsigned long x) {
|
||||
unsigned long r;
|
||||
r = 0;
|
||||
while (x) {
|
||||
r += popcnt32(x);
|
||||
x >>= 32;
|
||||
}
|
||||
return r;
|
||||
uint64_t(popcnt)(uint64_t x) {
|
||||
uint32_t r;
|
||||
x = x - ((x >> 1) & 0x5555555555555555);
|
||||
x = ((x >> 2) & 0x3333333333333333) + (x & 0x3333333333333333);
|
||||
x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0f;
|
||||
x = (x + (x >> 32)) & 0xffffffff;
|
||||
x = x + (x >> 16);
|
||||
x = (x + (x >> 8)) & 0x0000007f;
|
||||
return x;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ unsigned long popcnt(unsigned long) pureconst;
|
|||
|
||||
#if defined(__GNUC__) && !defined(__STRICT_ANSI__)
|
||||
#define popcnt(X) \
|
||||
(isconstant(X) ? __builtin_popcount(X) : ({ \
|
||||
(isconstant(X) ? __builtin_popcountll(X) : ({ \
|
||||
unsigned long Res, Pop = (X); \
|
||||
if (X86_HAVE(POPCNT)) { \
|
||||
asm("popcnt\t%1,%0" : "=r"(Res) : "r"(Pop) : "cc"); \
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
#endif
|
||||
|
||||
#if !defined(__GNUC__) || defined(__STRICT_ANSI__)
|
||||
#define pushmov(d, x) ((d) = (x))
|
||||
#define pushmov(d, x) (*(d) = (x))
|
||||
#else
|
||||
#define pushmov(d, x) \
|
||||
({ \
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
long min(long x, long y);
|
||||
long max(long x, long y);
|
||||
long roundup(long w, long k);
|
||||
long rounddown(long w, long k);
|
||||
bool isempty(const char *s);
|
||||
const char *nulltoempty(const char *s);
|
||||
const char *emptytonull(const char *s);
|
||||
const char *firstnonnull(const char *a, const char *b);
|
||||
uint64_t(unsignedsubtract)(uint64_t x, uint64_t y) pureconst;
|
||||
long min(long, long);
|
||||
long max(long, long);
|
||||
long roundup(long, long);
|
||||
long rounddown(long, long);
|
||||
bool isempty(const char *);
|
||||
const char *nulltoempty(const char *);
|
||||
const char *emptytonull(const char *);
|
||||
const char *firstnonnull(const char *, const char *);
|
||||
uint64_t(unsignedsubtract)(uint64_t, uint64_t) pureconst;
|
||||
|
||||
#if !defined(__STRICT_ANSI__) && defined(__GNUC__)
|
||||
|
||||
|
@ -83,4 +84,5 @@ uint64_t(unsignedsubtract)(uint64_t x, uint64_t y) pureconst;
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_SAFEMACROS_H_ */
|
||||
|
|
23
libc/bits/segmentation.h
Normal file
23
libc/bits/segmentation.h
Normal file
|
@ -0,0 +1,23 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_SEGMENTATION_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_SEGMENTATION_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
/**
|
||||
* Reads scalar from memory, offset by segment.
|
||||
*
|
||||
* @return *(MEM) relative to segment
|
||||
* @see arch_prctl()
|
||||
* @see pushpop()
|
||||
*/
|
||||
#define fs(MEM) __peek("fs", MEM)
|
||||
#define gs(MEM) __peek("gs", MEM)
|
||||
|
||||
#define __peek(SEGMENT, ADDRESS) \
|
||||
({ \
|
||||
typeof(*(ADDRESS)) Pk; \
|
||||
asm("mov\t%%" SEGMENT ":%1,%0" : "=r"(Pk) : "m"(*(ADDRESS))); \
|
||||
Pk; \
|
||||
})
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_SEGMENTATION_H_ */
|
28
libc/bits/weaken.h
Normal file
28
libc/bits/weaken.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_BITS_WEAKEN_H_
|
||||
#define COSMOPOLITAN_LIBC_BITS_WEAKEN_H_
|
||||
#include "libc/bits/ezlea.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
#ifndef __STRICT_ANSI__
|
||||
|
||||
#define weaken(symbol) ((const typeof(&(symbol)))weakaddr(#symbol))
|
||||
|
||||
#define strongaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(ezlea(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
|
||||
#define weakaddr(symbolstr) \
|
||||
({ \
|
||||
intptr_t waddr; \
|
||||
asm(".weak\t" symbolstr "\n\t" ezlea(symbolstr) "0" : "=r"(waddr)); \
|
||||
waddr; \
|
||||
})
|
||||
|
||||
#else
|
||||
#define weaken(symbol) symbol
|
||||
#define weakaddr(symbolstr) &(symbolstr)
|
||||
#endif /* __STRICT_ANSI__ */
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_BITS_WEAKEN_H_ */
|
|
@ -81,20 +81,19 @@ bool isregularfile(const char *);
|
|||
bool32 isatty(int) nosideeffect;
|
||||
bool32 ischardev(int) nosideeffect;
|
||||
char *get_current_dir_name(void) nodiscard;
|
||||
char *getcwd(char *, size_t) paramsnonnull();
|
||||
char *getcwd(char *, size_t);
|
||||
char *realpath(const char *, char *);
|
||||
char *replaceuser(const char *) nodiscard;
|
||||
char *slurp(const char *, size_t *) nodiscard;
|
||||
char *ttyname(int);
|
||||
const char *commandv(const char *);
|
||||
int access(const char *, int) nothrow paramsnonnull();
|
||||
int access(const char *, int) nothrow;
|
||||
int arch_prctl();
|
||||
int chdir(const char *) paramsnonnull();
|
||||
int chdir(const char *);
|
||||
int chmod(const char *, uint32_t);
|
||||
int chown(const char *, uint32_t, uint32_t) paramsnonnull();
|
||||
int chown(const char *, uint32_t, uint32_t);
|
||||
int close(int);
|
||||
int closedir(DIR *);
|
||||
int copyfile(const char *, const char *, bool);
|
||||
int creat(const char *, uint32_t) nodiscard;
|
||||
int dirfd(DIR *);
|
||||
int dup(int) nodiscard;
|
||||
|
@ -119,7 +118,7 @@ int fdatasync(int);
|
|||
int filecmp(const char *, const char *);
|
||||
int flock(int, int);
|
||||
int fork(void);
|
||||
int fstat(int, struct stat *) paramsnonnull();
|
||||
int fstat(int, struct stat *);
|
||||
int fstatat(int, const char *, struct stat *, uint32_t);
|
||||
int fsync(int);
|
||||
int ftruncate(int, int64_t);
|
||||
|
@ -131,7 +130,7 @@ int kill(int, int);
|
|||
int killpg(int, int);
|
||||
int link(const char *, const char *) nothrow;
|
||||
int linkat(int, const char *, int, const char *, uint32_t);
|
||||
int lstat(const char *, struct stat *) paramsnonnull();
|
||||
int lstat(const char *, struct stat *);
|
||||
int madvise(void *, uint64_t, int);
|
||||
int mkdir(const char *, uint32_t);
|
||||
int mkdirat(int, const char *, uint32_t);
|
||||
|
@ -141,7 +140,7 @@ int mknodat(int, const char *, int32_t, uint64_t);
|
|||
int mlock(const void *, size_t);
|
||||
int mlock2(const void *, size_t, int);
|
||||
int mlockall(int);
|
||||
int mprotect(void *, uint64_t, int) paramsnonnull() privileged;
|
||||
int mprotect(void *, uint64_t, int) privileged;
|
||||
int msync(void *, size_t, int);
|
||||
int munlock(const void *, size_t);
|
||||
int munlockall(void);
|
||||
|
@ -150,11 +149,11 @@ int munmap_s(void *, uint64_t);
|
|||
int nice(int);
|
||||
int open(const char *, int, ...) nodiscard;
|
||||
int openanon(char *, unsigned) nodiscard;
|
||||
int openat();
|
||||
int openat(int, const char *, int, ...);
|
||||
int pause(void);
|
||||
int personality(uint64_t);
|
||||
int pipe(int[hasatleast 2]) paramsnonnull() nodiscard;
|
||||
int pipe2(int[hasatleast 2], int) paramsnonnull() nodiscard;
|
||||
int pipe(int[hasatleast 2]) nodiscard;
|
||||
int pipe2(int[hasatleast 2], int) nodiscard;
|
||||
int posix_fadvise(int, uint64_t, uint64_t, int);
|
||||
int posix_fallocate(int, int64_t, int64_t);
|
||||
int posix_madvise(void *, uint64_t, int);
|
||||
|
@ -184,7 +183,7 @@ int sigaction(int, const struct sigaction *, struct sigaction *);
|
|||
int sigignore(int);
|
||||
int sigprocmask(int, const struct sigset *, struct sigset *);
|
||||
int sigsuspend(const struct sigset *);
|
||||
int stat(const char *, struct stat *) paramsnonnull();
|
||||
int stat(const char *, struct stat *);
|
||||
int symlink(const char *, const char *);
|
||||
int symlinkat(const char *, int, const char *);
|
||||
int sync_file_range(int, int64_t, int64_t, unsigned);
|
||||
|
@ -230,7 +229,7 @@ uint32_t gettid(void) nosideeffect;
|
|||
uint32_t getuid(void) nosideeffect;
|
||||
uint32_t umask(int32_t);
|
||||
void *getprocaddressmodule(const char *, const char *);
|
||||
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t) vallocesque;
|
||||
void *mmap(void *, uint64_t, int32_t, int32_t, int32_t, int64_t);
|
||||
void *mremap(void *, uint64_t, uint64_t, int32_t, void *);
|
||||
|
||||
#define getcwd(BUF, SIZE) \
|
||||
|
|
|
@ -20,12 +20,14 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Sets current directory.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int chdir(const char *path) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return chdir$sysv(path);
|
||||
} else {
|
||||
|
|
|
@ -45,5 +45,6 @@
|
|||
* @see fchmod()
|
||||
*/
|
||||
int chmod(const char *pathname, uint32_t mode) {
|
||||
if (!pathname) return efault();
|
||||
return fchmodat$sysv(AT_FDCWD, pathname, mode, 0);
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Changes owner and/or group of pathname.
|
||||
|
@ -34,5 +35,6 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int chown(const char *pathname, uint32_t uid, uint32_t gid) {
|
||||
if (!pathname) return efault();
|
||||
return fchownat$sysv(AT_FDCWD, pathname, uid, gid, 0);
|
||||
}
|
||||
|
|
|
@ -17,10 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sock/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/zipos/zipos.h"
|
||||
|
@ -33,7 +32,7 @@
|
|||
*/
|
||||
int close(int fd) {
|
||||
int rc;
|
||||
if (fd == -1) return 0;
|
||||
if (fd == -1) return einval();
|
||||
if (isfdkind(fd, kFdZip)) {
|
||||
rc = weaken(__zipos_close)(
|
||||
(struct ZiposHandle *)(intptr_t)g_fds.p[fd].handle);
|
||||
|
|
|
@ -49,9 +49,9 @@ textwindows int fstat$nt(int64_t handle, struct stat *st) {
|
|||
: (((filetype == kNtFileTypeDisk) ? S_IFBLK : 0) |
|
||||
((filetype == kNtFileTypeChar) ? S_IFCHR : 0) |
|
||||
((filetype == kNtFileTypePipe) ? S_IFIFO : 0))));
|
||||
filetimetotimespec(&st->st_atim, wst.ftLastAccessFileTime);
|
||||
filetimetotimespec(&st->st_mtim, wst.ftLastWriteFileTime);
|
||||
filetimetotimespec(&st->st_ctim, wst.ftCreationFileTime);
|
||||
st->st_atim = filetimetotimespec(wst.ftLastAccessFileTime);
|
||||
st->st_mtim = filetimetotimespec(wst.ftLastWriteFileTime);
|
||||
st->st_ctim = filetimetotimespec(wst.ftCreationFileTime);
|
||||
st->st_size = (uint64_t)wst.nFileSizeHigh << 32 | wst.nFileSizeLow;
|
||||
st->st_blksize = PAGESIZE;
|
||||
st->st_dev = wst.dwVolumeSerialNumber;
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
* Supports fstat(), etc. implementations.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int32_t fstat$sysv(int32_t fd, struct stat *st) {
|
||||
textstartup int32_t fstat$sysv(int32_t fd, struct stat *st) {
|
||||
int res;
|
||||
if ((res = __fstat$sysv(fd, st)) != -1) {
|
||||
stat2linux(st);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -17,18 +17,19 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/initializer.h"
|
||||
#include "libc/bits/pushpop.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/fileno.h"
|
||||
|
||||
STATIC_YOINK("_init_g_fds");
|
||||
|
||||
struct Fds g_fds;
|
||||
|
||||
INITIALIZER(300, _init_g_fds, {
|
||||
void InitializeFileDescriptors(void) {
|
||||
struct Fds *fds;
|
||||
fds = VEIL("D", &g_fds);
|
||||
fds = VEIL("r", &g_fds);
|
||||
pushmov(&fds->f, 3ul);
|
||||
pushmov(&fds->n, ARRAYLEN(fds->__init_p));
|
||||
fds->p = fds->__init_p;
|
||||
|
@ -40,4 +41,4 @@ INITIALIZER(300, _init_g_fds, {
|
|||
GetStdHandle(pushpop(kNtStdOutputHandle));
|
||||
fds->__init_p[STDERR_FILENO].handle =
|
||||
GetStdHandle(pushpop(kNtStdErrorHandle));
|
||||
})
|
||||
}
|
||||
|
|
|
@ -18,16 +18,12 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/macros.h"
|
||||
.source __FILE__
|
||||
|
||||
mapanon:push %rbp
|
||||
mov %rsp,%rbp
|
||||
push %rbx
|
||||
push %rbx
|
||||
ezlea _base,bx
|
||||
call __mapanon
|
||||
pop %rbx
|
||||
pop %rbx
|
||||
pop %rbp
|
||||
ret
|
||||
.endfn mapanon,globl
|
||||
.init.start 300,_init_g_fds
|
||||
push %rdi
|
||||
push %rsi
|
||||
call InitializeFileDescriptors
|
||||
pop %rsi
|
||||
pop %rdi
|
||||
.init.end 300,_init_g_fds
|
||||
.source __FILE__
|
|
@ -35,23 +35,28 @@
|
|||
* @error ERANGE, EINVAL
|
||||
*/
|
||||
char *(getcwd)(char *buf, size_t size) {
|
||||
buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
int olderr = errno;
|
||||
if (getcwd$sysv(buf, size) != NULL) {
|
||||
return buf;
|
||||
} else if (IsXnu() && errno == ENOSYS) {
|
||||
if (size >= 2) {
|
||||
buf[0] = '.'; /* XXX: could put forth more effort */
|
||||
buf[1] = '\0';
|
||||
errno = olderr;
|
||||
if (buf) {
|
||||
buf[0] = '\0';
|
||||
if (!IsWindows()) {
|
||||
int olderr = errno;
|
||||
if (getcwd$sysv(buf, size) != NULL) {
|
||||
return buf;
|
||||
} else {
|
||||
erange();
|
||||
} else if (IsXnu() && errno == ENOSYS) {
|
||||
if (size >= 2) {
|
||||
buf[0] = '.'; /* XXX: could put forth more effort */
|
||||
buf[1] = '\0';
|
||||
errno = olderr;
|
||||
return buf;
|
||||
} else {
|
||||
erange();
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return getcwd$nt(buf, size);
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
return getcwd$nt(buf, size);
|
||||
efault();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,10 +26,13 @@
|
|||
* Returns value of environment variable, or NULL if not found.
|
||||
*/
|
||||
char *getenv(const char *name) {
|
||||
char *empty[1] = {NULL};
|
||||
char **ep = firstnonnull(environ, empty);
|
||||
unsigned namelen = strlen(name);
|
||||
for (int i = 0; ep[i]; ++i) {
|
||||
char **ep;
|
||||
size_t i, namelen;
|
||||
char *empty[1] = {0};
|
||||
ep = environ;
|
||||
if (!ep) ep = empty;
|
||||
namelen = strlen(name);
|
||||
for (i = 0; ep[i]; ++i) {
|
||||
if (strncmp(ep[i], name, namelen) == 0 && ep[i][namelen] == '=') {
|
||||
return &ep[i][namelen + 1];
|
||||
}
|
||||
|
|
45
libc/calls/getrusage-nt.c
Normal file
45
libc/calls/getrusage-nt.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
|
||||
textwindows int getrusage$nt(int who, struct rusage *usage) {
|
||||
struct NtFileTime CreationFileTime;
|
||||
struct NtFileTime ExitFileTime;
|
||||
struct NtFileTime KernelFileTime;
|
||||
struct NtFileTime UserFileTime;
|
||||
memset(usage, 0, sizeof(*usage));
|
||||
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
||||
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
||||
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
|
||||
filetimetotimeval(&usage->ru_utime, UserFileTime);
|
||||
filetimetotimeval(&usage->ru_stime, KernelFileTime);
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
}
|
|
@ -19,35 +19,8 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/rusage.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/accounting.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
#include "libc/nt/thread.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/rusage.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
static textwindows noinline int getrusage$nt(int who, struct rusage *usage) {
|
||||
struct NtFileTime CreationFileTime;
|
||||
struct NtFileTime ExitFileTime;
|
||||
struct NtFileTime KernelFileTime;
|
||||
struct NtFileTime UserFileTime;
|
||||
memset(usage, 0, sizeof(*usage));
|
||||
if ((who == RUSAGE_SELF ? GetProcessTimes : GetThreadTimes)(
|
||||
(who == RUSAGE_SELF ? GetCurrentProcess : GetCurrentThread)(),
|
||||
&CreationFileTime, &ExitFileTime, &KernelFileTime, &UserFileTime)) {
|
||||
filetimetotimeval(&usage->ru_utime, UserFileTime);
|
||||
filetimetotimeval(&usage->ru_stime, KernelFileTime);
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns resource usage statistics.
|
||||
*
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
|
|
@ -17,10 +17,11 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Checks if effective user can access path in particular ways.
|
||||
|
@ -31,6 +32,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int access(const char *path, int mode) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return faccessat$sysv(AT_FDCWD, path, mode, 0);
|
||||
} else {
|
||||
|
|
108
libc/calls/hefty/copyfile.c
Normal file
108
libc/calls/hefty/copyfile.c
Normal file
|
@ -0,0 +1,108 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/hefty/copyfile.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/createfile.h"
|
||||
#include "libc/nt/enum/accessmask.h"
|
||||
#include "libc/nt/enum/creationdisposition.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/nt/runtime.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/madv.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
#include "libc/time/time.h"
|
||||
|
||||
static textwindows int copyfile$nt(const char *src, const char *dst,
|
||||
int flags) {
|
||||
int64_t fhsrc, fhdst;
|
||||
struct NtFileTime accessed, modified;
|
||||
char16_t src16[PATH_MAX], dst16[PATH_MAX];
|
||||
if (mkntpath(src, src16) == -1) return -1;
|
||||
if (mkntpath(dst, dst16) == -1) return -1;
|
||||
if (CopyFile(src16, dst16, !!(flags & COPYFILE_NOCLOBBER))) {
|
||||
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
|
||||
fhsrc = CreateFile(src16, kNtFileReadAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0);
|
||||
fhdst = CreateFile(dst16, kNtFileWriteAttributes, kNtFileShareRead, NULL,
|
||||
kNtOpenExisting, kNtFileAttributeNormal, 0);
|
||||
if (fhsrc != -1 && fhdst != -1) {
|
||||
GetFileTime(fhsrc, NULL, &accessed, &modified);
|
||||
SetFileTime(fhdst, NULL, &accessed, &modified);
|
||||
}
|
||||
CloseHandle(fhsrc);
|
||||
CloseHandle(fhdst);
|
||||
}
|
||||
return 0;
|
||||
} else {
|
||||
return winerr();
|
||||
}
|
||||
}
|
||||
|
||||
static int copyfile$sysv(const char *src, const char *dst, int flags) {
|
||||
struct stat st;
|
||||
size_t remaining;
|
||||
ssize_t transferred;
|
||||
struct timespec amtime[2];
|
||||
int64_t inoffset, outoffset;
|
||||
int rc, srcfd, dstfd, oflags, omode;
|
||||
rc = -1;
|
||||
if ((srcfd = openat$sysv(AT_FDCWD, src, O_RDONLY, 0)) != -1) {
|
||||
if (fstat$sysv(srcfd, &st) != -1) {
|
||||
omode = st.st_mode & 0777;
|
||||
oflags = O_WRONLY | O_CREAT;
|
||||
if (flags & COPYFILE_NOCLOBBER) oflags |= O_EXCL;
|
||||
if ((dstfd = openat$sysv(AT_FDCWD, dst, oflags, omode)) != -1) {
|
||||
remaining = st.st_size;
|
||||
ftruncate(dstfd, remaining);
|
||||
inoffset = 0;
|
||||
outoffset = 0;
|
||||
while (remaining &&
|
||||
(transferred = copy_file_range(
|
||||
srcfd, &inoffset, dstfd, &outoffset, remaining, 0)) != -1) {
|
||||
remaining -= transferred;
|
||||
}
|
||||
if (!remaining) {
|
||||
rc = 0;
|
||||
if (flags & COPYFILE_PRESERVE_TIMESTAMPS) {
|
||||
amtime[0] = st.st_atim;
|
||||
amtime[1] = st.st_mtim;
|
||||
utimensat$sysv(dstfd, NULL, amtime, 0);
|
||||
}
|
||||
}
|
||||
rc |= close$sysv(dstfd);
|
||||
}
|
||||
}
|
||||
rc |= close$sysv(srcfd);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies file.
|
||||
*/
|
||||
int copyfile(const char *src, const char *dst, int flags) {
|
||||
if (!IsWindows()) {
|
||||
return copyfile$sysv(src, dst, flags);
|
||||
} else {
|
||||
return copyfile$nt(src, dst, flags);
|
||||
}
|
||||
}
|
15
libc/calls/hefty/copyfile.h
Normal file
15
libc/calls/hefty/copyfile.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_
|
||||
|
||||
#define COPYFILE_NOCLOBBER 1
|
||||
#define COPYFILE_PRESERVE_OWNER 2
|
||||
#define COPYFILE_PRESERVE_TIMESTAMPS 4
|
||||
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int copyfile(const char *, const char *, int) paramsnonnull();
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_HEFTY_COPYFILE_H_ */
|
30
libc/calls/hefty/faccessat-nt.c
Normal file
30
libc/calls/hefty/faccessat-nt.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/hefty/internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
int faccessat$nt(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (dirfd != AT_FDCWD || flags) return einval();
|
||||
if (mkntpath(path, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
}
|
|
@ -18,6 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/hefty/internal.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
@ -33,12 +34,10 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int faccessat(int dirfd, const char *path, int mode, uint32_t flags) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return faccessat$sysv(dirfd, path, mode, flags);
|
||||
} else {
|
||||
char16_t path16[PATH_MAX];
|
||||
if (dirfd != AT_FDCWD || flags) return einval();
|
||||
if (mkntpath(path, path16) == -1) return -1;
|
||||
return ntaccesscheck(path16, mode);
|
||||
return faccessat$nt(dirfd, path, mode, flags);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,17 +36,18 @@ LIBC_CALLS_HEFTY_A_CHECKS = \
|
|||
|
||||
LIBC_CALLS_HEFTY_A_DIRECTDEPS = \
|
||||
LIBC_ALG \
|
||||
LIBC_CALLS \
|
||||
LIBC_CONV \
|
||||
LIBC_FMT \
|
||||
LIBC_MEM \
|
||||
LIBC_STR \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_CALLS \
|
||||
LIBC_STUBS \
|
||||
LIBC_NT_KERNELBASE \
|
||||
LIBC_RUNTIME \
|
||||
LIBC_STR \
|
||||
LIBC_STUBS \
|
||||
LIBC_SYSV \
|
||||
LIBC_SYSV_CALLS \
|
||||
LIBC_SYSV
|
||||
LIBC_TIME
|
||||
|
||||
LIBC_CALLS_HEFTY_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_CALLS_HEFTY_A_DIRECTDEPS),$($(x))))
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
int faccessat$nt(int, const char *, int, uint32_t) hidden;
|
||||
int execve$nt(const char *, char *const[], char *const[]) hidden;
|
||||
int spawnve$nt(unsigned, int[3], const char *, char *const[],
|
||||
char *const[]) hidden;
|
||||
|
|
|
@ -35,36 +35,32 @@
|
|||
* @return freshly allocated lpEnvironment or NULL w/ errno
|
||||
*/
|
||||
textwindows char16_t *mkntenvblock(char *const envp[]) {
|
||||
size_t block_i = 0;
|
||||
size_t block_n = 0;
|
||||
char16_t *block_p = NULL;
|
||||
size_t i, j;
|
||||
if (!(envp = sortenvp(envp))) goto error;
|
||||
const char16_t kNul = u'\0';
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
unsigned consumed;
|
||||
for (j = 0;; j += consumed) {
|
||||
wint_t wc;
|
||||
char16_t cbuf[2];
|
||||
consumed = abs(tpdecode(&envp[i][j], &wc));
|
||||
if (CONCAT(&block_p, &block_i, &block_n, cbuf,
|
||||
abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false))) == -1) {
|
||||
goto error;
|
||||
wint_t wc;
|
||||
size_t i, j, bi, bn;
|
||||
char16_t *bp, cbuf[2];
|
||||
unsigned consumed, produced;
|
||||
bi = 0;
|
||||
bn = 8;
|
||||
bp = NULL;
|
||||
if ((envp = sortenvp(envp)) && (bp = calloc(bn, sizeof(char16_t)))) {
|
||||
for (i = 0; envp[i]; ++i) {
|
||||
for (j = 0;; j += consumed) {
|
||||
consumed = abs(tpdecode(&envp[i][j], &wc));
|
||||
produced = abs(pututf16(cbuf, ARRAYLEN(cbuf), wc, false));
|
||||
if (CONCAT(&bp, &bi, &bn, cbuf, produced) == -1) goto error;
|
||||
if (!wc) break;
|
||||
}
|
||||
if (!wc) break;
|
||||
}
|
||||
++bi;
|
||||
if (bi > ENV_MAX) {
|
||||
e2big();
|
||||
goto error;
|
||||
}
|
||||
free(envp);
|
||||
return bp;
|
||||
}
|
||||
if (APPEND(&block_p, &block_i, &block_n, &kNul) == -1) {
|
||||
goto error;
|
||||
}
|
||||
if (block_i > ENV_MAX) {
|
||||
e2big();
|
||||
goto error;
|
||||
}
|
||||
free(envp);
|
||||
return block_p;
|
||||
error:
|
||||
free(envp);
|
||||
free(block_p);
|
||||
free(bp);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
@ -19,12 +19,14 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifndef COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/struct/securityattributes.h"
|
||||
#include "libc/nt/struct/startupinfo.h"
|
||||
#include "libc/nt/struct/systeminfo.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
|
||||
#define kSigactionMinRva 8 /* >SIG_{ERR,DFL,IGN,...} */
|
||||
|
@ -36,6 +38,7 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
struct NtContext;
|
||||
struct NtWin32FileAttributeData;
|
||||
struct ZiposHandle;
|
||||
struct __darwin_siginfo;
|
||||
struct __darwin_ucontext;
|
||||
struct itimerval;
|
||||
|
@ -45,7 +48,7 @@ struct sigset;
|
|||
struct sysinfo;
|
||||
struct timeval;
|
||||
struct timezone;
|
||||
struct ZiposHandle;
|
||||
struct utimbuf;
|
||||
|
||||
struct IoctlPtmGet {
|
||||
int theduxfd;
|
||||
|
@ -62,7 +65,8 @@ struct IoctlPtmGet {
|
|||
* and helps us abstract peculiarities like close() vs. closesocket().
|
||||
*/
|
||||
struct Fds {
|
||||
size_t f, n;
|
||||
size_t f; // length
|
||||
size_t n; // capacity
|
||||
struct Fd {
|
||||
int64_t handle;
|
||||
int64_t extra;
|
||||
|
@ -132,6 +136,7 @@ i32 __dup3$sysv(i32, i32, i32) hidden;
|
|||
i32 __fstat$sysv(i32, struct stat *) hidden;
|
||||
i32 __fstatat$sysv(i32, const char *, struct stat *, i32) hidden;
|
||||
i32 __pipe2$sysv(i32[hasatleast 2], u32) hidden;
|
||||
i32 __utimensat$sysv(i32, const char *, const struct timespec *, i32) hidden;
|
||||
i32 chdir$sysv(const char *) hidden;
|
||||
i32 clock_gettime$sysv(i32, struct timespec *) hidden;
|
||||
i32 close$sysv(i32) hidden;
|
||||
|
@ -154,6 +159,8 @@ i32 fstat$sysv(i32, struct stat *) hidden;
|
|||
i32 fstatat$sysv(i32, const char *, struct stat *, i32) hidden;
|
||||
i32 fsync$sysv(i32) hidden;
|
||||
i32 ftruncate$sysv(i32, i64) hidden;
|
||||
i32 futimes$sysv(i32, const struct timeval *) hidden;
|
||||
i32 futimesat$sysv(i32, const char *, const struct timeval *) hidden;
|
||||
i32 getdents(i32, char *, u32) hidden;
|
||||
i32 getppid$sysv(void) hidden;
|
||||
i32 getpriority$sysv(i32, u32) hidden;
|
||||
|
@ -164,6 +171,7 @@ i32 ioctl$sysv(i32, u64, void *) hidden;
|
|||
i32 kill$sysv(i32, i32, i32) hidden;
|
||||
i32 linkat$sysv(i32, const char *, i32, const char *, i32) hidden;
|
||||
i32 lseek$sysv(i32, i64, i32) hidden;
|
||||
i32 lutimes$sysv(const char *, const struct timeval *) hidden;
|
||||
i32 madvise$sysv(void *, size_t, i32) hidden;
|
||||
i32 memfd_create$sysv(const char *, u32) hidden;
|
||||
i32 mkdirat$sysv(i32, const char *, u32) hidden;
|
||||
|
@ -194,6 +202,8 @@ i32 sysinfo$sysv(struct sysinfo *) hidden;
|
|||
i32 truncate$sysv(const char *, u64) hidden;
|
||||
i32 uname$sysv(char *) hidden;
|
||||
i32 unlinkat$sysv(i32, const char *, i32) hidden;
|
||||
i32 utime$sysv(const char *, const struct utimbuf *) hidden;
|
||||
i32 utimensat$sysv(i32, const char *, const struct timespec *, i32) hidden;
|
||||
i32 utimes$sysv(const char *, const struct timeval *) hidden;
|
||||
i32 wait4$sysv(i32, i32 *, i32, struct rusage *) hidden;
|
||||
i64 copy_file_range$sysv(i32, long *, i32, long *, u64, u32) hidden;
|
||||
|
@ -207,12 +217,12 @@ i64 sendfile$sysv(i32, i32, i64 *, u64) hidden;
|
|||
i64 splice$sysv(i32, i64 *, i32, i64 *, u64, u32) hidden;
|
||||
i64 vmsplice$sysv(i32, const struct iovec *, i64, u32) hidden;
|
||||
i64 write$sysv(i32, const void *, u64) hidden;
|
||||
int setresgid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
int setresuid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
u32 getgid$sysv(void) hidden;
|
||||
u32 getpid$sysv(void) hidden;
|
||||
u32 gettid$sysv(void) hidden;
|
||||
u32 getuid$sysv(void) hidden;
|
||||
int setresuid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
int setresgid$sysv(uint32_t, uint32_t, uint32_t) hidden;
|
||||
void *mmap$sysv(void *, u64, u32, u32, i64, i64) hidden;
|
||||
void *mremap$sysv(void *, u64, u64, i32, void *) hidden;
|
||||
|
||||
|
@ -223,13 +233,13 @@ void *mremap$sysv(void *, u64, u64, i32, void *) hidden;
|
|||
int __getpid(void) hidden;
|
||||
void __onfork(void) hidden;
|
||||
bool32 __sigenter(i32, struct siginfo *, struct ucontext *) hidden;
|
||||
i32 __mprotect(void *, u64, i32) privileged;
|
||||
i32 fixupnewfd$sysv(i32, i32) hidden;
|
||||
i32 tunefd$sysv(i32, i32, i32, i32) hidden;
|
||||
u32 fprot2nt(i32, i32) hidden;
|
||||
u32 prot2nt(i32, i32) privileged;
|
||||
void __restore_rt() hidden;
|
||||
void __sigenter$xnu(void *, i32, i32, void *, void *) hidden noreturn;
|
||||
int utimensat$xnu(int, const char *, const struct timespec *, int) hidden;
|
||||
void stat2linux(void *) hidden;
|
||||
void xnutrampoline(void *, i32, i32, const struct __darwin_siginfo *,
|
||||
const struct __darwin_ucontext *) hidden noreturn;
|
||||
|
@ -271,6 +281,8 @@ int wait4$nt(int, int *, int, struct rusage *) hidden;
|
|||
i64 lseek$nt(int, i64, int) hidden;
|
||||
ssize_t read$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
ssize_t write$nt(struct Fd *, const struct iovec *, size_t, ssize_t) hidden;
|
||||
int utimensat$nt(int, const char *, const struct timespec *, int) hidden;
|
||||
int getrusage$nt(int, struct rusage *) hidden;
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § syscalls » windows nt » support ─╬─│┼
|
||||
|
@ -317,4 +329,5 @@ int __mkntpath(const char *, unsigned, char16_t[hasatleast PATH_MAX - 16])
|
|||
#undef u64
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_INTERNAL_H_ */
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/ioctl.h"
|
||||
#include "libc/nt/winsock.h"
|
||||
|
|
|
@ -32,18 +32,17 @@ textwindows int ioctl$tiocgwinsz$nt(int fd, struct winsize *ws) {
|
|||
struct NtConsoleScreenBufferInfoEx sbinfo;
|
||||
if (!isfdkind(fd, kFdFile)) return ebadf();
|
||||
if (!GetConsoleMode(g_fds.p[fd].handle, &mode)) return enotty();
|
||||
if (g_ntstartupinfo.dwFlags & kNtStartfUsecountchars) {
|
||||
ws->ws_col = g_ntstartupinfo.dwXCountChars;
|
||||
ws->ws_row = g_ntstartupinfo.dwYCountChars;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
return 0;
|
||||
}
|
||||
memset(&sbinfo, 0, sizeof(sbinfo));
|
||||
sbinfo.cbSize = sizeof(sbinfo);
|
||||
if (GetConsoleScreenBufferInfoEx(g_fds.p[fd].handle, &sbinfo)) {
|
||||
ws->ws_col = sbinfo.srWindow.Right;
|
||||
ws->ws_row = sbinfo.srWindow.Bottom;
|
||||
ws->ws_col = sbinfo.srWindow.Right - sbinfo.srWindow.Left;
|
||||
ws->ws_row = sbinfo.srWindow.Bottom - sbinfo.srWindow.Top;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
return 0;
|
||||
} else if (g_ntstartupinfo.dwFlags & kNtStartfUsecountchars) {
|
||||
ws->ws_col = g_ntstartupinfo.dwXCountChars;
|
||||
ws->ws_row = g_ntstartupinfo.dwYCountChars;
|
||||
ws->ws_xpixel = 0;
|
||||
ws->ws_ypixel = 0;
|
||||
return 0;
|
||||
|
|
|
@ -17,6 +17,9 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#ifdef __STRICT_ANSI__
|
||||
#undef __STRICT_ANSI__
|
||||
#endif
|
||||
#include "libc/calls/ioctl.h"
|
||||
|
||||
#define EQUAL(X, Y) ((X) == (Y))
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
/**
|
||||
* Returns true if file descriptor is backed by character i/o.
|
||||
*/
|
||||
bool32 ischardev(int fd) {
|
||||
textstartup bool32 ischardev(int fd) {
|
||||
int olderr;
|
||||
struct stat st;
|
||||
if (!IsWindows()) {
|
||||
|
|
|
@ -24,13 +24,14 @@
|
|||
#include "libc/conv/conv.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/log/log.h"
|
||||
#include "libc/nexgen32e/vendor.h"
|
||||
#include "libc/nt/struct/teb.h"
|
||||
#include "libc/runtime/runtime.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/consts/o.h"
|
||||
|
||||
#define kBufSize 1024
|
||||
#define kBufSize 1024
|
||||
#define kProcStatus "/proc/self/status"
|
||||
alignas(16) static const char kGdbPid[] = "TracerPid:\t";
|
||||
|
||||
|
@ -43,18 +44,20 @@ int IsDebuggerPresent(bool force) {
|
|||
ssize_t got;
|
||||
char buf[1024];
|
||||
res = 0;
|
||||
if (force || isempty(getenv("HEISENDEBUG"))) {
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
} else if (IsLinux()) {
|
||||
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
|
||||
buf[got] = '\0';
|
||||
res = atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) +
|
||||
strlen(kGdbPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
if (!force) {
|
||||
if (getenv("HEISENDEBUG")) return false;
|
||||
if (IsGenuineCosmo()) return false;
|
||||
}
|
||||
if (IsWindows()) {
|
||||
res = NtGetPeb()->BeingDebugged;
|
||||
} else if (IsLinux()) {
|
||||
if ((fd = openat$sysv(AT_FDCWD, kProcStatus, O_RDONLY, 0)) != -1) {
|
||||
if ((got = read$sysv(fd, buf, sizeof(buf) - sizeof(kGdbPid))) != -1) {
|
||||
buf[got] = '\0';
|
||||
res =
|
||||
atoi(firstnonnull(strstr(buf, kGdbPid), kGdbPid) + strlen(kGdbPid));
|
||||
}
|
||||
close$sysv(fd);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/errno.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#include "libc/errno.h"
|
||||
|
||||
/**
|
||||
* Returns true if file exists and is a directory
|
||||
* Returns true if file exists and is a directory.
|
||||
*/
|
||||
bool isdirectory(const char *path) {
|
||||
struct stat st;
|
||||
|
|
|
@ -24,33 +24,35 @@
|
|||
#include "libc/nt/enum/processcreationflags.h"
|
||||
#include "libc/nt/enum/threadpriority.h"
|
||||
|
||||
#define FFS(x) __builtin_ffs(x)
|
||||
|
||||
const struct NtPriorityCombo kNtPriorityCombos[] = {
|
||||
{-20, ffs(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
|
||||
{-18, ffs(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-17, ffs(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-15, ffs(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-13, ffs(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
|
||||
{-11, ffs(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
|
||||
{-9, ffs(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
|
||||
{-7, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
|
||||
{-5, ffs(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
|
||||
{-3, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
|
||||
{-1, ffs(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
|
||||
{0, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
|
||||
{1, ffs(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
|
||||
{2, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
|
||||
{3, ffs(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
|
||||
{4, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
|
||||
{5, ffs(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
|
||||
{6, ffs(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
|
||||
{7, ffs(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
|
||||
{9, ffs(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
|
||||
{11, ffs(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
|
||||
{13, ffs(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
|
||||
{15, ffs(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
|
||||
{17, ffs(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{18, ffs(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{19, ffs(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{-20, FFS(kNtHighPriorityClass), kNtThreadPriorityHighest, 15},
|
||||
{-18, FFS(kNtHighPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-17, FFS(kNtNormalPriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-15, FFS(kNtIdlePriorityClass), kNtThreadPriorityTimeCritical, 15},
|
||||
{-13, FFS(kNtHighPriorityClass), kNtThreadPriorityAboveNormal, 14},
|
||||
{-11, FFS(kNtHighPriorityClass), kNtThreadPriorityNormal, 13},
|
||||
{-9, FFS(kNtHighPriorityClass), kNtThreadPriorityBelowNormal, 12},
|
||||
{-7, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 11},
|
||||
{-5, FFS(kNtHighPriorityClass), kNtThreadPriorityLowest, 11},
|
||||
{-3, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 10},
|
||||
{-1, FFS(kNtNormalPriorityClass), kNtThreadPriorityHighest, 9},
|
||||
{0, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 9},
|
||||
{1, FFS(kNtNormalPriorityClass), kNtThreadPriorityAboveNormal, 8},
|
||||
{2, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 8},
|
||||
{3, FFS(kNtNormalPriorityClass), kNtThreadPriorityNormal, 7},
|
||||
{4, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 7},
|
||||
{5, FFS(kNtIdlePriorityClass), kNtThreadPriorityHighest, 6},
|
||||
{6, FFS(kNtNormalPriorityClass), kNtThreadPriorityBelowNormal, 6},
|
||||
{7, FFS(kNtIdlePriorityClass), kNtThreadPriorityAboveNormal, 5},
|
||||
{9, FFS(kNtNormalPriorityClass), kNtThreadPriorityLowest, 5},
|
||||
{11, FFS(kNtIdlePriorityClass), kNtThreadPriorityNormal, 4},
|
||||
{13, FFS(kNtIdlePriorityClass), kNtThreadPriorityBelowNormal, 3},
|
||||
{15, FFS(kNtIdlePriorityClass), kNtThreadPriorityLowest, 2},
|
||||
{17, FFS(kNtHighPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{18, FFS(kNtNormalPriorityClass), kNtThreadPriorityIdle, 1},
|
||||
{19, FFS(kNtIdlePriorityClass), kNtThreadPriorityIdle, 1},
|
||||
};
|
||||
|
||||
const unsigned kNtPriorityCombosLen = ARRAYLEN(kNtPriorityCombos);
|
||||
|
|
|
@ -17,16 +17,14 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
/**
|
||||
* Modifies restrictions on virtual memory address range.
|
||||
*
|
||||
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
int mprotect(void *addr, uint64_t len, int prot) {
|
||||
return __mprotect(addr, len, prot);
|
||||
int mkdirat(int dirfd, const char *pathname, unsigned mode) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return mkdir(pathname, mode);
|
||||
} else {
|
||||
return mkdirat$sysv(dirfd, pathname, mode);
|
||||
}
|
||||
}
|
|
@ -39,8 +39,9 @@
|
|||
* @return short count excluding NUL on success, or -1 w/ errno
|
||||
* @error ENAMETOOLONG
|
||||
*/
|
||||
textwindows int(mkntpath)(const char *path, unsigned flags,
|
||||
char16_t path16[hasatleast PATH_MAX - 16]) {
|
||||
forcealignargpointer textwindows int(mkntpath)(
|
||||
const char *path, unsigned flags,
|
||||
char16_t path16[hasatleast PATH_MAX - 16]) {
|
||||
/*
|
||||
* 1. Reserve +1 for NUL-terminator
|
||||
* 2. Reserve +1 for UTF-16 overflow
|
||||
|
|
|
@ -26,7 +26,14 @@
|
|||
#include "libc/nt/thunk/msabi.h"
|
||||
#include "libc/sysv/consts/nr.h"
|
||||
|
||||
privileged int __mprotect(void *addr, uint64_t len, int prot) {
|
||||
/**
|
||||
* Modifies restrictions on virtual memory address range.
|
||||
*
|
||||
* @param prot can have PROT_{NONE,READ,WRITE,EXEC,GROWSDOWN}
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
* @see mmap()
|
||||
*/
|
||||
int mprotect(void *addr, uint64_t len, int prot) {
|
||||
extern __msabi typeof(VirtualProtect) *const __imp_VirtualProtect;
|
||||
bool cf;
|
||||
int64_t rc;
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
49
libc/calls/openat.c
Normal file
49
libc/calls/openat.c
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Opens file, the modern way.
|
||||
*
|
||||
* @param dirfd is normally AT_FDCWD or an open relative directory thing
|
||||
* @param file is a UTF-8 string, preferably relative w/ forward slashes
|
||||
* @param flags should be O_RDONLY, O_WRONLY, or O_RDWR, and can be or'd
|
||||
* with O_CREAT, O_TRUNC, O_APPEND, O_EXCL, O_CLOEXEC, O_TMPFILE
|
||||
* @param mode is an octal user/group/other permission signifier, that's
|
||||
* ignored if O_CREAT or O_TMPFILE weren't passed
|
||||
* @return number needing close(), or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int openat(int dirfd, const char *pathname, int flags, ...) {
|
||||
va_list va;
|
||||
unsigned mode;
|
||||
va_start(va, flags);
|
||||
mode = va_arg(va, unsigned);
|
||||
va_end(va);
|
||||
if (!pathname) return efault();
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return open(pathname, flags, mode);
|
||||
} else {
|
||||
return openat$sysv(dirfd, pathname, flags, mode);
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Creates file-less file descriptors for inter-process communication.
|
||||
|
@ -30,6 +31,7 @@
|
|||
* @see pipe2()
|
||||
*/
|
||||
int pipe(int pipefd[hasatleast 2]) {
|
||||
if (!pipefd) return efault();
|
||||
if (!IsWindows()) {
|
||||
return pipe$sysv(pipefd);
|
||||
} else {
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Creates file-less file descriptors for interprocess communication.
|
||||
|
@ -29,6 +30,7 @@
|
|||
* @return 0 on success, or -1 w/ errno and pipefd isn't modified
|
||||
*/
|
||||
int pipe2(int pipefd[hasatleast 2], int flags) {
|
||||
if (!pipefd) return efault();
|
||||
if (!IsWindows()) {
|
||||
return pipe2$sysv(pipefd, flags);
|
||||
} else {
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
|
|
@ -17,17 +17,20 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Moves file the Unix way.
|
||||
*
|
||||
* @return 0 on success or -1 w/ errno
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
int rename(const char *oldpathname, const char *newpathname) {
|
||||
if (!oldpathname || !newpathname) return efault();
|
||||
if (!IsWindows()) {
|
||||
return renameat$sysv(AT_FDCWD, oldpathname, AT_FDCWD, newpathname);
|
||||
} else {
|
||||
|
|
32
libc/calls/renameat.c
Normal file
32
libc/calls/renameat.c
Normal file
|
@ -0,0 +1,32 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
int renameat(int olddirfd, const char *oldpath, int newdirfd,
|
||||
const char *newpath) {
|
||||
unsigned mode;
|
||||
if (olddirfd == AT_FDCWD && newdirfd == AT_FDCWD) {
|
||||
return rename(oldpath, newpath);
|
||||
} else {
|
||||
return renameat$sysv(olddirfd, oldpath, newdirfd, newpath);
|
||||
}
|
||||
}
|
|
@ -30,10 +30,14 @@
|
|||
static textwindows noinline int sched_setaffinity$nt(int pid,
|
||||
uint64_t bitsetsize,
|
||||
const void *bitset) {
|
||||
int rc;
|
||||
uintptr_t mask;
|
||||
int64_t handle;
|
||||
typeof(SetThreadAffinityMask) *SetAffinityMask = SetThreadAffinityMask;
|
||||
uintptr_t mask = 0;
|
||||
mask = 0;
|
||||
memcpy(&mask, bitset, min(bitsetsize, sizeof(uintptr_t)));
|
||||
int64_t handle = 0;
|
||||
handle = 0;
|
||||
if (!pid) pid = GetCurrentThreadId();
|
||||
if (0 < pid && pid <= UINT32_MAX) {
|
||||
if (pid == GetCurrentProcessId()) {
|
||||
pid = GetCurrentProcess();
|
||||
|
@ -50,7 +54,7 @@ static textwindows noinline int sched_setaffinity$nt(int pid,
|
|||
}
|
||||
}
|
||||
}
|
||||
int rc = SetAffinityMask(handle ? handle : pid, mask) ? 0 : winerr();
|
||||
rc = SetAffinityMask(handle ? handle : pid, mask) ? 0 : winerr();
|
||||
if (handle) CloseHandle(handle);
|
||||
return rc;
|
||||
}
|
||||
|
@ -58,7 +62,7 @@ static textwindows noinline int sched_setaffinity$nt(int pid,
|
|||
/**
|
||||
* Asks kernel to only schedule process on particular CPUs.
|
||||
*
|
||||
* @param pid is the process or thread id
|
||||
* @param pid is the process or thread id (or 0 for caller)
|
||||
* @param bitsetsize is byte length of bitset
|
||||
* @param bitset can be manipulated using bt(), bts(), etc.
|
||||
* @return 0 on success, or -1 w/ errno
|
||||
|
|
|
@ -20,7 +20,12 @@
|
|||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigaction-freebsd.h"
|
||||
#include "libc/calls/struct/sigaction-linux.h"
|
||||
#include "libc/calls/struct/sigaction-openbsd.h"
|
||||
#include "libc/calls/struct/sigaction-xnu.h"
|
||||
#include "libc/calls/struct/sigaction.h"
|
||||
#include "libc/calls/typedef/sigaction_f.h"
|
||||
#include "libc/calls/ucontext.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/limits.h"
|
||||
|
@ -32,51 +37,13 @@
|
|||
#include "libc/sysv/consts/sig.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
struct siginfo;
|
||||
|
||||
union metasigaction {
|
||||
struct sigaction cosmo;
|
||||
|
||||
struct sigaction$linux {
|
||||
intptr_t sa_handler;
|
||||
uint64_t sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
struct sigset$linux {
|
||||
uint32_t sig[2];
|
||||
} sa_mask;
|
||||
} linux;
|
||||
|
||||
struct sigaction$freebsd {
|
||||
intptr_t sa_handler;
|
||||
uint32_t sa_flags;
|
||||
struct sigset$freebsd {
|
||||
uint32_t sig[4];
|
||||
} sa_mask;
|
||||
} freebsd;
|
||||
|
||||
struct sigaction$openbsd {
|
||||
intptr_t sa_handler;
|
||||
struct sigset$openbsd {
|
||||
uint32_t sig[1];
|
||||
} sa_mask;
|
||||
int32_t sa_flags;
|
||||
} openbsd;
|
||||
|
||||
struct sigaction$xnu_in {
|
||||
intptr_t sa_handler;
|
||||
void (*sa_restorer)(void *, int, int, const struct __darwin_siginfo *,
|
||||
const struct __darwin_ucontext *);
|
||||
struct sigset$xnu {
|
||||
uint32_t sig[1];
|
||||
} sa_mask;
|
||||
int32_t sa_flags;
|
||||
} xnu_in;
|
||||
|
||||
struct sigaction$xnu_out {
|
||||
intptr_t sa_handler;
|
||||
struct sigset$xnu sa_mask;
|
||||
int32_t sa_flags;
|
||||
} xnu_out;
|
||||
struct sigaction$linux linux;
|
||||
struct sigaction$freebsd freebsd;
|
||||
struct sigaction$openbsd openbsd;
|
||||
struct sigaction$xnu_in xnu_in;
|
||||
struct sigaction$xnu_out xnu_out;
|
||||
};
|
||||
|
||||
#define SWITCHEROO(S1, S2, A, B, C, D) \
|
||||
|
@ -210,9 +177,8 @@ int(sigaction)(int sig, const struct sigaction *act, struct sigaction *oldact) {
|
|||
if (rc != -1) {
|
||||
if (oldact) {
|
||||
oldrva = g_sighandrvas[sig];
|
||||
oldact->sa_sigaction = oldrva < kSigactionMinRva
|
||||
? (sigaction_f)(intptr_t)oldrva
|
||||
: (sigaction_f)((uintptr_t)&_base + oldrva);
|
||||
oldact->sa_sigaction = (sigaction_f)(
|
||||
oldrva < kSigactionMinRva ? oldrva : (intptr_t)&_base + oldrva);
|
||||
}
|
||||
if (act) {
|
||||
g_sighandrvas[sig] = rva;
|
||||
|
|
|
@ -17,10 +17,10 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/dce.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/sigset.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
|
@ -31,6 +31,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int sigsuspend(const sigset_t *mask) {
|
||||
if (!mask) return efault();
|
||||
if (!IsWindows()) {
|
||||
return sigsuspend$sysv(mask, 8);
|
||||
} else {
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
|
|
|
@ -73,7 +73,7 @@ forceinline void stat2linux_openbsd(union metastat *ms) {
|
|||
* Transcodes “The Dismal Data Structure” from BSD→Linux ABI.
|
||||
* @asyncsignalsafe
|
||||
*/
|
||||
void stat2linux(void *ms) {
|
||||
textstartup void stat2linux(void *ms) {
|
||||
if (ms) {
|
||||
if (SupportsXnu() && IsXnu()) {
|
||||
stat2linux_xnu((union metastat *)ms);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_METASTAT_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_METASTAT_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/calls/struct/stat.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -52,4 +53,5 @@ union metastat {
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_METASTAT_H_ */
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_METATERMIOS_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_METATERMIOS_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/calls/struct/termios.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
@ -32,4 +33,5 @@ union metatermios {
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_METATERMIOS_H_ */
|
||||
|
|
14
libc/calls/struct/sigaction-freebsd.h
Normal file
14
libc/calls/struct/sigaction-freebsd.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct sigaction$freebsd {
|
||||
intptr_t sa_handler;
|
||||
uint32_t sa_flags;
|
||||
struct sigset$freebsd {
|
||||
uint32_t sig[4];
|
||||
} sa_mask;
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_FREEBSD_H_ */
|
15
libc/calls/struct/sigaction-linux.h
Normal file
15
libc/calls/struct/sigaction-linux.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct sigaction$linux {
|
||||
intptr_t sa_handler;
|
||||
uint64_t sa_flags;
|
||||
void (*sa_restorer)(void);
|
||||
struct sigset$linux {
|
||||
uint32_t sig[2];
|
||||
} sa_mask;
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_LINUX_H_ */
|
14
libc/calls/struct/sigaction-openbsd.h
Normal file
14
libc/calls/struct/sigaction-openbsd.h
Normal file
|
@ -0,0 +1,14 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct sigaction$openbsd {
|
||||
intptr_t sa_handler;
|
||||
struct sigset$openbsd {
|
||||
uint32_t sig[1];
|
||||
} sa_mask;
|
||||
int32_t sa_flags;
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_OPENBSD_H_ */
|
28
libc/calls/struct/sigaction-xnu.h
Normal file
28
libc/calls/struct/sigaction-xnu.h
Normal file
|
@ -0,0 +1,28 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_
|
||||
#include "libc/calls/internal.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct __darwin_ucontext;
|
||||
struct __darwin_siginfo;
|
||||
|
||||
struct sigset$xnu {
|
||||
uint32_t sig[1];
|
||||
};
|
||||
|
||||
struct sigaction$xnu_in {
|
||||
intptr_t sa_handler;
|
||||
void (*sa_restorer)(void *, int, int, const struct __darwin_siginfo *,
|
||||
const struct __darwin_ucontext *);
|
||||
struct sigset$xnu sa_mask;
|
||||
int32_t sa_flags;
|
||||
};
|
||||
|
||||
struct sigaction$xnu_out {
|
||||
intptr_t sa_handler;
|
||||
struct sigset$xnu sa_mask;
|
||||
int32_t sa_flags;
|
||||
};
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGACTION_XNU_H_ */
|
|
@ -10,7 +10,5 @@ struct sigaltstack {
|
|||
|
||||
typedef struct sigaltstack stack_t;
|
||||
|
||||
static_assert(sizeof(stack_t) == 24);
|
||||
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGALTSTACK_H_ */
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#define COSMOPOLITAN_LIBC_CALLS_STRUCT_SIGSET_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
||||
struct sigset {
|
||||
struct sigset { /* cosmo abi (linux is uint64_t) */
|
||||
uint32_t sig[4]; /* ignore sig[2] and sig[3] (for freebsd) */
|
||||
} aligned(8);
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_
|
||||
#define COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_
|
||||
#ifndef __STRICT_ANSI__
|
||||
#include "libc/bits/safemacros.h"
|
||||
#include "libc/str/str.h"
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
|
@ -26,4 +27,5 @@ void termios2linux(struct termios *, const union metatermios *);
|
|||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* !ANSI */
|
||||
#endif /* COSMOPOLITAN_LIBC_CALLS_TERMIOS_INTERNAL_H_ */
|
||||
|
|
|
@ -12,10 +12,10 @@ COSMOPOLITAN_C_START_
|
|||
│ cosmopolitan § teletypewriter control ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
int tcgetattr(int fd, struct termios *tio);
|
||||
int tcsetattr(int fd, int opt, const struct termios *tio);
|
||||
int tcsetpgrp(int fd, int32_t pgrp);
|
||||
int32_t tcgetpgrp(int fd);
|
||||
int tcgetattr(int, struct termios *);
|
||||
int tcsetattr(int, int, const struct termios *);
|
||||
int tcsetpgrp(int, int32_t);
|
||||
int32_t tcgetpgrp(int);
|
||||
|
||||
int openpty(int *, int *, char *, const struct termios *,
|
||||
const struct winsize *) paramsnonnull((1, 2)) nodiscard;
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Reduces or extends underlying physical medium of file.
|
||||
|
@ -32,6 +33,7 @@
|
|||
* @error ENOENT
|
||||
*/
|
||||
int truncate(const char *path, uint64_t length) {
|
||||
if (!path) return efault();
|
||||
if (!IsWindows()) {
|
||||
return truncate$sysv(path, length);
|
||||
} else {
|
||||
|
|
|
@ -6,29 +6,29 @@
|
|||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
|
||||
#define REG_R8 REG_R8
|
||||
#define REG_R9 REG_R9
|
||||
#define REG_R10 REG_R10
|
||||
#define REG_R11 REG_R11
|
||||
#define REG_R12 REG_R12
|
||||
#define REG_R13 REG_R13
|
||||
#define REG_R14 REG_R14
|
||||
#define REG_R15 REG_R15
|
||||
#define REG_RDI REG_RDI
|
||||
#define REG_RSI REG_RSI
|
||||
#define REG_RBP REG_RBP
|
||||
#define REG_RBX REG_RBX
|
||||
#define REG_RDX REG_RDX
|
||||
#define REG_RAX REG_RAX
|
||||
#define REG_RCX REG_RCX
|
||||
#define REG_RSP REG_RSP
|
||||
#define REG_RIP REG_RIP
|
||||
#define REG_EFL REG_EFL
|
||||
#define REG_CSGSFS REG_CSGSFS
|
||||
#define REG_ERR REG_ERR
|
||||
#define REG_TRAPNO REG_TRAPNO
|
||||
#define REG_R8 REG_R8
|
||||
#define REG_R9 REG_R9
|
||||
#define REG_R10 REG_R10
|
||||
#define REG_R11 REG_R11
|
||||
#define REG_R12 REG_R12
|
||||
#define REG_R13 REG_R13
|
||||
#define REG_R14 REG_R14
|
||||
#define REG_R15 REG_R15
|
||||
#define REG_RDI REG_RDI
|
||||
#define REG_RSI REG_RSI
|
||||
#define REG_RBP REG_RBP
|
||||
#define REG_RBX REG_RBX
|
||||
#define REG_RDX REG_RDX
|
||||
#define REG_RAX REG_RAX
|
||||
#define REG_RCX REG_RCX
|
||||
#define REG_RSP REG_RSP
|
||||
#define REG_RIP REG_RIP
|
||||
#define REG_EFL REG_EFL
|
||||
#define REG_CSGSFS REG_CSGSFS
|
||||
#define REG_ERR REG_ERR
|
||||
#define REG_TRAPNO REG_TRAPNO
|
||||
#define REG_OLDMASK REG_OLDMASK
|
||||
#define REG_CR2 REG_CR2
|
||||
#define REG_CR2 REG_CR2
|
||||
|
||||
enum GeneralRegister {
|
||||
REG_R8,
|
||||
|
@ -60,16 +60,12 @@ struct XmmRegister {
|
|||
uint64_t u64[2];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct XmmRegister) == 16);
|
||||
|
||||
struct FpuStackEntry {
|
||||
uint16_t significand[4];
|
||||
uint16_t exponent;
|
||||
uint16_t padding[3];
|
||||
};
|
||||
|
||||
static_assert(sizeof(struct FpuStackEntry) == 16);
|
||||
|
||||
struct FpuState {
|
||||
uint16_t cwd;
|
||||
uint16_t swd;
|
||||
|
|
|
@ -17,12 +17,12 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/dce.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/str/str.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
/**
|
||||
* Deletes file.
|
||||
|
@ -36,7 +36,7 @@
|
|||
* @asyncsignalsafe
|
||||
*/
|
||||
int unlink(const char *name) {
|
||||
if (!name) return 0;
|
||||
if (!name) return efault();
|
||||
if (!IsWindows()) {
|
||||
return unlinkat$sysv(AT_FDCWD, name, 0);
|
||||
} else {
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/runtime/mappings.h"
|
||||
|
||||
/**
|
||||
* Deletes file, the Cosmopolitan way.
|
||||
|
|
30
libc/calls/unlinkat.c
Normal file
30
libc/calls/unlinkat.c
Normal file
|
@ -0,0 +1,30 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sysv/consts/at.h"
|
||||
|
||||
int unlinkat(int dirfd, const char *pathname, int flags) {
|
||||
if (dirfd == AT_FDCWD) {
|
||||
return unlink(pathname);
|
||||
} else {
|
||||
return unlinkat$sysv(dirfd, pathname, flags);
|
||||
}
|
||||
}
|
|
@ -21,45 +21,46 @@
|
|||
#include "libc/dce.h"
|
||||
#include "libc/fmt/fmt.h"
|
||||
#include "libc/limits.h"
|
||||
#include "libc/macros.h"
|
||||
#include "libc/nt/files.h"
|
||||
#include "libc/sysv/errfuns.h"
|
||||
|
||||
#define DBUFSIZ 1460 /* tcp ethernet frame < -Wframe-larger-than=4096 */
|
||||
|
||||
struct dfile {
|
||||
struct VdprintfState {
|
||||
int n;
|
||||
int fd;
|
||||
unsigned idx;
|
||||
unsigned toto;
|
||||
unsigned char buf[DBUFSIZ];
|
||||
unsigned char buf[1024];
|
||||
};
|
||||
|
||||
static int vdprintf_flush(struct dfile *df) {
|
||||
ssize_t wrote;
|
||||
do {
|
||||
wrote = write(df->fd, &df->buf[0], df->idx);
|
||||
if (wrote == -1) return -1;
|
||||
df->toto += (unsigned)wrote;
|
||||
df->idx -= (unsigned)wrote;
|
||||
if (df->toto > INT_MAX) return eoverflow();
|
||||
} while (df->idx);
|
||||
static int vdprintf_flush(struct VdprintfState *df, int n) {
|
||||
int i, rc;
|
||||
for (i = 0; i < n; i += rc) {
|
||||
if ((rc = write(df->fd, df->buf + i, n - i)) == -1) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vdprintfputchar(unsigned char c, struct dfile *df) {
|
||||
df->buf[df->idx++] = c;
|
||||
if (df->idx == DBUFSIZ && vdprintf_flush(df) == -1) return -1;
|
||||
return 0;
|
||||
static int vdprintfputchar(int c, struct VdprintfState *df) {
|
||||
df->buf[df->n++ & (ARRAYLEN(df->buf) - 1)] = c & 0xff;
|
||||
if ((df->n & (ARRAYLEN(df->buf) - 1))) {
|
||||
return 0;
|
||||
} else {
|
||||
return vdprintf_flush(df, ARRAYLEN(df->buf));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats string directly to system i/o device.
|
||||
*/
|
||||
int(vdprintf)(int fd, const char *fmt, va_list va) {
|
||||
struct dfile df;
|
||||
struct VdprintfState df;
|
||||
df.n = 0;
|
||||
df.fd = fd;
|
||||
df.idx = 0;
|
||||
df.toto = 0;
|
||||
if (palandprintf(vdprintfputchar, &df, fmt, va) == -1) return -1;
|
||||
if (df.idx && vdprintf_flush(&df) == -1) return -1;
|
||||
return df.toto;
|
||||
if (palandprintf(vdprintfputchar, &df, fmt, va) != -1 ||
|
||||
vdprintf_flush(&df, df.n & (ARRAYLEN(df.buf) - 1)) != -1) {
|
||||
return df.n;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/bits/bits.h"
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/calls/struct/iovec.h"
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/bits/weaken.h"
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/calls/internal.h"
|
||||
#include "libc/sock/internal.h"
|
||||
|
|
|
@ -2,10 +2,26 @@
|
|||
#define COSMOPOLITAN_LIBC_COMPLEX_H_
|
||||
#if !(__ASSEMBLER__ + __LINKER__ + 0)
|
||||
COSMOPOLITAN_C_START_
|
||||
#if __STDC_VERSION__ + 0 >= 201112
|
||||
|
||||
#define complex _Complex
|
||||
#define imaginary _Imaginary
|
||||
|
||||
double cabs(complex double);
|
||||
double carg(complex double);
|
||||
double cimag(complex double);
|
||||
double creal(complex double);
|
||||
|
||||
float cabsf(complex float);
|
||||
float cargf(complex float);
|
||||
float cimagf(complex float);
|
||||
float crealf(complex float);
|
||||
|
||||
long double cabsl(complex long double);
|
||||
long double cargl(complex long double);
|
||||
long double cimagl(complex long double);
|
||||
long double creall(complex long double);
|
||||
|
||||
complex double cacos(complex double);
|
||||
complex double cacosh(complex double);
|
||||
complex double casin(complex double);
|
||||
|
@ -46,21 +62,6 @@ complex float csqrtf(complex float);
|
|||
complex float ctanf(complex float);
|
||||
complex float ctanhf(complex float);
|
||||
|
||||
double cabs(complex double);
|
||||
double carg(complex double);
|
||||
double cimag(complex double);
|
||||
double creal(complex double);
|
||||
|
||||
float cabsf(complex float);
|
||||
float cargf(complex float);
|
||||
float cimagf(complex float);
|
||||
float crealf(complex float);
|
||||
|
||||
long double cabsl(complex long double);
|
||||
long double cargl(complex long double);
|
||||
long double cimagl(complex long double);
|
||||
long double creall(complex long double);
|
||||
|
||||
complex long double cprojl(complex long double);
|
||||
complex long double csinhl(complex long double);
|
||||
complex long double csinl(complex long double);
|
||||
|
@ -81,6 +82,7 @@ complex long double clogl(complex long double);
|
|||
complex long double conjl(complex long double);
|
||||
complex long double cpowl(complex long double, complex long double);
|
||||
|
||||
#endif /* C11 */
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_COMPLEX_H_ */
|
||||
|
|
|
@ -31,4 +31,6 @@
|
|||
* @param path is NUL-terminated UTF-8 path
|
||||
* @return pointer inside path or path itself
|
||||
*/
|
||||
char *basename(const char *path) { return basename_n(path, strlen(path)); }
|
||||
textstartup char *basename(const char *path) {
|
||||
return basename_n(path, strlen(path));
|
||||
}
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
* @param size is byte length of path
|
||||
* @return pointer inside path or path itself
|
||||
*/
|
||||
char *basename_n(const char *path, size_t size) {
|
||||
textstartup char *basename_n(const char *path, size_t size) {
|
||||
size_t i, l;
|
||||
if (size) {
|
||||
if (isslash(path[size - 1])) {
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#ifndef COSMOPOLITAN_LIBC_CONV_CONV_H_
|
||||
#define COSMOPOLITAN_LIBC_CONV_CONV_H_
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/calls/struct/timeval.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § conversion ─╬─│┼
|
||||
|
@ -23,6 +26,7 @@ long labs(long) libcesque pureconst;
|
|||
long long llabs(long long) libcesque pureconst;
|
||||
char *ltpcpy(char *, long) paramsnonnull() libcesque nocallback;
|
||||
int llog10(unsigned long) libcesque pureconst;
|
||||
int unsleb128(const void *, size_t, int64_t *);
|
||||
int atoi(const char *) paramsnonnull() libcesque nosideeffect;
|
||||
long atol(const char *) paramsnonnull() libcesque nosideeffect;
|
||||
long long atoll(const char *) paramsnonnull() libcesque nosideeffect;
|
||||
|
@ -38,18 +42,12 @@ long wcstol(const wchar_t *, wchar_t **, int);
|
|||
long strtol(const char *, char **, int)
|
||||
paramsnonnull((1)) libcesque nosideeffect;
|
||||
|
||||
intmax_t __imaxabs(intmax_t) asm("imaxabs") libcesque pureconst;
|
||||
#define imaxabs(x) __imaxabs(x)
|
||||
|
||||
/*───────────────────────────────────────────────────────────────────────────│─╗
|
||||
│ cosmopolitan § conversion » time ─╬─│┼
|
||||
╚────────────────────────────────────────────────────────────────────────────│*/
|
||||
|
||||
struct NtFileTime;
|
||||
struct timespec;
|
||||
struct timeval;
|
||||
|
||||
void filetimetotimespec(struct timespec *, struct NtFileTime) paramsnonnull();
|
||||
struct timespec filetimetotimespec(struct NtFileTime);
|
||||
struct NtFileTime timespectofiletime(struct timespec);
|
||||
struct NtFileTime timetofiletime(int64_t) nothrow pureconst;
|
||||
int64_t filetimetotime(struct NtFileTime) nothrow pureconst;
|
||||
void filetimetotimeval(struct timeval *, struct NtFileTime) nothrow;
|
||||
|
@ -104,6 +102,11 @@ double RoundDecimalPlaces(double, double, double(double));
|
|||
#define lldiv(num, den) ((lldiv_t){(num) / (den), (num) % (den)})
|
||||
#endif
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
intmax_t __imaxabs(intmax_t) asm("imaxabs") libcesque pureconst;
|
||||
#define imaxabs(x) __imaxabs(x)
|
||||
#endif /* !ANSI */
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
#endif /* COSMOPOLITAN_LIBC_CONV_CONV_H_ */
|
||||
|
|
|
@ -38,7 +38,8 @@ LIBC_CONV_A_DIRECTDEPS = \
|
|||
LIBC_STUBS \
|
||||
LIBC_NEXGEN32E \
|
||||
LIBC_TINYMATH \
|
||||
LIBC_SYSV
|
||||
LIBC_SYSV \
|
||||
THIRD_PARTY_COMPILER_RT
|
||||
|
||||
LIBC_CONV_A_DEPS := \
|
||||
$(call uniq,$(foreach x,$(LIBC_CONV_A_DIRECTDEPS),$($(x))))
|
||||
|
@ -51,12 +52,10 @@ $(LIBC_CONV_A).pkg: \
|
|||
$(LIBC_CONV_A_OBJS) \
|
||||
$(foreach x,$(LIBC_CONV_A_DIRECTDEPS),$($(x)_A).pkg)
|
||||
|
||||
#o/$(MODE)/libc/conv/strtoimax.o: CC = clang-10
|
||||
#o/$(MODE)/libc/conv/strtoumax.o: CC = clang-10
|
||||
|
||||
o/$(MODE)/libc/conv/itoa64radix10.o \
|
||||
o/$(MODE)/libc/conv/itoa64radix10.greg.o \
|
||||
o/$(MODE)/libc/conv/timetofiletime.o \
|
||||
o/$(MODE)/libc/conv/filetimetotime.o \
|
||||
o/$(MODE)/libc/conv/timespectofiletime.o \
|
||||
o/$(MODE)/libc/conv/filetimetotimespec.o \
|
||||
o/$(MODE)/libc/conv/filetimetotimeval.o: \
|
||||
OVERRIDE_COPTS += \
|
||||
|
|
|
@ -24,9 +24,11 @@
|
|||
/**
|
||||
* Converts Windows COBOL timestamp to UNIX epoch in nanoseconds.
|
||||
*/
|
||||
void filetimetotimespec(struct timespec *ts, struct NtFileTime ft) {
|
||||
uint64_t t = (uint64_t)ft.dwHighDateTime << 32 | ft.dwLowDateTime;
|
||||
uint64_t x = t - MODERNITYSECONDS * HECTONANOSECONDS;
|
||||
ts->tv_sec = x / HECTONANOSECONDS;
|
||||
ts->tv_nsec = x % HECTONANOSECONDS * 100;
|
||||
struct timespec filetimetotimespec(struct NtFileTime ft) {
|
||||
uint64_t x;
|
||||
x = ft.dwHighDateTime;
|
||||
x <<= 32;
|
||||
x |= ft.dwLowDateTime;
|
||||
x -= MODERNITYSECONDS;
|
||||
return (struct timespec){x / HECTONANOSECONDS, x % HECTONANOSECONDS * 100};
|
||||
}
|
||||
|
|
|
@ -23,13 +23,17 @@ COSMOPOLITAN_C_START_
|
|||
|
||||
*/
|
||||
|
||||
size_t int128toarray_radix10(int128_t, char *);
|
||||
size_t uint128toarray_radix10(uint128_t, char *);
|
||||
size_t int64toarray_radix10(int64_t, char *);
|
||||
size_t uint64toarray_radix10(uint64_t, char *);
|
||||
size_t int64toarray(int64_t, char *, int);
|
||||
size_t uint64toarray(uint64_t, char *, int);
|
||||
size_t uint64toarray_radix16(uint64_t, char[hasatleast 17]);
|
||||
size_t uint64toarray_fixed16(uint64_t, char[hasatleast 17], uint8_t);
|
||||
|
||||
#ifndef __STRICT_ANSI__
|
||||
size_t int128toarray_radix10(int128_t, char *);
|
||||
size_t uint128toarray_radix10(uint128_t, char *);
|
||||
#endif
|
||||
|
||||
COSMOPOLITAN_C_END_
|
||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||
|
|
|
@ -20,13 +20,21 @@
|
|||
#include "libc/alg/reverse.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
uint128_t __udivmodti4(uint128_t, uint128_t, uint128_t *);
|
||||
|
||||
/**
|
||||
* Converts unsigned 128-bit integer to string.
|
||||
* @param a needs at least 40 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
|
||||
size_t j;
|
||||
unsigned rem;
|
||||
uint128_t rem;
|
||||
j = 0;
|
||||
do {
|
||||
i = div10(i, &rem);
|
||||
i = __udivmodti4(i, 10, &rem);
|
||||
a[j++] = rem + '0';
|
||||
} while (i > 0);
|
||||
a[j] = '\0';
|
||||
|
@ -34,10 +42,21 @@ noinline size_t uint128toarray_radix10(uint128_t i, char *a) {
|
|||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts signed 128-bit integer to string.
|
||||
* @param a needs at least 41 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
size_t int128toarray_radix10(int128_t i, char *a) {
|
||||
if (i < 0) {
|
||||
*a++ = '-';
|
||||
i = -i;
|
||||
if (i != INT128_MIN) {
|
||||
*a++ = '-';
|
||||
return 1 + uint128toarray_radix10(-i, a);
|
||||
} else {
|
||||
memcpy(a, "-170141183460469231731687303715884105728", 41);
|
||||
return 40;
|
||||
}
|
||||
} else {
|
||||
return uint128toarray_radix10(i, a);
|
||||
}
|
||||
return uint128toarray_radix10(i, a);
|
||||
}
|
||||
|
|
38
libc/conv/itoa64fixed16.greg.c
Normal file
38
libc/conv/itoa64fixed16.greg.c
Normal file
|
@ -0,0 +1,38 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/alg/reverse.h"
|
||||
#include "libc/assert.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
|
||||
size_t uint64toarray_fixed16(uint64_t i, char a[hasatleast 17], uint8_t b) {
|
||||
size_t j;
|
||||
assert(b <= 64);
|
||||
assert(b % 4 == 0);
|
||||
j = 0;
|
||||
if (b) {
|
||||
do {
|
||||
a[j++] = "0123456789abcdef"[i & 15];
|
||||
i >>= 4;
|
||||
} while (b -= 4);
|
||||
}
|
||||
a[j] = '\0';
|
||||
reverse(a, j);
|
||||
return j;
|
||||
}
|
|
@ -20,7 +20,13 @@
|
|||
#include "libc/alg/reverse.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/conv/itoa.h"
|
||||
#include "libc/limits.h"
|
||||
|
||||
/**
|
||||
* Converts unsigned 64-bit integer to string.
|
||||
* @param a needs at least 21 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
noinline size_t uint64toarray_radix10(uint64_t i, char *a) {
|
||||
size_t j;
|
||||
j = 0;
|
||||
|
@ -33,10 +39,21 @@ noinline size_t uint64toarray_radix10(uint64_t i, char *a) {
|
|||
return j;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts signed 64-bit integer to string.
|
||||
* @param a needs at least 21 bytes
|
||||
* @return bytes written w/o nul
|
||||
*/
|
||||
size_t int64toarray_radix10(int64_t i, char *a) {
|
||||
if (i < 0) {
|
||||
*a++ = '-';
|
||||
i = -i;
|
||||
if (i != INT64_MIN) {
|
||||
*a++ = '-';
|
||||
return 1 + uint64toarray_radix10(-i, a);
|
||||
} else {
|
||||
memcpy(a, "-9223372036854775808", 21);
|
||||
return 20;
|
||||
}
|
||||
} else {
|
||||
return uint64toarray_radix10(i, a);
|
||||
}
|
||||
return uint64toarray_radix10(i, a);
|
||||
}
|
||||
|
|
|
@ -22,11 +22,9 @@
|
|||
|
||||
size_t uint64toarray_radix16(uint64_t i, char a[hasatleast 17]) {
|
||||
size_t j;
|
||||
unsigned char d;
|
||||
j = 0;
|
||||
do {
|
||||
d = i % 16;
|
||||
a[j++] = d < 10 ? d + '0' : d + 'a';
|
||||
a[j++] = "0123456789abcdef"[i % 16];
|
||||
i /= 16;
|
||||
} while (i > 0);
|
||||
a[j] = '\0';
|
||||
|
|
|
@ -76,6 +76,10 @@ intmax_t strtoimax(const char *s, char **endptr, int base) {
|
|||
} else {
|
||||
base = 10;
|
||||
}
|
||||
} else if (*s == '0') {
|
||||
++s;
|
||||
if (base == 2 && *s == 'b' && *s == 'B') ++s;
|
||||
if (base == 16 && *s == 'x' && *s == 'X') ++s;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
|
@ -28,7 +28,10 @@
|
|||
*/
|
||||
uintmax_t strtoumax(const char *s, char **endptr, int base) {
|
||||
const unsigned char *p = (const unsigned char *)s;
|
||||
uintmax_t res = 0;
|
||||
unsigned diglet;
|
||||
uintmax_t res;
|
||||
|
||||
res = 0;
|
||||
|
||||
while (isspace(*p)) {
|
||||
p++;
|
||||
|
@ -49,10 +52,14 @@ uintmax_t strtoumax(const char *s, char **endptr, int base) {
|
|||
} else {
|
||||
base = 10;
|
||||
}
|
||||
} else if (*s == '0') {
|
||||
++s;
|
||||
if (base == 2 && *s == 'b' && *s == 'B') ++s;
|
||||
if (base == 16 && *s == 'x' && *s == 'X') ++s;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
unsigned diglet = kBase36[*p];
|
||||
diglet = kBase36[*p];
|
||||
if (!diglet || diglet > base) break;
|
||||
p++;
|
||||
res *= base;
|
||||
|
|
34
libc/conv/timespectofiletime.c
Normal file
34
libc/conv/timespectofiletime.c
Normal file
|
@ -0,0 +1,34 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/conv/conv.h"
|
||||
#include "libc/nexgen32e/nexgen32e.h"
|
||||
#include "libc/nt/struct/filetime.h"
|
||||
|
||||
/**
|
||||
* Converts UNIX nanosecond timestamp to Windows COBOL timestamp.
|
||||
*/
|
||||
struct NtFileTime timespectofiletime(struct timespec ts) {
|
||||
uint64_t x;
|
||||
x = MODERNITYSECONDS;
|
||||
x += ts.tv_sec * HECTONANOSECONDS;
|
||||
x += div100int64(ts.tv_nsec);
|
||||
return (struct NtFileTime){x, x >> 32};
|
||||
}
|
45
libc/conv/unsleb128.c
Normal file
45
libc/conv/unsleb128.c
Normal file
|
@ -0,0 +1,45 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2020 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ This program is free software; you can redistribute it and/or modify │
|
||||
│ it under the terms of the GNU General Public License as published by │
|
||||
│ the Free Software Foundation; version 2 of the License. │
|
||||
│ │
|
||||
│ This program 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 │
|
||||
│ General Public License for more details. │
|
||||
│ │
|
||||
│ You should have received a copy of the GNU General Public License │
|
||||
│ along with this program; if not, write to the Free Software │
|
||||
│ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA │
|
||||
│ 02110-1301 USA │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/conv/conv.h"
|
||||
|
||||
/**
|
||||
* Decodes a GNU-style varint from a buffer.
|
||||
*
|
||||
* The GNU Assembler is able to encode numbers this way, since it's used
|
||||
* by the DWARF debug format.
|
||||
*/
|
||||
int unsleb128(const void *buf, size_t size, int64_t *out) {
|
||||
int b;
|
||||
int64_t r, w;
|
||||
unsigned char c;
|
||||
const unsigned char *p, *pe;
|
||||
pe = (p = buf) + size;
|
||||
r = b = 0;
|
||||
do {
|
||||
if (size && p == pe) return -1;
|
||||
c = *p++;
|
||||
w = c & 0x7f;
|
||||
r |= w << b;
|
||||
b += 7;
|
||||
} while (c & 0x80);
|
||||
if (c & 0x40) r |= -1ull << b;
|
||||
if (out) *out = r;
|
||||
return p - (const unsigned char *)buf;
|
||||
}
|
|
@ -24,21 +24,22 @@
|
|||
.section .start,"ax",@progbits
|
||||
.source __FILE__
|
||||
|
||||
nop
|
||||
|
||||
/ System Five userspace program entrypoint.
|
||||
/
|
||||
/ @param rsp is [n,argv₀..argvₙ₋₁,0,envp₀..,0,auxv₀..,0,..]
|
||||
/ @note FreeBSD is special (see freebsd/lib/csu/amd64/...)
|
||||
/ @noreturn
|
||||
_start_xnu:
|
||||
movb $XNU,hostos(%rip)
|
||||
jmp 0f
|
||||
_start: test %rdi,%rdi
|
||||
cmovnz %rdi,%rsp
|
||||
jz 0f
|
||||
movb $FREEBSD,hostos(%rip)
|
||||
0: movslq (%rsp),%r12 # argc
|
||||
lea 8(%rsp),%r13 # argv
|
||||
lea 24(%rsp,%r12,8),%r14 # envp
|
||||
0: mov (%rsp),%ebx # argc
|
||||
lea 8(%rsp),%rsi # argv
|
||||
lea 24(%rsp,%rbx,8),%rdx # envp
|
||||
.frame0
|
||||
bofram 9f
|
||||
.weak idata.iat,idata.iatend
|
||||
ezlea missingno,ax # make win32 imps noop
|
||||
ezlea idata.iat,di
|
||||
|
@ -48,9 +49,21 @@ _start: test %rdi,%rdi
|
|||
rep stosq
|
||||
xor %eax,%eax # find end of environ
|
||||
or $-1,%ecx
|
||||
mov %r14,%rdi
|
||||
mov %rdx,%rdi
|
||||
repnz scasq
|
||||
mov %rdi,%r15 # auxv
|
||||
jmp __executive
|
||||
.endfn _start,weak,hidden
|
||||
mov %rdi,%rcx # auxv
|
||||
mov %ebx,%edi
|
||||
call _executive
|
||||
9: .endfn _start,weak,hidden
|
||||
|
||||
ud2
|
||||
|
||||
/ Macintosh userspace program entrypoint.
|
||||
/
|
||||
/ @param rsp is [n,argv₀..argvₙ₋₁,0,envp₀..,0,auxv₀..,0,..]
|
||||
/ @note FreeBSD is special (see freebsd/lib/csu/amd64/...)
|
||||
/ @noreturn
|
||||
_start_xnu:
|
||||
movb $XNU,hostos(%rip)
|
||||
jmp 0b
|
||||
.endfn _start_xnu,weak,hidden
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue