Rewrite Cosmopolitan Ar

The build/bootstrap/ar.com program is now tinier. This change reduces
its size from 140kb to 53kb. Nothing was traded away. Cosmopolitan Ar
performance is now 2x better than llvm-ar largely thanks to using the
copy_file_range() system call. This change homebrews a new allocation
API that addresses the shortcomings of the C standard library design.
Using these new balloc() and reballoc() functions I managed to reduce
memory consumption so much that Cosmpolitan Ar should now use roughly
100x fewer bytes of peak resident memory compared to llvm-ar. Correct
behavior with better compatibility has been assured. Binary output is
now pretty much bit-identical to llvm-ar, as of this change. This can
and should be the living proof we need to show that a better world is
possible for software.
This commit is contained in:
Justine Tunney 2023-07-02 10:19:16 -07:00
parent 197aa0d465
commit 0c630d95b5
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
27 changed files with 916 additions and 341 deletions

View file

@ -10,7 +10,8 @@ COSMOPOLITAN_C_START_
struct ar_hdr {
char ar_name[16];
char ar_date[12];
char ar_uid[6], ar_gid[6];
char ar_uid[6];
char ar_gid[6];
char ar_mode[8];
char ar_size[10];
char ar_fmag[2];

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/dce.h"
#include "libc/elf/def.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/phdr.h"

View file

@ -11,16 +11,17 @@ COSMOPOLITAN_C_START_
cosmopolitan § executable linkable format
*/
char *GetElfStringTable(const Elf64_Ehdr *, size_t, const char *);
Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *, size_t, int, Elf64_Xword *);
bool IsElf64Binary(const Elf64_Ehdr *, size_t);
bool IsElfSymbolContent(const Elf64_Sym *);
bool IsElf64Binary(const Elf64_Ehdr *, size_t);
char *GetElfStringTable(const Elf64_Ehdr *, size_t, const char *);
Elf64_Sym *GetElfSymbols(const Elf64_Ehdr *, size_t, int, Elf64_Xword *);
Elf64_Shdr *GetElfSymbolTable(const Elf64_Ehdr *, size_t, int, Elf64_Xword *);
Elf64_Phdr *GetElfProgramHeaderAddress(const Elf64_Ehdr *, size_t, Elf64_Half);
Elf64_Shdr *GetElfSectionHeaderAddress(const Elf64_Ehdr *, size_t, Elf64_Half);
const char *GetElfString(const Elf64_Ehdr *, size_t, const char *, Elf64_Word);
void *GetElfSectionAddress(const Elf64_Ehdr *, size_t, const Elf64_Shdr *);
char *GetElfSectionNameStringTable(const Elf64_Ehdr *, size_t);
char *GetElfString(const Elf64_Ehdr *, size_t, const char *, Elf64_Word);
const char *GetElfSectionName(const Elf64_Ehdr *, size_t, Elf64_Shdr *);
char *GetElfSectionNameStringTable(const Elf64_Ehdr *, size_t);
#endif /* COSMO */
COSMOPOLITAN_C_END_

View file

