From 830334d76701bfff8e2c4544a6bbc6c5b499f33a Mon Sep 17 00:00:00 2001 From: Justine Tunney Date: Thu, 24 Dec 2020 16:01:48 -0800 Subject: [PATCH] Hunt down some small bugs --- libc/calls/getuid.c | 10 +- libc/str/highwayhash64.c | 166 ++++ libc/str/highwayhash64.h | 10 + libc/str/knuthmultiplicativehash.internal.h | 15 - test/libc/nexgen32e/crc32_test.c | 7 - test/libc/str/highwayhash64_test.c | 108 +++ third_party/chibicc/as.c | 101 ++- third_party/chibicc/chibicc.mk | 9 + third_party/chibicc/test/initializer_test.c | 802 ++++++++++++++++++++ third_party/dlmalloc/dlmalloc.internal.h | 2 +- tool/build/ar.c | 1 - tool/build/lib/interner.c | 4 +- tool/build/mkdeps.c | 1 - tool/decode/lib/asmcodegen.c | 2 +- tool/decode/lib/elfidnames.c | 1 + 15 files changed, 1156 insertions(+), 83 deletions(-) create mode 100644 libc/str/highwayhash64.c create mode 100644 libc/str/highwayhash64.h delete mode 100644 libc/str/knuthmultiplicativehash.internal.h create mode 100644 test/libc/str/highwayhash64_test.c create mode 100644 third_party/chibicc/test/initializer_test.c diff --git a/libc/calls/getuid.c b/libc/calls/getuid.c index 97c93521..5464eac4 100644 --- a/libc/calls/getuid.c +++ b/libc/calls/getuid.c @@ -23,10 +23,18 @@ #include "libc/macros.h" #include "libc/nt/accounting.h" #include "libc/runtime/runtime.h" -#include "libc/str/knuthmultiplicativehash.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/auxv.h" +static uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) { + size_t i; + uint32_t h; + const uint32_t kPhiPrime = 0x9e3779b1; + const unsigned char *p = (const unsigned char *)buf; + for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime; + return h; +} + static textwindows noinline uint32_t GetUserNameHash(void) { char16_t buf[257]; uint32_t size = ARRAYLEN(buf); diff --git a/libc/str/highwayhash64.c b/libc/str/highwayhash64.c new file mode 100644 index 00000000..c013ef7a --- /dev/null +++ b/libc/str/highwayhash64.c @@ -0,0 +1,166 @@ +/*-*- 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 2017 Google LLC │ +│ │ +│ Licensed under the Apache License, Version 2.0 (the "License"); │ +│ you may not use this file except in compliance with the License. │ +│ You may obtain a copy of the License at │ +│ │ +│ http://www.apache.org/licenses/LICENSE-2.0 │ +│ │ +│ Unless required by applicable law or agreed to in writing, software │ +│ distributed under the License is distributed on an "AS IS" BASIS, │ +│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ +│ See the License for the specific language governing permissions and │ +│ limitations under the License. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/str/highwayhash64.h" + +asm(".ident\t\"\\n\\n\ +HighwayHash (Apache 2.0)\\n\ +Copyright 2017 Google LLC\""); +asm(".include \"libc/disclaimer.inc\""); + +typedef struct { + uint64_t v0[4]; + uint64_t v1[4]; + uint64_t mul0[4]; + uint64_t mul1[4]; +} HighwayHashState; + +static void HighwayHashReset(const uint64_t key[4], HighwayHashState *state) { + state->mul0[0] = 0xdbe6d5d5fe4cce2full; + state->mul0[1] = 0xa4093822299f31d0ull; + state->mul0[2] = 0x13198a2e03707344ull; + state->mul0[3] = 0x243f6a8885a308d3ull; + state->mul1[0] = 0x3bd39e10cb0ef593ull; + state->mul1[1] = 0xc0acf169b5f18a8cull; + state->mul1[2] = 0xbe5466cf34e90c6cull; + state->mul1[3] = 0x452821e638d01377ull; + state->v0[0] = state->mul0[0] ^ key[0]; + state->v0[1] = state->mul0[1] ^ key[1]; + state->v0[2] = state->mul0[2] ^ key[2]; + state->v0[3] = state->mul0[3] ^ key[3]; + state->v1[0] = state->mul1[0] ^ ((key[0] >> 32) | (key[0] << 32)); + state->v1[1] = state->mul1[1] ^ ((key[1] >> 32) | (key[1] << 32)); + state->v1[2] = state->mul1[2] ^ ((key[2] >> 32) | (key[2] << 32)); + state->v1[3] = state->mul1[3] ^ ((key[3] >> 32) | (key[3] << 32)); +} + +static void ZipperMergeAndAdd(const uint64_t v1, const uint64_t v0, + uint64_t *add1, uint64_t *add0) { + *add0 += (((v0 & 0xff000000ull) | (v1 & 0xff00000000ull)) >> 24) | + (((v0 & 0xff0000000000ull) | (v1 & 0xff000000000000ull)) >> 16) | + (v0 & 0xff0000ull) | ((v0 & 0xff00ull) << 32) | + ((v1 & 0xff00000000000000ull) >> 8) | (v0 << 56); + *add1 += (((v1 & 0xff000000ull) | (v0 & 0xff00000000ull)) >> 24) | + (v1 & 0xff0000ull) | ((v1 & 0xff0000000000ull) >> 16) | + ((v1 & 0xff00ull) << 24) | ((v0 & 0xff000000000000ull) >> 8) | + ((v1 & 0xffull) << 48) | (v0 & 0xff00000000000000ull); +} + +static void Update(const uint64_t lanes[4], HighwayHashState *state) { + int i; + for (i = 0; i < 4; ++i) { + state->v1[i] += state->mul0[i] + lanes[i]; + state->mul0[i] ^= (state->v1[i] & 0xffffffff) * (state->v0[i] >> 32); + state->v0[i] += state->mul1[i]; + state->mul1[i] ^= (state->v0[i] & 0xffffffff) * (state->v1[i] >> 32); + } + ZipperMergeAndAdd(state->v1[1], state->v1[0], &state->v0[1], &state->v0[0]); + ZipperMergeAndAdd(state->v1[3], state->v1[2], &state->v0[3], &state->v0[2]); + ZipperMergeAndAdd(state->v0[1], state->v0[0], &state->v1[1], &state->v1[0]); + ZipperMergeAndAdd(state->v0[3], state->v0[2], &state->v1[3], &state->v1[2]); +} + +static uint64_t Read64(const uint8_t *src) { + return (uint64_t)src[0] | ((uint64_t)src[1] << 8) | ((uint64_t)src[2] << 16) | + ((uint64_t)src[3] << 24) | ((uint64_t)src[4] << 32) | + ((uint64_t)src[5] << 40) | ((uint64_t)src[6] << 48) | + ((uint64_t)src[7] << 56); +} + +static void HighwayHashUpdatePacket(const uint8_t *packet, + HighwayHashState *state) { + uint64_t lanes[4]; + lanes[0] = Read64(packet + 0); + lanes[1] = Read64(packet + 8); + lanes[2] = Read64(packet + 16); + lanes[3] = Read64(packet + 24); + Update(lanes, state); +} + +static void Rotate32By(uint64_t count, uint64_t lanes[4]) { + int i; + for (i = 0; i < 4; ++i) { + uint32_t half0 = lanes[i] & 0xffffffff; + uint32_t half1 = (lanes[i] >> 32); + lanes[i] = (half0 << count) | (half0 >> (32 - count)); + lanes[i] |= (uint64_t)((half1 << count) | (half1 >> (32 - count))) << 32; + } +} + +static void HighwayHashUpdateRemainder(const uint8_t *bytes, + const size_t size_mod32, + HighwayHashState *state) { + int i; + const size_t size_mod4 = size_mod32 & 3; + const uint8_t *remainder = bytes + (size_mod32 & ~3); + uint8_t packet[32] = {0}; + for (i = 0; i < 4; ++i) { + state->v0[i] += ((uint64_t)size_mod32 << 32) + size_mod32; + } + Rotate32By(size_mod32, state->v1); + for (i = 0; i < remainder - bytes; i++) { + packet[i] = bytes[i]; + } + if (size_mod32 & 16) { + for (i = 0; i < 4; i++) { + packet[28 + i] = remainder[i + size_mod4 - 4]; + } + } else { + if (size_mod4) { + packet[16 + 0] = remainder[0]; + packet[16 + 1] = remainder[size_mod4 >> 1]; + packet[16 + 2] = remainder[size_mod4 - 1]; + } + } + HighwayHashUpdatePacket(packet, state); +} + +static void Permute(const uint64_t v[4], uint64_t *permuted) { + permuted[0] = (v[2] >> 32) | (v[2] << 32); + permuted[1] = (v[3] >> 32) | (v[3] << 32); + permuted[2] = (v[0] >> 32) | (v[0] << 32); + permuted[3] = (v[1] >> 32) | (v[1] << 32); +} + +static void PermuteAndUpdate(HighwayHashState *state) { + uint64_t permuted[4]; + Permute(state->v0, permuted); + Update(permuted, state); +} + +static uint64_t HighwayHashFinalize64(HighwayHashState *state) { + int i; + for (i = 0; i < 4; i++) PermuteAndUpdate(state); + return state->v0[0] + state->v1[0] + state->mul0[0] + state->mul1[0]; +} + +static void ProcessAll(const uint8_t *data, size_t size, const uint64_t key[4], + HighwayHashState *state) { + size_t i; + HighwayHashReset(key, state); + for (i = 0; i + 32 <= size; i += 32) { + HighwayHashUpdatePacket(data + i, state); + } + if ((size & 31) != 0) HighwayHashUpdateRemainder(data + i, size & 31, state); +} + +uint64_t HighwayHash64(const uint8_t *data, size_t size, + const uint64_t key[4]) { + HighwayHashState state; + ProcessAll(data, size, key, &state); + return HighwayHashFinalize64(&state); +} diff --git a/libc/str/highwayhash64.h b/libc/str/highwayhash64.h new file mode 100644 index 00000000..d3cf882c --- /dev/null +++ b/libc/str/highwayhash64.h @@ -0,0 +1,10 @@ +#ifndef COSMOPOLITAN_LIBC_STR_HIGHWAYHASH64_H_ +#define COSMOPOLITAN_LIBC_STR_HIGHWAYHASH64_H_ +#if !(__ASSEMBLER__ + __LINKER__ + 0) +COSMOPOLITAN_C_START_ + +uint64_t HighwayHash64(const uint8_t *, size_t, const uint64_t[4]); + +COSMOPOLITAN_C_END_ +#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ +#endif /* COSMOPOLITAN_LIBC_STR_HIGHWAYHASH64_H_ */ diff --git a/libc/str/knuthmultiplicativehash.internal.h b/libc/str/knuthmultiplicativehash.internal.h deleted file mode 100644 index 872f1bf9..00000000 --- a/libc/str/knuthmultiplicativehash.internal.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef COSMOPOLITAN_LIBC_STR_KNUTHMULTIPLICATIVEHASH_H_ -#define COSMOPOLITAN_LIBC_STR_KNUTHMULTIPLICATIVEHASH_H_ -#if !(__ASSEMBLER__ + __LINKER__ + 0) - -forceinline uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) { - size_t i; - uint32_t h; - const uint32_t kPhiPrime = 0x9e3779b1; - const unsigned char *p = (const unsigned char *)buf; - for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime; - return h; -} - -#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */ -#endif /* COSMOPOLITAN_LIBC_STR_KNUTHMULTIPLICATIVEHASH_H_ */ diff --git a/test/libc/nexgen32e/crc32_test.c b/test/libc/nexgen32e/crc32_test.c index 2e7a5722..d5d36471 100644 --- a/test/libc/nexgen32e/crc32_test.c +++ b/test/libc/nexgen32e/crc32_test.c @@ -20,7 +20,6 @@ #include "libc/macros.h" #include "libc/nexgen32e/crc32.h" #include "libc/nexgen32e/x86feature.h" -#include "libc/str/knuthmultiplicativehash.internal.h" #include "libc/str/str.h" #include "libc/testlib/ezbench.h" #include "libc/testlib/hyperion.h" @@ -49,9 +48,3 @@ BENCH(crc32c, bench) { EZBENCH2("crc32c", donothing, EXPROPRIATE(crc32c(0, VEIL("r", TESTSTR), sizeof(TESTSTR) - 1))); } - -BENCH(KnuthMultiplicativeHash32, bench) { - EZBENCH2("KMP", donothing, - EXPROPRIATE(KnuthMultiplicativeHash32(VEIL("r", TESTSTR), - sizeof(TESTSTR) - 1))); -} diff --git a/test/libc/str/highwayhash64_test.c b/test/libc/str/highwayhash64_test.c new file mode 100644 index 00000000..0c7bb7f3 --- /dev/null +++ b/test/libc/str/highwayhash64_test.c @@ -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 2017 Google LLC │ +│ │ +│ Licensed under the Apache License, Version 2.0 (the "License"); │ +│ you may not use this file except in compliance with the License. │ +│ You may obtain a copy of the License at │ +│ │ +│ http://www.apache.org/licenses/LICENSE-2.0 │ +│ │ +│ Unless required by applicable law or agreed to in writing, software │ +│ distributed under the License is distributed on an "AS IS" BASIS, │ +│ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. │ +│ See the License for the specific language governing permissions and │ +│ limitations under the License. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/inttypes.h" +#include "libc/nexgen32e/crc32.h" +#include "libc/stdio/stdio.h" +#include "libc/str/highwayhash64.h" +#include "libc/str/str.h" +#include "libc/testlib/ezbench.h" +#include "libc/testlib/hyperion.h" +#include "libc/testlib/testlib.h" + +#define kMaxSize 64 + +static const uint64_t kTestKey1[4] = { + 0x0706050403020100ull, + 0x0F0E0D0C0B0A0908ull, + 0x1716151413121110ull, + 0x1F1E1D1C1B1A1918ull, +}; + +static const uint64_t kTestKey2[4] = {1ull, 2ull, 3ull, 4ull}; + +const uint64_t kExpected64[kMaxSize + 1] = { + 0x907A56DE22C26E53ull, 0x7EAB43AAC7CDDD78ull, 0xB8D0569AB0B53D62ull, + 0x5C6BEFAB8A463D80ull, 0xF205A46893007EDAull, 0x2B8A1668E4A94541ull, + 0xBD4CCC325BEFCA6Full, 0x4D02AE1738F59482ull, 0xE1205108E55F3171ull, + 0x32D2644EC77A1584ull, 0xF6E10ACDB103A90Bull, 0xC3BBF4615B415C15ull, + 0x243CC2040063FA9Cull, 0xA89A58CE65E641FFull, 0x24B031A348455A23ull, + 0x40793F86A449F33Bull, 0xCFAB3489F97EB832ull, 0x19FE67D2C8C5C0E2ull, + 0x04DD90A69C565CC2ull, 0x75D9518E2371C504ull, 0x38AD9B1141D3DD16ull, + 0x0264432CCD8A70E0ull, 0xA9DB5A6288683390ull, 0xD7B05492003F028Cull, + 0x205F615AEA59E51Eull, 0xEEE0C89621052884ull, 0x1BFC1A93A7284F4Full, + 0x512175B5B70DA91Dull, 0xF71F8976A0A2C639ull, 0xAE093FEF1F84E3E7ull, + 0x22CA92B01161860Full, 0x9FC7007CCF035A68ull, 0xA0C964D9ECD580FCull, + 0x2C90F73CA03181FCull, 0x185CF84E5691EB9Eull, 0x4FC1F5EF2752AA9Bull, + 0xF5B7391A5E0A33EBull, 0xB9B84B83B4E96C9Cull, 0x5E42FE712A5CD9B4ull, + 0xA150F2F90C3F97DCull, 0x7FA522D75E2D637Dull, 0x181AD0CC0DFFD32Bull, + 0x3889ED981E854028ull, 0xFB4297E8C586EE2Dull, 0x6D064A45BB28059Cull, + 0x90563609B3EC860Cull, 0x7AA4FCE94097C666ull, 0x1326BAC06B911E08ull, + 0xB926168D2B154F34ull, 0x9919848945B1948Dull, 0xA2A98FC534825EBEull, + 0xE9809095213EF0B6ull, 0x582E5483707BC0E9ull, 0x086E9414A88A6AF5ull, + 0xEE86B98D20F6743Dull, 0xF89B7FF609B1C0A7ull, 0x4C7D9CC19E22C3E8ull, + 0x9A97005024562A6Full, 0x5DD41CF423E6EBEFull, 0xDF13609C0468E227ull, + 0x6E0DA4F64188155Aull, 0xB755BA4B50D7D4A1ull, 0x887A3484647479BDull, + 0xAB8EEBE9BF2139A0ull, 0x75542C5D4CD2A6FFull, +}; + +uint32_t KnuthMultiplicativeHash32(const void *buf, size_t size) { + size_t i; + uint32_t h; + const uint32_t kPhiPrime = 0x9e3779b1; + const unsigned char *p = (const unsigned char *)buf; + for (h = i = 0; i < size; i++) h = (p[i] + h) * kPhiPrime; + return h; +} + +void TestHash64(uint64_t expected, const uint8_t *data, size_t size, + const uint64_t *key) { + uint64_t hash = HighwayHash64(data, size, key); + if (expected != hash) { + printf("Test failed: expected %016" PRIx64 ", got %016" PRIx64 + ", size: %d\n", + expected, hash, (int)size); + exit(1); + } +} + +TEST(highwayhash64, test) { + int i; + uint8_t data[kMaxSize + 1] = {0}; + for (i = 0; i <= kMaxSize; i++) { + data[i] = i; + TestHash64(kExpected64[i], data, i, kTestKey1); + } + for (i = 0; i < 33; i++) { + data[i] = 128 + i; + } + TestHash64(0x53c516cce478cad7ull, data, 33, kTestKey2); +} + +BENCH(highwayhash64, bench) { + EZBENCH2("crc32c small", donothing, crc32c(0, "hello", 5)); + EZBENCH2("knuth small", donothing, + EXPROPRIATE(KnuthMultiplicativeHash32(VEIL("r", "hello"), 5))); + EZBENCH2("highwayhash64 small", donothing, + HighwayHash64((void *)"hello", 5, kTestKey1)); + EZBENCH2("crc32c big", donothing, crc32c(0, kHyperion, kHyperionSize)); + EZBENCH2("knuth big", donothing, + EXPROPRIATE( + KnuthMultiplicativeHash32(VEIL("r", kHyperion), kHyperionSize))); + EZBENCH2("highwayhash64 big", donothing, + HighwayHash64((void *)kHyperion, kHyperionSize, kTestKey1)); +} diff --git a/third_party/chibicc/as.c b/third_party/chibicc/as.c index 09b8d6df..6a6133d9 100644 --- a/third_party/chibicc/as.c +++ b/third_party/chibicc/as.c @@ -156,6 +156,7 @@ struct As { int inpath; // strings int outpath; // strings int counter; + int pcrelative; bool inhibiterr; bool inhibitwarn; struct Ints { @@ -1320,14 +1321,14 @@ static int ParseEquality(struct As *a, int *rest, int i) { if (IsPunct(a, i, '=' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { - a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x & 63; + a->exprs.p[x].x = a->exprs.p[x].x == a->exprs.p[y].x; } else { x = NewBinary(a, EX_EQ, x, y); } } else if (IsPunct(a, i, '!' << 8 | '=')) { y = ParseRelational(a, &i, i + 1); if (a->exprs.p[x].kind == EX_INT || a->exprs.p[y].kind == EX_INT) { - a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x & 63; + a->exprs.p[x].x = a->exprs.p[x].x != a->exprs.p[y].x; } else { x = NewBinary(a, EX_NE, x, y); } @@ -1878,73 +1879,44 @@ static void OnSize(struct As *a, struct Slice s) { a->symbols.p[i].size = GetInt(a); } -static void OnInternal(struct As *a, struct Slice s) { +static void OpVisibility(struct As *a, int visibility) { int i; while (IsSlice(a, a->i)) { i = GetSymbol(a, a->things.p[a->i++].i); - a->symbols.p[i].stv = STV_INTERNAL; + a->symbols.p[i].stv = visibility; } } +static void OnInternal(struct As *a, struct Slice s) { + OpVisibility(a, STV_INTERNAL); +} + static void OnHidden(struct As *a, struct Slice s) { - int i; - while (IsSlice(a, a->i)) { - i = GetSymbol(a, a->things.p[a->i++].i); - a->symbols.p[i].stv = STV_HIDDEN; - } + OpVisibility(a, STV_HIDDEN); } static void OnProtected(struct As *a, struct Slice s) { + OpVisibility(a, STV_PROTECTED); +} + +static void OpBind(struct As *a, int bind) { int i; while (IsSlice(a, a->i)) { i = GetSymbol(a, a->things.p[a->i++].i); - a->symbols.p[i].stv = STV_PROTECTED; + a->symbols.p[i].stb = bind; } } static void OnLocal(struct As *a, struct Slice s) { - int i; - while (IsSlice(a, a->i)) { - i = GetSymbol(a, a->things.p[a->i++].i); - a->symbols.p[i].stb = STB_LOCAL; - } + OpBind(a, STB_LOCAL); } static void OnWeak(struct As *a, struct Slice s) { - int i; - while (IsSlice(a, a->i)) { - i = GetSymbol(a, a->things.p[a->i++].i); - a->symbols.p[i].stb = STB_WEAK; - } + OpBind(a, STB_WEAK); } static void OnGlobal(struct As *a, struct Slice s) { - int i; - while (IsSlice(a, a->i)) { - i = GetSymbol(a, a->things.p[a->i++].i); - a->symbols.p[i].stb = STB_GLOBAL; - } -} - -static bool IsSizableOp(const char *op, struct Slice s) { - int n = strlen(op); - if (n == s.n) return !memcmp(op, s.p, n); - if (n + 1 == s.n && !memcmp(op, s.p, n)) { - switch (s.p[n]) { - case 'b': - case 'B': - case 'w': - case 'W': - case 'l': - case 'L': - case 'q': - case 'Q': - return true; - default: - break; - } - } - return false; + OpBind(a, STB_GLOBAL); } static int GetOpSize(struct As *a, struct Slice s, int modrm, int i) { @@ -2183,18 +2155,21 @@ static void EmitModrm(struct As *a, int reg, int modrm, int disp) { if (modrm & ISREG) { EmitByte(a, 0300 | reg | modrm & 7); } else { - if (modrm & (HASBASE | HASINDEX)) { - if (modrm & ISRIP) { - EmitByte(a, 005 | reg); - } else { - EmitByte(a, 0204 | reg); // suboptimal - EmitByte(a, modrm); - } + if (modrm & ISRIP) { + EmitByte(a, 005 | reg); + } else if (modrm & (HASBASE | HASINDEX)) { + EmitByte(a, 0204 | reg); // suboptimal + EmitByte(a, modrm); } else { EmitByte(a, 004 | reg); EmitByte(a, 045); } - EmitExpr(a, disp, R_X86_64_32S, EmitLong); + EmitExpr( + a, disp, + a->pcrelative && ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX))) + ? a->pcrelative + : R_X86_64_32S, + EmitLong); } } @@ -2691,7 +2666,9 @@ static void OnCall(struct As *a, struct Slice s) { if (IsPunct(a, a->i, '*')) ++a->i; modrm = RemoveRexw(ParseModrm(a, &disp)); if (modrm & (ISREG | ISRIP | HASINDEX | HASBASE)) { + if (modrm & ISRIP) a->pcrelative = R_X86_64_GOTPCRELX; EmitRexOpModrm(a, 0xFF, 2, modrm, disp, 0); + a->pcrelative = 0; } else { EmitByte(a, 0xE8); EmitExpr(a, disp, R_X86_64_PC32, EmitLong); @@ -2703,7 +2680,12 @@ static noinline void OpJmpImpl(struct As *a, int cc) { if (IsPunct(a, a->i, '*')) ++a->i; modrm = RemoveRexw(ParseModrm(a, &disp)); if (cc == -1) { + if ((modrm & ISRIP) || !(modrm & (HASBASE | HASINDEX))) { + modrm |= ISRIP; + a->pcrelative = R_X86_64_GOTPCRELX; + } EmitRexOpModrm(a, 0xFF, 4, modrm, disp, 0); + a->pcrelative = 0; } else { EmitByte(a, 0x0F); EmitByte(a, 0x80 + cc); @@ -3795,6 +3777,15 @@ static void Write32(char b[4], int x) { b[3] = x >> 030; } +static void MarkUndefinedSymbolsGlobal(struct As *a) { + int i; + for (i = 0; i < a->symbols.n; ++i) { + if (!a->symbols.p[i].section && a->symbols.p[i].stb == STB_LOCAL) { + a->symbols.p[i].stb = STB_GLOBAL; + } + } +} + static void MarkUsedSymbols(struct As *a, int i) { if (i == -1) return; MarkUsedSymbols(a, a->exprs.p[i].lhs); @@ -3939,7 +3930,9 @@ void Assembler(int argc, char *argv[]) { /* PrintThings(a); */ Assemble(a); Evaluate(a); + MarkUndefinedSymbolsGlobal(a); Objectify(a, a->outpath); + malloc_stats(); FreeAssembler(a); } diff --git a/third_party/chibicc/chibicc.mk b/third_party/chibicc/chibicc.mk index 3244a195..67d0bd19 100644 --- a/third_party/chibicc/chibicc.mk +++ b/third_party/chibicc/chibicc.mk @@ -115,6 +115,15 @@ o/$(MODE)/third_party/chibicc/as.com.dbg: \ $(THIRD_PARTY_CHIBICC_A).pkg @$(APELINK) +o/$(MODE)/third_party/chibicc/hello.com.dbg: \ + $(THIRD_PARTY_CHIBICC_A_DEPS) \ + $(THIRD_PARTY_CHIBICC_A) \ + $(APE) \ + $(CRT) \ + o/$(MODE)/third_party/chibicc/hello.chibicc.o \ + $(THIRD_PARTY_CHIBICC_A).pkg + @$(APELINK) + o/$(MODE)/third_party/chibicc/chibicc.o: \ CPPFLAGS += $(THIRD_PARTY_CHIBICC_DEFINES) diff --git a/third_party/chibicc/test/initializer_test.c b/third_party/chibicc/test/initializer_test.c new file mode 100644 index 00000000..c8914f2c --- /dev/null +++ b/third_party/chibicc/test/initializer_test.c @@ -0,0 +1,802 @@ +#include "third_party/chibicc/test/test.h" + +char g3 = 3; +short g4 = 4; +int g5 = 5; +long g6 = 6; +int g9[3] = {0, 1, 2}; +struct { + char a; + int b; +} g11[2] = {{1, 2}, {3, 4}}; +struct { + int a[2]; +} g12[2] = {{{1, 2}}}; +union { + int a; + char b[8]; +} g13[2] = {0x01020304, 0x05060708}; +char g17[] = "foobar"; +char g18[10] = "foobar"; +char g19[3] = "foobar"; +char *g20 = g17 + 0; +char *g21 = g17 + 3; +char *g22 = &g17 - 3; +char *g23[] = {g17 + 0, g17 + 3, g17 - 3}; +int g24 = 3; +int *g25 = &g24; +int g26[3] = {1, 2, 3}; +int *g27 = g26 + 1; +int *g28 = &g11[1].a; +long g29 = (long)(long)g26; +struct { + struct { + int a[3]; + } a; +} g30 = {{{1, 2, 3}}}; +int *g31 = g30.a.a; +struct { + int a[2]; +} g40[2] = {{1, 2}, 3, 4}; +struct { + int a[2]; +} g41[2] = {1, 2, 3, 4}; +char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0}; +char *g44 = {"foo"}; +union { + int a; + char b[4]; +} g50 = {.b[2] = 0x12}; +union { + int a; +} g51[2] = {}; + +typedef char T60[]; +T60 g60 = {1, 2, 3}; +T60 g61 = {1, 2, 3, 4, 5, 6}; + +typedef struct { + char a, b[]; +} T65; +T65 g65 = {'f', 'o', 'o', 0}; +T65 g66 = {'f', 'o', 'o', 'b', 'a', 'r', 0}; + +int main() { + ASSERT(1, ({ + int x[3] = {1, 2, 3}; + x[0]; + })); + ASSERT(2, ({ + int x[3] = {1, 2, 3}; + x[1]; + })); + ASSERT(3, ({ + int x[3] = {1, 2, 3}; + x[2]; + })); + ASSERT(3, ({ + int x[3] = {1, 2, 3}; + x[2]; + })); + + ASSERT(2, ({ + int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; + x[0][1]; + })); + ASSERT(4, ({ + int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; + x[1][0]; + })); + ASSERT(6, ({ + int x[2][3] = {{1, 2, 3}, {4, 5, 6}}; + x[1][2]; + })); + + ASSERT(0, ({ + int x[3] = {}; + x[0]; + })); + ASSERT(0, ({ + int x[3] = {}; + x[1]; + })); + ASSERT(0, ({ + int x[3] = {}; + x[2]; + })); + + ASSERT(2, ({ + int x[2][3] = {{1, 2}}; + x[0][1]; + })); + ASSERT(0, ({ + int x[2][3] = {{1, 2}}; + x[1][0]; + })); + ASSERT(0, ({ + int x[2][3] = {{1, 2}}; + x[1][2]; + })); + + ASSERT('a', ({ + char x[4] = "abc"; + x[0]; + })); + ASSERT('c', ({ + char x[4] = "abc"; + x[2]; + })); + ASSERT(0, ({ + char x[4] = "abc"; + x[3]; + })); + ASSERT('a', ({ + char x[2][4] = {"abc", "def"}; + x[0][0]; + })); + ASSERT(0, ({ + char x[2][4] = {"abc", "def"}; + x[0][3]; + })); + ASSERT('d', ({ + char x[2][4] = {"abc", "def"}; + x[1][0]; + })); + ASSERT('f', ({ + char x[2][4] = {"abc", "def"}; + x[1][2]; + })); + + ASSERT(4, ({ + int x[] = {1, 2, 3, 4}; + x[3]; + })); + ASSERT(16, ({ + int x[] = {1, 2, 3, 4}; + sizeof(x); + })); + ASSERT(4, ({ + char x[] = "foo"; + sizeof(x); + })); + + ASSERT(4, ({ + typedef char T[]; + T x = "foo"; + T y = "x"; + sizeof(x); + })); + ASSERT(2, ({ + typedef char T[]; + T x = "foo"; + T y = "x"; + sizeof(y); + })); + ASSERT(2, ({ + typedef char T[]; + T x = "x"; + T y = "foo"; + sizeof(x); + })); + ASSERT(4, ({ + typedef char T[]; + T x = "x"; + T y = "foo"; + sizeof(y); + })); + + ASSERT(1, ({ + struct { + int a; + int b; + int c; + } x = {1, 2, 3}; + x.a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + int c; + } x = {1, 2, 3}; + x.b; + })); + ASSERT(3, ({ + struct { + int a; + int b; + int c; + } x = {1, 2, 3}; + x.c; + })); + ASSERT(1, ({ + struct { + int a; + int b; + int c; + } x = {1}; + x.a; + })); + ASSERT(0, ({ + struct { + int a; + int b; + int c; + } x = {1}; + x.b; + })); + ASSERT(0, ({ + struct { + int a; + int b; + int c; + } x = {1}; + x.c; + })); + + ASSERT(1, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[0].a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[0].b; + })); + ASSERT(3, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[1].a; + })); + ASSERT(4, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}, {3, 4}}; + x[1].b; + })); + + ASSERT(0, ({ + struct { + int a; + int b; + } x[2] = {{1, 2}}; + x[1].b; + })); + + ASSERT(0, ({ + struct { + int a; + int b; + } x = {}; + x.a; + })); + ASSERT(0, ({ + struct { + int a; + int b; + } x = {}; + x.b; + })); + + ASSERT(5, ({ + typedef struct { + int a, b, c, d, e, f; + } T; + T x = {1, 2, 3, 4, 5, 6}; + T y; + y = x; + y.e; + })); + ASSERT(2, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y, z; + z = y = x; + z.b; + })); + + ASSERT(1, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y = x; + y.a; + })); + + ASSERT(4, ({ + union { + int a; + char b[4]; + } x = {0x01020304}; + x.b[0]; + })); + ASSERT(3, ({ + union { + int a; + char b[4]; + } x = {0x01020304}; + x.b[1]; + })); + + ASSERT(0x01020304, ({ + union { + struct { + char a, b, c, d; + } e; + int f; + } x = {{4, 3, 2, 1}}; + x.f; + })); + + ASSERT(3, g3); + ASSERT(4, g4); + ASSERT(5, g5); + ASSERT(6, g6); + + ASSERT(0, g9[0]); + ASSERT(1, g9[1]); + ASSERT(2, g9[2]); + + ASSERT(1, g11[0].a); + ASSERT(2, g11[0].b); + ASSERT(3, g11[1].a); + ASSERT(4, g11[1].b); + + ASSERT(1, g12[0].a[0]); + ASSERT(2, g12[0].a[1]); + ASSERT(0, g12[1].a[0]); + ASSERT(0, g12[1].a[1]); + + ASSERT(4, g13[0].b[0]); + ASSERT(3, g13[0].b[1]); + ASSERT(8, g13[1].b[0]); + ASSERT(7, g13[1].b[1]); + + ASSERT(7, sizeof(g17)); + ASSERT(10, sizeof(g18)); + ASSERT(3, sizeof(g19)); + + ASSERT(0, memcmp(g17, "foobar", 7)); + ASSERT(0, memcmp(g18, "foobar\0\0\0", 10)); + ASSERT(0, memcmp(g19, "foo", 3)); + + ASSERT(0, strcmp(g20, "foobar")); + ASSERT(0, strcmp(g21, "bar")); + ASSERT(0, strcmp(g22 + 3, "foobar")); + + ASSERT(0, strcmp(g23[0], "foobar")); + ASSERT(0, strcmp(g23[1], "bar")); + ASSERT(0, strcmp(g23[2] + 3, "foobar")); + + ASSERT(3, g24); + ASSERT(3, *g25); + ASSERT(2, *g27); + ASSERT(3, *g28); + ASSERT(1, *(int *)g29); + + ASSERT(1, g31[0]); + ASSERT(2, g31[1]); + ASSERT(3, g31[2]); + + ASSERT(1, g40[0].a[0]); + ASSERT(2, g40[0].a[1]); + ASSERT(3, g40[1].a[0]); + ASSERT(4, g40[1].a[1]); + + ASSERT(1, g41[0].a[0]); + ASSERT(2, g41[0].a[1]); + ASSERT(3, g41[1].a[0]); + ASSERT(4, g41[1].a[1]); + + ASSERT(0, ({ + int x[2][3] = {0, 1, 2, 3, 4, 5}; + x[0][0]; + })); + ASSERT(3, ({ + int x[2][3] = {0, 1, 2, 3, 4, 5}; + x[1][0]; + })); + + ASSERT(0, ({ + struct { + int a; + int b; + } x[2] = {0, 1, 2, 3}; + x[0].a; + })); + ASSERT(2, ({ + struct { + int a; + int b; + } x[2] = {0, 1, 2, 3}; + x[1].a; + })); + + ASSERT(0, strcmp(g43[0], "foo")); + ASSERT(0, strcmp(g43[1], "bar")); + ASSERT(0, strcmp(g44, "foo")); + + ASSERT(3, ({ + int a[] = { + 1, + 2, + 3, + }; + a[2]; + })); + ASSERT(1, ({ + struct { + int a, b, c; + } x = { + 1, + 2, + 3, + }; + x.a; + })); + ASSERT(1, ({ + union { + int a; + char b; + } x = { + 1, + }; + x.a; + })); + ASSERT(2, ({ + enum { + x, + y, + z, + }; + z; + })); + + ASSERT(3, sizeof(g60)); + ASSERT(6, sizeof(g61)); + + ASSERT(4, sizeof(g65)); + ASSERT(7, sizeof(g66)); + ASSERT(0, strcmp(g65.b, "oo")); + ASSERT(0, strcmp(g66.b, "oobar")); + + ASSERT(4, ({ + int x[3] = {1, 2, 3, [0] = 4, 5}; + x[0]; + })); + ASSERT(5, ({ + int x[3] = {1, 2, 3, [0] = 4, 5}; + x[1]; + })); + ASSERT(3, ({ + int x[3] = {1, 2, 3, [0] = 4, 5}; + x[2]; + })); + + ASSERT(10, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[0][0]; + })); + ASSERT(11, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[0][1]; + })); + ASSERT(8, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[0][2]; + })); + ASSERT(12, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[1][0]; + })); + ASSERT(5, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[1][1]; + })); + ASSERT(6, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0][1] = 7, 8, [0] = 9, [0] = 10, 11, [1][0] = 12}; + x[1][2]; + })); + + ASSERT(7, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[0][0]; + })); + ASSERT(8, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[0][1]; + })); + ASSERT(3, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[0][2]; + })); + ASSERT(9, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[1][0]; + })); + ASSERT(10, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[1][1]; + })); + ASSERT(6, ({ + int x[2][3] = {1, 2, 3, 4, 5, 6, [0] = {7, 8}, 9, 10}; + x[1][2]; + })); + + ASSERT(7, ((int[10]){[3] = 7})[3]); + ASSERT(0, ((int[10]){[3] = 7})[4]); + + ASSERT(10, ({ + char x[] = {[10 - 3] = 1, 2, 3}; + sizeof(x); + })); + ASSERT(20, ({ + char x[][2] = {[8][1] = 1, 2}; + sizeof(x); + })); + + ASSERT(3, sizeof(g60)); + ASSERT(6, sizeof(g61)); + + ASSERT(4, sizeof(g65)); + ASSERT(7, sizeof(g66)); + ASSERT(0, strcmp(g65.b, "oo")); + ASSERT(0, strcmp(g66.b, "oobar")); + + ASSERT(7, ((int[10]){[3] 7})[3]); + ASSERT(0, ((int[10]){[3] 7})[4]); + + ASSERT(4, ({ + struct { + int a, b; + } x = {1, 2, .b = 3, .a = 4}; + x.a; + })); + ASSERT(3, ({ + struct { + int a, b; + } x = {1, 2, .b = 3, .a = 4}; + x.b; + })); + + ASSERT(1, ({ + struct { + struct { + int a, b; + } c; + } x = {.c = 1, 2}; + x.c.a; + })); + ASSERT(2, ({ + struct { + struct { + int a, b; + } c; + } x = {.c = 1, 2}; + x.c.b; + })); + + ASSERT(0, ({ + struct { + struct { + int a, b; + } c; + } x = {.c.b = 1}; + x.c.a; + })); + ASSERT(1, ({ + struct { + struct { + int a, b; + } c; + } x = {.c.b = 1}; + x.c.b; + })); + + ASSERT(1, ({ + struct { + int a[2]; + } x = {.a = 1, 2}; + x.a[0]; + })); + ASSERT(2, ({ + struct { + int a[2]; + } x = {.a = 1, 2}; + x.a[1]; + })); + + ASSERT(0, ({ + struct { + int a[2]; + } x = {.a[1] = 1}; + x.a[0]; + })); + ASSERT(1, ({ + struct { + int a[2]; + } x = {.a[1] = 1}; + x.a[1]; + })); + + ASSERT(3, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[0].a; + })); + ASSERT(4, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[0].b; + })); + ASSERT(0, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[1].a; + })); + ASSERT(1, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[1].b; + })); + ASSERT(2, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[2].a; + })); + ASSERT(0, ({ + struct { + int a, b; + } x[] = { + [1].b = 1, + 2, + [0] = 3, + 4, + }; + x[2].b; + })); + + ASSERT(1, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x}; + y[0].a; + })); + ASSERT(2, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x}; + y[0].b; + })); + ASSERT(0, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x, [0].b = 3}; + y[0].a; + })); + ASSERT(3, ({ + typedef struct { + int a, b; + } T; + T x = {1, 2}; + T y[] = {x, [0].b = 3}; + y[0].b; + })); + + ASSERT(5, ((struct { int a, b, c; }){.c = 5}).c); + ASSERT(0, ((struct { int a, b, c; }){.c = 5}).a); + + ASSERT(0x00ff, ({ + union { + unsigned short a; + char b[2]; + } x = {.b[0] = 0xff}; + x.a; + })); + ASSERT(0xff00, ({ + union { + unsigned short a; + char b[2]; + } x = {.b[1] = 0xff}; + x.a; + })); + + ASSERT(0x00120000, g50.a); + ASSERT(0, g51[0].a); + ASSERT(0, g51[1].a); + + ASSERT(1, ({ + struct { + struct { + int a; + struct { + int b; + }; + }; + int c; + } x = {1, 2, 3, .b = 4, 5}; + x.a; + })); + ASSERT(4, ({ + struct { + struct { + int a; + struct { + int b; + }; + }; + int c; + } x = {1, 2, 3, .b = 4, 5}; + x.b; + })); + ASSERT(5, ({ + struct { + struct { + int a; + struct { + int b; + }; + }; + int c; + } x = {1, 2, 3, .b = 4, 5}; + x.c; + })); + + ASSERT(16, ({ + char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'}; + sizeof(x); + })); + ASSERT(0, ({ + char x[] = {[2 ... 10] = 'a', [7] = 'b', [15 ... 15] = 'c', [3 ... 5] = 'd'}; + memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16); + })); + + return 0; +} diff --git a/third_party/dlmalloc/dlmalloc.internal.h b/third_party/dlmalloc/dlmalloc.internal.h index 6007e034..a88b8000 100644 --- a/third_party/dlmalloc/dlmalloc.internal.h +++ b/third_party/dlmalloc/dlmalloc.internal.h @@ -17,7 +17,7 @@ COSMOPOLITAN_C_START_ #define DLMALLOC_VERSION 20806 #ifndef FOOTERS -#define FOOTERS !IsTrustworthy() +#define FOOTERS !NoDebug() #endif #define HAVE_MMAP 1 diff --git a/tool/build/ar.c b/tool/build/ar.c index 086adf99..f1aed2bf 100644 --- a/tool/build/ar.c +++ b/tool/build/ar.c @@ -163,7 +163,6 @@ int main(int argc, char *argv[]) { CONCAT(&filenames.p, &filenames.i, &filenames.n, "/\n", 2); CHECK_NE(MAP_FAILED, (elf = mmap(NULL, st->st_size, PROT_READ, MAP_PRIVATE, fd, 0))); - madvise(elf, st->st_size, MADV_WILLNEED); CHECK(IsElf64Binary(elf, st->st_size)); CHECK_NOTNULL((strs = GetElfStringTable(elf, st->st_size))); CHECK_NOTNULL((syms = GetElfSymbolTable(elf, st->st_size, &symcount))); diff --git a/tool/build/lib/interner.c b/tool/build/lib/interner.c index ab92bd60..fd2580db 100644 --- a/tool/build/lib/interner.c +++ b/tool/build/lib/interner.c @@ -21,7 +21,7 @@ #include "libc/alg/arraylist2.internal.h" #include "libc/bits/safemacros.internal.h" #include "libc/mem/mem.h" -#include "libc/str/knuthmultiplicativehash.internal.h" +#include "libc/nexgen32e/crc32.h" #include "libc/str/str.h" #include "libc/x/x.h" #include "tool/build/lib/interner.h" @@ -100,7 +100,7 @@ size_t internobj(struct Interner *t, const void *data, size_t size) { step = 0; item = data; it = (struct InternerObject *)t; - hash = max(1, KnuthMultiplicativeHash32(data, size)); + hash = max(1, crc32c(0, data, size)); do { /* it is written that triangle probe halts iff i> 1)) & (it->n - 1); diff --git a/tool/build/mkdeps.c b/tool/build/mkdeps.c index 728f5533..6a63ada6 100644 --- a/tool/build/mkdeps.c +++ b/tool/build/mkdeps.c @@ -36,7 +36,6 @@ #include "libc/runtime/gc.h" #include "libc/runtime/runtime.h" #include "libc/stdio/stdio.h" -#include "libc/str/knuthmultiplicativehash.internal.h" #include "libc/str/str.h" #include "libc/sysv/consts/madv.h" #include "libc/sysv/consts/map.h" diff --git a/tool/decode/lib/asmcodegen.c b/tool/decode/lib/asmcodegen.c index 1644ef4a..4c0e31f5 100644 --- a/tool/decode/lib/asmcodegen.c +++ b/tool/decode/lib/asmcodegen.c @@ -41,7 +41,7 @@ nodiscard char *tabpad(const char *s, unsigned width) { size_t i, l, need; l = strlen(s); need = width > l ? (roundup(width, 8) - l - 1) / 8 + 1 : 0; - p = memcpy(malloc(l + need + 1), s, l); + p = memcpy(malloc(l + need + 2), s, l); for (i = 0; i < need; ++i) p[l + i] = '\t'; if (!need) { p[l] = ' '; diff --git a/tool/decode/lib/elfidnames.c b/tool/decode/lib/elfidnames.c index fffad0cb..9539e33e 100644 --- a/tool/decode/lib/elfidnames.c +++ b/tool/decode/lib/elfidnames.c @@ -221,6 +221,7 @@ const struct IdName kElfSpecialSectionNames[] = { }; const struct IdName kElfNexgen32eRelocationNames[] = { + {R_X86_64_NONE, "NONE"}, {R_X86_64_64, "64"}, {R_X86_64_PC32, "PC32"}, {R_X86_64_GOT32, "GOT32"},