@ -31,7 +31,7 @@
Elf64_Phdr *GetElfProgramHeaderAddress(const Elf64_Ehdr *elf, //
size_t mapsize, //
Elf64_Half i) { //
uint64_t off;
Elf64_Off off;
if (i >= elf->e_phnum) return 0;
if (elf->e_phoff <= 0) return 0;
if (elf->e_phoff >= mapsize) return 0;

View file

@ -16,25 +16,33 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/elf/scalar.h"
#include "libc/stdckdint.h"
/**
* Returns pointer to elf section file content.
* Returns pointer to ELF section file content.
*
* This function shouldn't be used on the bss section.
* This function computes `elf + sh_offset` with safety checks.
*
* @param elf points to the start of the executable image
* @param mapsize is the number of bytes past `elf` we can access
* @param shdr is from GetElfSectionHeaderAddress() and null-propagating
* @return pointer to content bytes, or null on error
* @param elf points to the start of the executable image data
* @param mapsize is the number of bytes of `elf` we can access
* @param shdr is from GetElfSectionHeaderAddress(), or null
* @return pointer to section data within image, or null if
* 1. `shdr` was null, or
* 2. `sh_size` was zero, or
* 3, `sh_type` was `SHT_NOBITS`, or
* 4. content wasn't contained within `[elf,elf+mapsize)`, or
* 5. an arithmetic overflow occurred
*/
void *GetElfSectionAddress(const Elf64_Ehdr *elf, // validated
size_t mapsize, // validated
const Elf64_Shdr *shdr) { // foreign
uint64_t last;
Elf64_Off last;
if (!shdr) return 0;
if (shdr->sh_size <= 0) return 0;
if (shdr->sh_type == SHT_NOBITS) return 0;
if (ckd_add(&last, shdr->sh_offset, shdr->sh_size)) return 0;
if (last > mapsize) return 0;
return (char *)elf + shdr->sh_offset;

View file

@ -16,21 +16,29 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/shdr.h"
/**
* Returns section header object at `elf.section[i]`.
*
* @param elf points to the start of the executable image
* @param elf points to the start of the executable image data
* @param mapsize is the number of bytes past `elf` we can access
* @param i is the section header index, starting at zero
* @return section header pointer, or null on error
* @param i is the index of the section header
* @return pointer to section header within image, or null if
* 1. `i` was a magic number, i.e. `i >= SHN_LORESERVE`, or
* 2. `e_shoff` was zero (image has no section headers), or
* 3. `e_shentsize` had fewer than the mandatory 60 bytes, or
* 4. section header wasn't contained by `[elf,elf+mapsize)`, or
* 5. an arithmetic overflow occurred
*/
Elf64_Shdr *GetElfSectionHeaderAddress(const Elf64_Ehdr *elf, //
size_t mapsize, //
Elf64_Half i) { //
uint64_t off;
Elf64_Off off;
if (i >= SHN_LORESERVE) return 0;
if (i >= elf->e_shnum) return 0;
if (elf->e_shoff <= 0) return 0;
if (elf->e_shoff >= mapsize) return 0;

View file

@ -24,21 +24,32 @@
/**
* Returns `strtab + i` from elf string table.
*
* @param elf points to the start of the executable image
* @param elf points to the start of the executable image data
* @param mapsize is the number of bytes past `elf` we can access
* @param strtab is double-nul string list from GetElfStringTable()
* @param i is byte index into strtab where needed string starts
* @return pointer to nul terminated string, or null on error
* which may be null, in which case only the `!i` name is valid
* @param i is byte index into strtab where needed string starts or
* zero (no name) in which case empty string is always returned
* as a pointer to the read-only string literal, rather than in
* the elf image, since the elf spec permits an empty or absent
* string table section
* @return a const nul-terminated string pointer, otherwise null if
* 1. `i` was nonzero and `strtab` was null, or
* 2. `strtab+i` wasn't inside `[elf,elf+mapsize)`, or
* 3. a nul byte wasn't present within `[strtab+i,elf+mapsize)`, or
* 4. an arithmetic overflow occurred
*/
char *GetElfString(const Elf64_Ehdr *elf, // validated
size_t mapsize, // validated
const char *strtab, // validated
Elf64_Word i) { // foreign
const char *GetElfString(const Elf64_Ehdr *elf, // validated
size_t mapsize, // validated
const char *strtab, // validated
Elf64_Word i) { // foreign
const char *e;
if (!i) return "";
e = (const char *)elf;
if (!strtab) return 0;
if (strtab < e) return 0;
if (strtab >= e + mapsize) return 0;
if (strtab + i >= e + mapsize) return 0;
if (!memchr(strtab + i, 0, (e + mapsize) - (strtab + i))) return 0;
return (char *)strtab + i;
return (const char *)strtab + i;
}

View file

@ -25,10 +25,16 @@
/**
* Returns pointer to elf string table.
*
* @param elf points to the start of the executable image
* @param elf points to the start of the executable image data
* @param mapsize is the number of bytes past `elf` we can access
* @param section_name is usually `".strtab"`, `".dynstr"`, or null
* @return pointer to double-nul terminated string list or null on error
* @return pointer to string table within `elf` image, which should
* normally be a sequence of NUL-terminated strings whose first
* string is the empty string; otherwise NULL is returned, when
* either: (1) `section_name` is not found, (2) it did not have
* the `SHT_STRTAB` section type, (3) the section size was zero
* noting that the ELF spec does consider that legal, or lastly
* (4) an overflow or boundary violation occurred
*/
char *GetElfStringTable(const Elf64_Ehdr *elf, //
size_t mapsize, //

58
libc/elf/getelfsymbols.c Normal file
View file

@ -0,0 +1,58 @@
/*-*- 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
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/elf/elf.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/sym.h"
/**
* Returns pointer to array of elf symbols.
*
* This is a shortcut composing GetElfSymbolTable() and
* GetElfSectionAddress(), that can be used as follows:
*
* Elf64_Xword i, n;
* Elf64_Sym *st = GetElfSymbols(map, size, SHT_SYMTAB, &n);
* for (i = 0; st && i < n; ++i) {
* // st[i] holds a symbol
* }
*
* The above code will iterate over the relocatable and/or
* statically-linked symbols defined by an ELF image.
*
* @param elf points to the start of the executable image data
* @param mapsize is the number of bytes past `elf` we can access
* @param section_type is usually `SHT_SYMTAB` or `SHT_DYNSYM`
* @param out_count optionally receives number of symbols
* @return pointer to array of elf symbol array, otherwise null
*/
Elf64_Sym *GetElfSymbols(const Elf64_Ehdr *elf, //
size_t mapsize, //
int section_type, //
Elf64_Xword *out_count) {
Elf64_Sym *syms;
Elf64_Xword count;
if ((syms = GetElfSectionAddress(
elf, mapsize,
GetElfSymbolTable(elf, mapsize, section_type, &count))) &&
out_count) {
*out_count = count;
}
return syms;
}

View file

@ -1,7 +1,7 @@
/*-*- 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
Copyright 2023 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
@ -20,29 +20,59 @@
#include "libc/elf/elf.h"
#include "libc/elf/scalar.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/shdr.h"
#include "libc/elf/struct/sym.h"
/**
* Returns pointer to elf symbol table.
* Returns pointer to the elf section header for a symbol table.
*
* @param elf points to the start of the executable image
* The easiest way to get the symbol table is:
*
* Elf64_Xword i, n;
* Elf64_Sym *st = GetElfSymbols(map, size, SHT_SYMTAB, &n);
* for (i = 0; st && i < n; ++i) {
* // st[i] holds a symbol
* }
*
* This API is more verbose than the GetElfSymbols() shortcut, however
* calling this the long way makes tricks like the following possible:
*
* Elf64_Xword i, n;
* Elf64_Shdr *sh = GetElfSymbolTable(map, size, SHT_SYMTAB, &n);
* Elf64_Sym *st = GetElfSectionAddress(map, size, sh);
* if (st) {
* for (i = sh->sh_info; i < n; ++i) {
* // st[i] holds a non-local symbol
* }
* }
*
* Our code here only cares about `STB_GLOBAL` and `STB_WEAK` symbols
* however `SHT_SYMTAB` usually has countless `STB_LOCAL` entries too
* that must be skipped over. The trick is that the ELF spec requires
* local symbols be ordered before global symbols, and that the index
* dividing the two be stored to `sh_info`. So, if we start iterating
* there, then we've cleverly avoided possibly dozens of page faults!
*
* @param elf points to the start of the executable image data
* @param mapsize is the number of bytes past `elf` we can access
* @param section_type is usually `SHT_SYMTAB` or `SHT_DYNSYM`
* @param out_count optionally receives number of elements in res
* @return pointer to symbol array, or null on error
* @param out_count optionally receives number of symbols
* @return pointer to symbol table section header, otherwise null
*/
Elf64_Sym *GetElfSymbolTable(const Elf64_Ehdr *elf, //
size_t mapsize, //
int section_type, //
Elf64_Xword *out_count) {
Elf64_Shdr *GetElfSymbolTable(const Elf64_Ehdr *elf, //
size_t mapsize, //
int section_type, //
Elf64_Xword *out_count) {
int i;
Elf64_Shdr *shdr;
for (i = elf->e_shnum; i > 0; --i) {
if ((shdr = GetElfSectionHeaderAddress(elf, mapsize, i - 1)) && //
shdr->sh_entsize == sizeof(Elf64_Sym) && //
shdr->sh_type == section_type) {
if (out_count) *out_count = shdr->sh_size / sizeof(Elf64_Sym);
return GetElfSectionAddress(elf, mapsize, shdr);
if (out_count) {
*out_count = shdr->sh_size / sizeof(Elf64_Sym);
}
return shdr;
}
}
return 0;

View file

@ -16,6 +16,7 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/elf/def.h"
#include "libc/elf/elf.h"
bool IsElfSymbolContent(const Elf64_Sym *sym) {

View file

@ -1,27 +1,162 @@
#ifndef COSMOPOLITAN_LIBC_ELF_STRUCT_EHDR_H_
#define COSMOPOLITAN_LIBC_ELF_STRUCT_EHDR_H_
#include "libc/elf/def.h"
#include "libc/elf/scalar.h"
#define EI_NIDENT 16
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*
* ELF header.
*/
typedef struct Elf64_Ehdr {
unsigned char e_ident[EI_NIDENT];
/*
* Leading bytes of ELF header.
*
* - `e_ident[0]` is always `127`
* - `e_ident[1]` is always `'E'`
* - `e_ident[2]` is always `'L'`
* - `e_ident[3]` is always `'F'`
*
* - `e_ident[EI_CLASS]` is mandatory and should be:
*
* - `ELFCLASSNONE64` if it's an Elf64 image
* - `ELFCLASSNONE32` if it's an Elf32 image
* - Otherwise we assume it's an Elf64 image
*
* - `e_ident[EI_DATA]` is advisory and could be:
*
* - `ELFDATANONE` isn't strictly valid
* - `ELFDATA2LSB` for little-endian
* - `ELFDATA2MSB` for big-endian
*
* - `e_ident[EI_VERSION]` is advisory and should be:
*
* - `EV_NONE` if it's zero or unspecified
* - `EV_CURRENT` for current ELF version (which is 1)
*
* - `e_ident[EI_OSABI]` is mandatory and could be:
*
* - `ELFOSABI_NONE` is zero
* - `ELFOSABI_GNU` is for GNU
* - `ELFOSABI_SYSV` used by GNU
* - `ELFOSABI_LINUX` doesn't care
* - `ELFOSABI_FREEBSD` does care (recommended)
* - `ELFOSABI_NETBSD` doesn't care (see `PT_NOTE`)
* - `ELFOSABI_OPENBSD` doesn't care (see `PT_NOTE`)
*
* - `e_ident[EI_ABIVERSION]` is advisory
*
*/
unsigned char e_ident[16];
/*
* ELF image type.
*
* This field is mandatory and should be one of:
*
* - `ET_REL` for `.o` object files
* - `ET_DYN` for `.so` files and `-pie` executables
* - `ET_EXEC` for statically-linked executables
*
*/
Elf64_Half e_type;
/*
* ELF machine type.
*
* This field is mandatory and could be one of:
*
* - `EM_M32` for Bellmac
* - `EM_X86_64` for Amd64
* - `EM_AARCH64` for Arm64
* - `EM_PPC64` for Raptors
* - `EM_RISCV` for Berkeley
* - `EM_S390` for System/360
*
*/
Elf64_Half e_machine;
/*
* ELF version.
*
* This field is advisory and could be:
*
* - `EV_NONE` if it's zero or unspecified
* - `EV_CURRENT` for current ELF version (which is 1)
*
* @see `e_ident[EI_VERSION]`
*/
Elf64_Word e_version;
/*
* ELF executable entrypoint.
*
* Static executables should use this field to store the virtual
* address of the _start() function. This field may be zero, for
* unspecified.
*/
Elf64_Addr e_entry;
/*
* `Elf64_Phdr` file offset.
*
* This field is mandatory. Object files should set it to zero.
*/
Elf64_Off e_phoff;
/*
* `Elf64_Shdr` file offset.
*
* This field is advisory.
*/
Elf64_Off e_shoff;
/*
* ELF flags.
*
* This field is advisory.
*/
Elf64_Word e_flags;
/*
* `Elf64_Ehdr` size.
*
* This field is advisory and should be 64.
*/
Elf64_Half e_ehsize;
/*
* `Elf64_Phdr` element size.
*
* This field *is* cared about and should be set to 56. Cosmopolitan
* permits larger values for the pleasure of it.
*/
Elf64_Half e_phentsize;
/*
* `Elf64_Phdr` array count.
*/
Elf64_Half e_phnum;
/*
* `Elf64_Shdr` element size.
*
* This field is advisory and should be set to 64. Cosmopolitan
* permits larger values for the pleasure of it.
*/
Elf64_Half e_shentsize;
/*
* `Elf64_Shdr` count.
*
* This field is advisory.
*/
Elf64_Half e_shnum;
/*
* Section header index of section name string table.
*/
Elf64_Half e_shstrndx;
} Elf64_Ehdr;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -3,9 +3,51 @@
#include "libc/elf/scalar.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*
* ELF relocation.
*
* Relocations let us easily apply fixups to compiled object code. This
* data structure represents the contents of an `sh_type` w/ `SHT_REL`.
*
* @see Elf64_Rela
*/
typedef struct Elf64_Rel {
/*
* Location to be modified.
*
* If `e_type` is `ET_REL` then this is a section data byte offset.
*
* If `e_type` isn't `ET_REL` then this is a virtual address.
*/
Elf64_Addr r_offset;
Elf64_Xword r_info; /** @see ELF64_R_{SYM,SIZE,INFO} */
/*
* Relocation type and symbol.
*
* This value may be created using:
*
* r_info = ELF64_R_INFO(sym, type);
*
* This value may be read using:
*
* Elf64_Word sym = ELF64_R_SYM(r_info);
* Elf64_Word type = ELF64_R_TYPE(r_info);
*
* Where `sym` is a symbol index, and `type` might be:
*
* - `R_X86_64_64`
* - `R_X86_64_PC32`
* - `R_X86_64_GOTPCRELX`
* - `R_AARCH64_ABS64`
*
* Each relocation type specifies a mathematical formula that's used
* to compute the appropriate value for the fixed-up object code. If
* if needs an addend, then this struct doesn't have one, but it can
* still be embedded by the compiler in the location to be modified.
*/
Elf64_Xword r_info;
} Elf64_Rel;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -3,15 +3,55 @@
#include "libc/elf/scalar.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
/*
* ELF relocation w/ explicit addend.
*
* Relocations let us easily apply fixups to compiled object code. This
* data structure represents the contents of an `sh_type` w/ `SHT_RELA`
*
* @see Elf64_Rel
*/
typedef struct Elf64_Rela {
/*u64*/ Elf64_Addr r_offset;
/*
* ELF64_R_SYM(r_info) sym
* ELF64_R_TYPE(r_info) R_X86_64_{64,PC32,GOTPCRELX,...}
* ELF64_R_INFO(sym, type) r_info
* Location to be modified.
*
* If `e_type` is `ET_REL` then this is a section data byte offset.
*
* If `e_type` isn't `ET_REL` then this is a virtual address.
*/
/*u64*/ Elf64_Xword r_info; /* ELF64_R_{SYM,SIZE,INFO} */
/*i64*/ Elf64_Sxword r_addend;
Elf64_Addr r_offset;
/*
* Relocation type and symbol.
*
* This value may be created using:
*
* r_info = ELF64_R_INFO(sym, type);
*
* This value may be read using:
*
* Elf64_Word sym = ELF64_R_SYM(r_info);
* Elf64_Word type = ELF64_R_TYPE(r_info);
*
* Where `sym` is a symbol index, and `type` might be:
*
* - `R_X86_64_64`
* - `R_X86_64_PC32`
* - `R_X86_64_GOTPCRELX`
* - `R_AARCH64_ABS64`
*
*/
Elf64_Xword r_info;
/*
* Relocation parameter.
*
* Each relocation type has its own mathematical formula, which should
* incorporate this value in its own unique way.
*/
Elf64_Sxword r_addend;
} Elf64_Rela;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -8,24 +8,44 @@
* @see https://docs.oracle.com/cd/E19683-01/816-1386/chapter6-94076/index.html
*/
typedef struct Elf64_Shdr {
Elf64_Word sh_name;
Elf64_Word sh_type; /* SHT_{PROGBITS,NOBITS,STRTAB,SYMTAB,RELA,...} */
Elf64_Word sh_type; /* SHT_{PROGBITS,NOBITS,STRTAB,SYMTAB,RELA,...} */
Elf64_Xword sh_flags; /* SHF_{WRITE,ALLOC,EXECINSTR,MERGE,STRINGS,...} */
Elf64_Addr sh_addr;
Elf64_Off sh_offset;
Elf64_Xword sh_size;
/*
* If SHT_RELA: Index of section of associated symbol table.
* If SHT_SYMTAB: Index of section of associated string table.
* Index of linked section header.
*
* If `sh_type` is `SHT_RELA` then `sh_link` holds the section header
* index of the associated symbol table.
*
* If `sh_type` is `SHT_SYMTAB` then `sh_link` holds the section
* header index of the associated string table.
*/
Elf64_Word sh_link;
/*
* If SHT_RELA: Index of section to which relocations apply.
* If SHT_SYMTAB: One greater than symbol table index of last local symbol.
* If `sh_type` is `SHT_RELA` then `sh_info` contains the index of the
* section to which relocations apply.
*
* If `sh_type` is `SHT_SYMTAB` or `SHT_DYNSYM` then `sh_info`
* contains an index that's one greater than symbol table index of
* last `STB_LOCAL` symbol.
*/
Elf64_Word sh_info;
Elf64_Xword sh_addralign;
Elf64_Xword sh_entsize;
} Elf64_Shdr;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -4,18 +4,91 @@
#if !(__ASSEMBLER__ + __LINKER__ + 0)
typedef struct Elf64_Sym {
/*
* Symbol name.
*
* This value is a byte offset into the `.strtab` section. If this
* value is zero, then the symbol has no name.
*/
Elf64_Word st_name;
/* ELF64_ST_TYPE(st_info) → STT_{NOTYPE,OBJECT,FUNC,SECTION,FILE,COMMON,...}
* ELF64_ST_BIND(st_info) STB_{LOCAL,GLOBAL,WEAK,...} */
/*
* Symbol type and binding.
*
* This value may be created using:
*
* sym.st_info = ELF64_ST_INFO(bind, type);
*
* This value may be read using:
*
* int bind = ELF64_ST_BIND(sym.st_info);
* int type = ELF64_ST_TYPE(sym.st_info);
*
* Where `bind` is typically:
*
* - `STB_LOCAL`
* - `STB_GLOBAL`
* - `STB_WEAK`
*
* Where `type` is typically:
*
* - `STT_NOTYPE`
* - `STT_OBJECT`
* - `STT_FUNC`
* - `STT_SECTION`
* - `STT_FILE`
* - `STT_COMMON`
*/
uint8_t st_info;
/* STV_{DEFAULT,INTERNAL,HIDDEN,PROTECTED} */
/*
* Symbol visibility.
*
* This value should be accessed using:
*
* int visibility = ELF64_ST_VISIBILITY(sym.st_other);
*
* Where `visibility` is typically:
*
* - `STV_DEFAULT`
* - `STV_INTERNAL`
* - `STV_HIDDEN`
* - `STV_PROTECTED`
*/
uint8_t st_other;
/* SHN_UNDEF, <section index>, SHN_ABS, SHN_COMMON, etc. */
/*
* Symbol section.
*
* If `st_shndx` is within `(SHN_UNDEF,SHN_LORESERVE)` then it holds
* an index into the section header table.
*
* Otherwise `st_shndx` is usually one of the following magic numbers:
*
* - `SHN_UNDEF` means symbol is undefined
* - `SHN_ABS` means symbol is a linker integer
* - `SHN_COMMON` means symbol is defined traditionally
*/
Elf64_Section st_shndx;
/* byte offset into GetElfSectionAddress(st_shndx) */
/*
* Symbol value.
*
* If `e_type` is `ET_REL` and `st_shndx` is `SHN_COMMON`, then
* `st_value` holds the required symbol alignment, or 1 if no
* alignment is required.
*
* If `e_type` is `ET_REL` and `st_shndx` is a section index, then
* `st_value` holds a byte offset into the section memory.
*
* If `e_type` isn't `ET_REL` then `st_value` holds a virtual address.
*/
Elf64_Addr st_value;
/* byte length optionally set by .size directive */
Elf64_Xword st_size;
} Elf64_Sym;
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -1,5 +1,6 @@
#ifndef COSMOPOLITAN_LIBC_ELF_TINYELF_INTERNAL_H_
#define COSMOPOLITAN_LIBC_ELF_TINYELF_INTERNAL_H_
#include "libc/elf/def.h"
#include "libc/elf/struct/ehdr.h"
#include "libc/elf/struct/phdr.h"
#include "libc/elf/struct/shdr.h"

View file

@ -18,6 +18,7 @@
*/
#include "libc/calls/calls.h"
#include "libc/errno.h"
#include "libc/intrin/weaken.h"
#include "libc/mem/mem.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/internal.h"
@ -27,8 +28,12 @@
int __fflush_impl(FILE *f) {
size_t i;
ssize_t rc;
free(f->getln);
f->getln = 0;
if (f->getln) {
if (_weaken(free)) {
_weaken(free)(f->getln);
}
f->getln = 0;
}
if (f->beg && !f->end && (f->iomode & O_ACCMODE) != O_RDONLY) {
for (i = 0; i < f->beg; i += rc) {
if ((rc = write(f->fd, f->buf + i, f->beg - i)) == -1) {