Compare commits

..

No commits in common. "master" and "pledge-1.7" have entirely different histories.

23731 changed files with 521483 additions and 1641459 deletions

View file

@ -6,11 +6,8 @@ AlignConsecutiveMacros: true
AlignConsecutiveDeclarations: false
AlwaysBreakBeforeMultilineStrings: false
AllowShortFunctionsOnASingleLine: false
AllowShortLoopsOnASingleLine: false
AllowShortIfStatementsOnASingleLine: false
KeepEmptyLinesAtTheStartOfBlocks: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
IncludeBlocks: Merge
---
Language: Cpp
AllowShortFunctionsOnASingleLine: false

View file

@ -1,31 +0,0 @@
# Run this command to always ignore formatting commits in git blame
# git config blame.ignoreRevsFile .git-blame-ignore-revs
# Upgraded clang-format to 19.0.0git
89fc95fefd40413706ff1bdaac2e8d98b328dbf1
# vim c++ filetype in modelines
04c6bc478e082263d67c41bedbd033dde2d429eb
# Ran clang-format
f032b5570b4cd87c6bb4abb54c0b98e69c939955
# Applied clang-format update to repo
6e6fc38935054db0534d5af4fb99c6193305b946
# revert retabbing
2b315626f3af765cdfbc61114647412cdb798b3a
# more modeline errata
3a8e01a77a7c97af0b16fb1651b230cee7f7d4c6
# fix more vi modelines
2fc507c98f53a76718f61f9a36602f86b5ac0cc9
# flip et/noet in modelines
e16a7d8f3b8f906c3ef76e79f57f3adfc7f25186
# fix vi modelines
394d998315f613a888cc6b6c051d4163bdf5cd6f
# clang-format
c0eacf2eb1e1c0b3bd4f71f12fef258f5b249c3f
# ape-m1 formatting cleanup
da8baf2aa5ce93b958aca90a0ae69f537806324b
# Run clang-format on most sources
369f9740de4534c28d0e81ab2afc99decbb9a3e6
# Get rid of .internal.h convention in LIBC_INTRIN
86d884cce24d773e298a2714c1e3d91ecab9be45
# Remove .internal from more header filenames
31194165d2afca36c2315a6e7ca2f0797dde09e3

9
.gitattributes vendored
View file

@ -1,10 +1,3 @@
# -*- conf -*-
*.gz binary
*.so binary
*.dll binary
*.dylib binary
/build/bootstrap/* binary
/usr/share/terminfo/* binary
/usr/share/terminfo/*/* binary
/build/bootstrap/*.com binary
/usr/share/zoneinfo/* binary
/usr/share/zoneinfo/*/* binary

View file

@ -1,59 +0,0 @@
name: Low Severity Bugs
description: Used to report low severity bugs in cosmopolitan (e.g. cosmetic issues, non critical UI glitches)
title: "Bug: "
labels: ["bug", "low severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -1,59 +0,0 @@
name: Medium Severity Bug
description: Used to report medium severity bugs in cosmopolitan (e.g. Malfunctioning Features but generally still useable)
title: "Bug: "
labels: ["bug", "medium severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -1,59 +0,0 @@
name: High Severity Bug
description: Used to report high severity bugs in cosmopolitan (e.g. Malfunctioning features hindering important common workflow)
title: "Bug: "
labels: ["bug", "high severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -1,59 +0,0 @@
name: Critical Severity Bug
description: Used to report critical severity bugs in cosmopolitan (e.g. Crashing, Corrupted, Dataloss)
title: "Bug: "
labels: ["bug", "critical severity"]
body:
- type: markdown
attributes:
value: |
Thanks for taking the time to fill out this bug report!
Please include information about your system, the steps to reproduce the bug,
and the version of cosmopolitan that you are using.
If possible, please provide a minimal code example that reproduces the bug.
You may also consider using function call tracing `--ftrace` or the lighter system call tracing `--strace`
for additional technical logging that may allow us to narrow down where the fault occurred.
- type: input
id: contact
attributes:
label: Contact Details
description: How can we get in touch with you if we need more info?
placeholder: ex. email@example.com
validations:
required: false
- type: textarea
id: what-happened
attributes:
label: What happened?
description: Also tell us, what did you expect to happen?
placeholder: Tell us what you see!
validations:
required: true
- type: textarea
id: version
attributes:
label: Version
description: What version of our software are you running? (use `--version` to get a version string)
placeholder: "cosmocc (GCC) 12.3.0"
validations:
required: true
- type: dropdown
id: operating-system
attributes:
label: What operating system are you seeing the problem on?
multiple: true
options:
- Linux
- Mac
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
validations:
required: false
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -1,51 +0,0 @@
name: Enhancement template
description: Used to request enhancements for cosmopolitan
title: "Feature Request: "
labels: ["enhancement"]
body:
- type: markdown
attributes:
value: |
[Please post your idea first in Discussion if there is not yet a consensus for this enhancement request. This will help to keep this issue tracker focused on enhancements that the community has agreed needs to be implemented.](https://github.com/jart/cosmopolitan/discussions/categories/ideas)
- type: checkboxes
id: prerequisites
attributes:
label: Prerequisites
description: Please confirm the following before submitting your enhancement request.
options:
- label: I am running the latest code. Mention the version if possible as well.
required: true
- label: I carefully followed the [README.md](https://github.com/jart/cosmopolitan/blob/master/README.md).
required: true
- label: I searched using keywords relevant to my issue to make sure that I am creating a new issue that is not already open (or closed).
required: true
- label: I reviewed the [Discussions](https://github.com/jart/cosmopolitan/discussions), and have a new and useful enhancement to share.
required: true
- type: textarea
id: feature-description
attributes:
label: Feature Description
description: Please provide a detailed written description of what you were trying to do, and what you expected `cosmopolitan` to do as an enhancement.
placeholder: Detailed description of the enhancement
validations:
required: true
- type: textarea
id: motivation
attributes:
label: Motivation
description: Please provide a detailed written description of reasons why this feature is necessary and how it is useful to `cosmopolitan` users.
placeholder: Explanation of why this feature is needed and its benefits
validations:
required: true
- type: textarea
id: possible-implementation
attributes:
label: Possible Implementation
description: If you have an idea as to how it can be implemented, please write a detailed description. Feel free to give links to external sources or share visuals that might be helpful to understand the details better.
placeholder: Detailed description of potential implementation
validations:
required: false

View file

@ -1,52 +0,0 @@
name: Research
description: Track new technical research area
title: "Research: "
labels: ["research"]
body:
- type: markdown
attributes:
value: |
Don't forget to check for any [duplicate research issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3A%22research+%F0%9F%94%AC%22)
- type: checkboxes
id: research-stage
attributes:
label: Research Stage
description: Track general state of this research ticket
options:
- label: Background Research (Let's try to avoid reinventing the wheel)
- label: Hypothesis Formed (How do you think this will work and it's effect?)
- label: Strategy / Implementation Forming
- label: Analysis of results
- label: Debrief / Documentation (So people in the future can learn from us)
- type: textarea
id: background
attributes:
label: Previous existing literature and research
description: Whats the current state of the art and whats the motivation for this research?
- type: textarea
id: hypothesis
attributes:
label: Hypothesis
description: How do you think this will work and it's effect?
- type: textarea
id: implementation
attributes:
label: Implementation
description: Got an approach? e.g. a PR ready to go?
- type: textarea
id: analysis
attributes:
label: Analysis
description: How does the proposed implementation behave?
- type: textarea
id: logs
attributes:
label: Relevant log output
description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks.
render: shell

View file

@ -1,28 +0,0 @@
name: Refactor (Maintainers)
description: Used to track refactoring opportunities
title: "Refactor: "
labels: ["refactor"]
body:
- type: markdown
attributes:
value: |
Don't forget to [check for existing refactor issue tickets](https://github.com/jart/cosmopolitan/issues?q=is%3Aopen+is%3Aissue+label%3Arefactoring) in case it's already covered.
Also you may want to check [Pull request refactor label as well](https://github.com/jart/cosmopolitan/pulls?q=is%3Aopen+is%3Apr+label%3Arefactoring) for duplicates too.
- type: textarea
id: background-description
attributes:
label: Background Description
description: Please provide a detailed written description of the pain points you are trying to solve.
placeholder: Detailed description behind your motivation to request refactor
validations:
required: true
- type: textarea
id: possible-approaches
attributes:
label: Possible Refactor Approaches
description: If you have some idea of possible approaches to solve this problem. You may want to make it a todo list.
placeholder: Your idea of possible refactoring opportunity/approaches
validations:
required: false

View file

@ -1,15 +0,0 @@
blank_issues_enabled: true
contact_links:
- name: FAQ
url: https://github.com/jart/cosmopolitan/wiki/FAQ
about: Is your question a common one? You may want to check here first.
- name: Got an idea?
url: https://github.com/jart/cosmopolitan/discussions/categories/ideas
about: Pop it there. It may then become an enhancement ticket.
- name: Got a question?
url: https://github.com/jart/cosmopolitan/discussions/categories/q-a
about: Ask a question there!
- name: Want to contribute?
url: https://github.com/jart/cosmopolitan/wiki/contribute
about: Head to the contribution guide page of the wiki for areas you can help with

49
.github/labeler.yml vendored
View file

@ -1,49 +0,0 @@
# https://github.com/actions/labeler
documentation:
- changed-files:
- any-glob-to-any-file:
- README.md
- LICENSE
- CONTRIBUTING.md
- libc/README.md
- tool/cosmocc/README.md
- third_party/getopt/README.txt
build:
- changed-files:
- any-glob-to-any-file:
- build/**
- Makefile
- '*/*.mk'
examples:
- changed-files:
- any-glob-to-any-file: examples/**
devops:
- changed-files:
- any-glob-to-any-file:
- .github/**
- .clang-format
dsp:
- changed-files:
- any-glob-to-any-file:
- dsp/**
ape:
- changed-files:
- any-glob-to-any-file:
- ape/**
libc:
- changed-files:
- any-glob-to-any-file:
- libc/**
net:
- changed-files:
- any-glob-to-any-file:
- net/**
third_party:
- changed-files:
- any-glob-to-any-file:
- third_party/**
tool:
- changed-files:
- any-glob-to-any-file:
- tool/**

View file

@ -1,8 +1,5 @@
name: build
env:
COSMOCC_VERSION: 3.9.2
on:
push:
branches:
@ -20,50 +17,12 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
mode: ["", tiny, rel, tinylinux, optlinux]
mode: ["", tiny, opt, rel]
steps:
- uses: actions/checkout@v4
with:
# Full checkout needed for git-restore-mtime-bare.
fetch-depth: 0
- uses: actions/checkout@v3
# TODO(jart): fork this action.
- uses: chetan/git-restore-mtime-action@v2
- uses: actions/cache/restore@v4
id: cache
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}
restore-keys: |
${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-
${{ env.COSMOCC_VERSION }}-
- name: Restore mtimes
if: steps.cache.outputs.cache-hit == 'true'
run: |
while read mtime file; do
[ -f "$file" ] && touch -d "@$mtime" "$file"
done < o/.mtimes
- name: support ape bins 1
run: sudo cp -a build/bootstrap/ape.elf /usr/bin/ape
- name: support ape bins 2
run: sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
- name: support ape bins
run: sudo sh -c "echo ':APE:M::MZqFpD::/bin/sh:' >/proc/sys/fs/binfmt_misc/register"
- name: make matrix
run: V=0 make -j2 MODE=${{ matrix.mode }}
- name: Save mtimes
run: |
find o -type f -exec stat -c "%Y %n" {} \; > o/.mtimes
- uses: actions/cache/save@v4
with:
path: |
.cosmocc
o
key: ${{ env.COSMOCC_VERSION }}-${{ matrix.mode }}-${{ github.sha }}

View file

@ -1,17 +0,0 @@
name: "Pull Request Labeler"
on:
- pull_request_target
jobs:
labeler:
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
repository: "jart/cosmopolitan"
- uses: actions/labeler@v5
with:
configuration-path: '.github/labeler.yml'

View file

@ -1,24 +0,0 @@
name: Nightly cosmocc
on:
schedule:
# https://crontab.guru/#37_4_*_*_*
- cron: "37 4 * * *"
workflow_dispatch:
concurrency:
group: ${{ github.workflow }}
cancel-in-progress: true
jobs:
build-cosmocc:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: |
sudo cp build/bootstrap/ape.elf /usr/bin/ape
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
- run: tool/cosmocc/package.sh
# https://github.com/actions/upload-artifact/issues/590
- uses: actions/upload-artifact@v4.3.5
with:
name: cosmocc
path: cosmocc
compression-level: 9

5
.gitignore vendored
View file

@ -1,8 +1,6 @@
# -*- conf -*-
/o
/cosmocc
/.cosmocc
# TODO: Find some way to have Python write to o/
__pycache__
@ -13,6 +11,3 @@ __pycache__
/TAGS
/bx_enh_dbg.ini
/tool/emacs/*.elc
/perf.data
/perf.data.old
/qemu*core

112
.vscode/c_cpp_properties.json vendored Normal file
View file

@ -0,0 +1,112 @@
{
"configurations": [
{
"name": "Win32",
"includePath": [
"${workspaceFolder}"
],
"cStandard": "c11",
"cppStandard": "c++11",
"forcedInclude": ["${workspaceFolder}/.vscode/vscode.h"],
"defines": [
"libcesque=",
"pureconst=",
"paramsnonnull(x)=",
"alignas(x)",
"alignof(x)",
"artificial=",
"dontdiscard=",
"mayalias=",
"forceinline=",
"forcealign(x)=",
"scanfesque(x)=",
"strftimeesque(x)=",
"wontreturn=",
"textreal=",
"mallocesque=",
"callocesque=",
"vallocesque=",
"reallocesque=",
"strlenesque=",
"memcpyesque=",
"hasatleast=",
"noinline=",
"textexit=",
"returnstwice=",
"textwindows=",
"privileged=",
"compatfn=",
"noinstrument=",
"nodebuginfo=",
"interruptfn=",
"optimizespeed=",
"forcealignargpointer=",
"noasan=",
"noubsan=",
"testonly=",
"donothing=",
"nosideeffect=",
"unreachable=",
"thatispacked=",
"dontthrow=",
"nocallback=",
"relegated=",
"hidden=",
"textstartup=",
"initarray=",
"returnsnonnull=",
"returnspointerwithnoaliases=",
"printfesque(x)=",
"attributeallocsize(x)=",
"returnsaligned(x)=",
"attributeallocalign(x)=",
"nullterminated(x)="
]
},
{
"name": "Linux",
"includePath": [
"${workspaceFolder}"
],
"cStandard": "gnu17",
"compilerPath": "${workspaceFolder}/o/third_party/gcc/bin/x86_64-linux-musl-gcc",
"compilerArgs": [
"-Wall",
"-Werror",
"-fdebug-prefix-map=${workspaceFolder}=",
"-frecord-gcc-switches",
"-Wa,-W",
"-Wa,-I.",
"-Wa,--noexecstack",
"-Wa,--nocompress-debug-sections",
"-Og",
"-g",
"-gdescribe-dies",
"-msse3",
"-mno-red-zone",
"-fno-math-errno",
"-fno-trapping-math",
"-fno-fp-int-builtin-inexact",
"-fno-ident",
"-fno-common",
"-fno-gnu-unique",
"-fstrict-aliasing",
"-fstrict-overflow",
"-fno-semantic-interposition",
"-mno-omit-leaf-frame-pointer",
"-fno-jump-tables",
"-nostdinc",
"-iquote."
],
"forcedInclude": [
"libc/integral/normalize.inc"
],
"defines": [
"COSMO",
"MODE=",
"IMAGE_BASE_VIRTUAL=0x400000"
]
}
],
"version": 4
}

36
.vscode/settings.json vendored
View file

@ -1,36 +0,0 @@
{
"C_Cpp.default.compilerPath": ".cosmocc/3.9.2/bin/aarch64-linux-cosmo-c++",
"C_Cpp.default.compilerArgs": [
"-nostdinc",
"-nostdlib",
"-iquote.",
"-isystemlibc/isystem",
"-isystemthird_party/libcxx",
"-includelibc/integral/normalize.inc",
"-D_COSMO_SOURCE",
"-D__aarch64__"
],
"[c]": {
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"[cpp]": {
"editor.tabSize": 2,
"editor.insertSpaces": true
},
"[makefile]": {
"editor.tabSize": 8,
"editor.insertSpaces": false
},
"[make]": {
"editor.tabSize": 8,
"editor.insertSpaces": false
},
"[assembly]": {
"editor.tabSize": 8,
"editor.insertSpaces": true
},
"files.associations": {
"log.h": "c"
}
}

2
.vscode/vscode.h vendored Normal file
View file

@ -0,0 +1,2 @@
#define __VSCODE_INTELLISENSE__ 1
#include "libc/integral/normalize.inc"

View file

@ -2,77 +2,23 @@
We'd love to accept your patches! Please read this guide first.
## Identity Disclosure
This project does not accept anonymous contributions. Justine Tunney
won't merge pull requests from strangers. In order to change the Cosmo
codebase, and have your changes be upstreamed, she has to know who you
are. You're encouraged to disclose your full name and email address to
the public too, by including them in your git commit messages; however
that's not a requirement; as we're happy to respect the wishes of
contributors who prefer to remain anonymous to the public.
## Copyright Assignment
The first time you send a pull request, you need to send an email to
Justine Tunney <jtunney@gmail.com> stating that you intend to assign her
the copyright to the changes you contribute to Cosmopolitan. It only
needs to happen once. This only applies to the code you *choose* to
contribute. The email should be sent from an email address associated
with your identity. Your email should link to your pull request.
Please send an email to Justine Tunney <jtunney@gmail.com> stating that
you intend to assign her the copyright to the changes you contribute to
Cosmopolitan. Please use the same email address you use for git commits
which should only contain original source code from you or other people
who are also assigning copyright. Please note that, if you're employed,
you may need to get your employer's approval beforehand. If you can not
assign copyright due to local laws, then you may alternatively consider
disclaiming it using the language in [Unlicense](https://unlicense.org)
or [CC-0](http://creativecommons.org/share-your-work/public-domain/cc0)
To make things easy, here's an example of a good email you can use:
> **From**: YOUR NAME (yname@gmail.com)
> **To**: Justine Tunney (jtunney@gmail.com)
> **Subject**: Cosmopolitan Copyright Assignment for YOUR NAME
>
> Hi Justine,
>
> I made my first contribution to Cosmopolitan in
> https://github.com/jart/cosmopolitan/pull/XXXX could you please take a
> look? I intend to assign you the copyright to the changes I contribute
> to Cosmopolitan.
>
> Thanks!
Please note that in order to give Justine the copyright, it has to be
yours to give in the first place. If you're employed, then you should
get your employer's approval to do this beforehand. Even with big
companies like Google, this process is quick and painless. Usually we
see employers granting authorization in less than one day.
If you live in a country that doesn't recognize one's ability to assign
copyright, then you may alternatively consider disclaiming it using the
language in [Unlicense](https://unlicense.org) or
[CC-0](http://creativecommons.org/share-your-work/public-domain/cc0).
If you're checking-in third party code, then you need to have headers at
the top of each source file (but never header files) documenting its
owners and the code should go in the `third_party/` folder. Every third
party project should have a `README.cosmo` file that documents its
provenance as well as any local changes you've made.
## Copyright Policy Exceptions
### Tests
You're encoraged to claim ownership of your test code. If you add a new
file under the `test/` directory, then you should put your name in the
ISC license header at the top of the file. If you add new test cases to
an existing unit test file, then you're encouraged to append a line with
your name to the existing copyright header of that file.
### Exceptional Features
Let's say you discovered a faster better way to implement `log10()` and
you want to give it to Cosmopolitan. In cases like this, it really isn't
appropriate for Justine to own your code. What you could do instead, is
write your own new and improved `log10.c` from scratch, put your name on
the top with the ISC license, and then add a `__notice()` directive so
that your name will be embedded inside every executable that links the
`log10()` function. This will help you get your name out there. Please
note you need get approval from Justine each time you want to do this.
This is important because we can't produce 12kb single-file executables
that comply with license requirements if we have to embed lots of them.
Although that's less of an issue depending on the purpose of the files.
For example, ownership is much less of a concern in the unit test files
so you're encouraged to put your copyright on those, provided it's ISC.
## Style Guide
@ -83,4 +29,34 @@ clang-format -i -style=file tool/net/redbean.c
```
If you use Emacs this can be automated on save for Cosmopolitan using
[tool/emacs/cosmo-format.el](tool/emacs/cosmo-format.el).
[tool/emacs/cosmo-format.el]([tool/emacs/cosmo-format.el]).
### Source Files
- Must use include paths relative to the root of the repository
- Must have comment at top of file documenting copyright and license
- Must have notice embedding if not owned by Justine (exception: tests)
- May use language extensions that are supported by both GCC and Clang
- Should use Google indentation (otherwise use `/* clang-format off */`)
- Should use asm() instead of compiler APIs (exception: ctz, clz, memcpy)
### Header Files
- Must not have copyright or license comments
- Must have once guards (otherwise change `.h` to `.inc`)
- Must be ANSI C89 compatible to be included in the amalgamation header
- Must include its dependencies (exception: libc/integral/normalize.inc)
- Must not define objects (i.e. `cc -c -xc foo.h` will produce empty `.o`)
- Should not use typedefs
- Should not use forward declarations
- Should not include documentation comments
- Should not include parameter names in prototypes
- Should not pose problems if included by C++ or Assembly sources
- Should not declare non-ANSI code, at all, when the user requests ANSI
### Build Config
- Must not write files outside `o/`
- Must not communicate with Internet
- Must not depend on system libraries
- Must not depend on system commands (exception: sh, make, gzip, zip)

743
Makefile
View file

@ -1,5 +1,5 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set et ft=make ts=8 sw=8 fenc=utf-8 :vi ──────────────────────┘
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
@ -21,23 +21,23 @@
# make -j8 -O MODE=tiny
#
# # build individual target
# make -j8 -O o//examples/hello
# o//examples/hello
# make -j8 -O o//examples/hello.com
# o//examples/hello.com
#
# # view source
# less examples/hello.c
#
# # view binary
# o//tool/viz/bing o//examples/hello |
# o//tool/viz/fold
# o//tool/viz/bing.com o//examples/hello.com |
# o//tool/viz/fold.com
#
# # view transitive closure of legalese
# o//tool/viz/bing -n o//examples/hello |
# o//tool/viz/fold
# o//tool/viz/bing.com -n o//examples/hello.com |
# o//tool/viz/fold.com
#
# # basic debugging
# make -j8 -O MODE=dbg o/dbg/examples/crashreport
# o/examples/crashreport
# make -j8 -O MODE=dbg o/dbg/examples/crashreport.com
# o/examples/crashreport.com
# less examples/crashreport.c
#
# # extremely tiny binaries
@ -51,7 +51,7 @@
#
# TROUBLESHOOTING
#
# make -j8 -O V=1 o//examples/hello
# make -j8 -O V=1 o//examples/hello.com
# make o//examples/life.elf -pn |& less
# etc.
#
@ -59,124 +59,20 @@
#
# build/config.mk
SHELL = build/bootstrap/cocmd
SHELL = build/bootstrap/cocmd.com
HOSTS ?= freebsd openbsd netbsd rhel7 rhel5 win10 xnu
MAKEFLAGS += --no-builtin-rules
.SUFFIXES:
.DELETE_ON_ERROR:
.FEATURES: output-sync
.PHONY: all o bins check test depend tags aarch64 clean
.PHONY: all o bins check test depend tags
ifneq ($(m),)
ifeq ($(MODE),)
MODE := $(m)
endif
endif
COMMA := ,
PWD := $(shell pwd)
# detect wsl2 running cosmopolitan binaries on the host by checking whether:
# - user ran .cosmocc/current/bin/make, in which case make's working directory
# is in wsl
# - user ran make, in which case cocmd's working directory is in wsl
ifneq ($(findstring //wsl.localhost/,$(CURDIR) $(PWD)),)
$(warning wsl2 interop is enabled)
$(error you need to run sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop')
endif
UNAME_M := $(shell uname -m)
UNAME_S := $(shell uname -s)
# apple still distributes a 17 year old version of gnu make
ifeq ($(MAKE_VERSION), 3.81)
$(error please use https://cosmo.zip/pub/cosmos/bin/make)
endif
LC_ALL = C
SOURCE_DATE_EPOCH = 0
ARFLAGS = rcsD
ZFLAGS ?=
XARGS ?= xargs -P4 -rs8000
DOT ?= dot
CLANG = clang
TMPDIR = o/tmp
AR = $(BOOTSTRAP)/ar.ape
CP = $(BOOTSTRAP)/cp.ape
RM = $(BOOTSTRAP)/rm.ape -f
GZIP = $(BOOTSTRAP)/gzip.ape
ECHO = $(BOOTSTRAP)/echo.ape
CHMOD = $(BOOTSTRAP)/chmod.ape
TOUCH = $(BOOTSTRAP)/touch.ape
PKG = $(BOOTSTRAP)/package.ape
MKDEPS = $(BOOTSTRAP)/mkdeps
ZIPOBJ = $(BOOTSTRAP)/zipobj
ZIPCOPY = $(BOOTSTRAP)/zipcopy
PECHECK = $(BOOTSTRAP)/pecheck
FIXUPOBJ = $(BOOTSTRAP)/fixupobj
OBJBINCOPY = $(BOOTSTRAP)/objbincopy
MKDIR = $(BOOTSTRAP)/mkdir.ape -p
COMPILE = $(BOOTSTRAP)/compile.ape -V9 -M2048m -P8192 $(QUOTA)
# the default build modes is empty string
# on x86_64 hosts, MODE= is the same as MODE=x86_64
# on aarch64 hosts, MODE= is changed to MODE=aarch64
ifeq ($(MODE),)
ifeq ($(UNAME_M),arm64)
MODE := aarch64
endif
ifeq ($(UNAME_M),aarch64)
MODE := aarch64
endif
endif
ifneq ($(findstring aarch64,$(MODE)),)
ARCH = aarch64
HOSTS ?= pi pi5 studio freebsdarm
else
ARCH = x86_64
HOSTS ?= freebsd rhel7 xnu openbsd netbsd win10 luna
endif
ZIPOBJ_FLAGS += -a$(ARCH)
export ADDR2LINE
export LC_ALL
export MKDIR
export MODE
export SOURCE_DATE_EPOCH
export TMPDIR
COSMOCC = .cosmocc/3.9.2
BOOTSTRAP = $(COSMOCC)/bin
TOOLCHAIN = $(COSMOCC)/bin/$(ARCH)-linux-cosmo-
DOWNLOAD := $(shell build/download-cosmocc.sh $(COSMOCC) 3.9.2 f4ff13af65fcd309f3f1cfd04275996fb7f72a4897726628a8c9cf732e850193)
IGNORE := $(shell $(MKDIR) $(TMPDIR))
AS = $(TOOLCHAIN)as
CC = $(TOOLCHAIN)gcc
CXX = $(TOOLCHAIN)g++
CXXFILT = $(TOOLCHAIN)c++filt
LD = $(TOOLCHAIN)ld.bfd
NM = $(TOOLCHAIN)nm
GCC = $(TOOLCHAIN)gcc
STRIP = $(TOOLCHAIN)strip
OBJCOPY = $(TOOLCHAIN)objcopy
OBJDUMP = $(TOOLCHAIN)objdump
ifneq ($(wildcard $(PWD)/$(TOOLCHAIN)addr2line),)
ADDR2LINE = $(PWD)/$(TOOLCHAIN)addr2line
else
ADDR2LINE = $(TOOLCHAIN)addr2line
endif
# primary build rules
all: o
o: o/$(MODE)
o/$(MODE): \
o/$(MODE)/ape \
o/$(MODE)/ctl \
o/$(MODE)/dsp \
o/$(MODE)/net \
o/$(MODE)/libc \
@ -185,44 +81,18 @@ o/$(MODE): \
o/$(MODE)/examples \
o/$(MODE)/third_party
# TODO(jart): Make Emacs `C-c C-c` shortcut not need this.
.PHONY: o/$(MODE)/ o/$(MODE)/.
o/$(MODE)/: o/$(MODE)
o/$(MODE)/.: o/$(MODE)
# check if we're using o//third_party/make/make
# we added sandboxing to guarantee cosmo's makefile is hermetic
# it also shaves away 200ms of startup latency with native $(uniq)
ifneq ($(LANDLOCKMAKE_VERSION),)
ifeq ($(UNAME_S),Linux)
ifeq ($(wildcard /usr/bin/ape),)
$(warning please run ape/apeinstall.sh if you intend to use landlock make)
$(shell sleep .5)
endif
endif
ifneq ($(TOOLCHAIN),)
.STRICT = 1
endif
endif
.PLEDGE += stdio rpath wpath cpath fattr proc
.UNVEIL += \
libc/integral \
libc/stdbool.h \
rwc:/dev/shm \
rx:.cosmocc \
rx:build/bootstrap \
r:build/portcosmo.h \
/proc/stat \
rw:/dev/null \
rw:/dev/full \
w:o/stack.log \
/etc/hosts \
~/.runit.psk \
/proc/self/status \
rx:/usr/bin/qemu-aarch64 \
rx:o/third_party/qemu/qemu-aarch64 \
/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
.PLEDGE = stdio rpath wpath cpath fattr proc
.UNVEIL = \
libc/integral \
libc/disclaimer.inc \
rx:build/bootstrap \
rx:o/third_party/gcc \
/proc/self/status \
rw:/dev/null \
w:o/stack.log \
/etc/hosts \
~/.runit.psk
PKGS =
@ -231,164 +101,131 @@ include build/functions.mk #─┐
include build/definitions.mk # ├──META
include build/config.mk # │ You can build
include build/rules.mk # │ You can topologically order
include build/online.mk #─┘
include libc/nexgen32e/BUILD.mk #─┐
include libc/sysv/BUILD.mk # ├──SYSTEM SUPPORT
include libc/nt/BUILD.mk # │ You can do math
include libc/intrin/BUILD.mk # │ You can use the stack
include third_party/compiler_rt/BUILD.mk # │ You can manipulate arrays
include libc/tinymath/BUILD.mk # │ You can issue raw system calls
include libc/str/BUILD.mk # │
include third_party/xed/BUILD.mk # │
include third_party/puff/BUILD.mk # │
include libc/elf/BUILD.mk # │
include ape/BUILD.mk # │
include libc/fmt/BUILD.mk # │
include libc/vga/BUILD.mk # │
include libc/irq/BUILD.mk #─┘
include libc/calls/BUILD.mk #─┐
include libc/irq/BUILD.mk # ├──SYSTEMS RUNTIME
include third_party/nsync/BUILD.mk # │ You can issue system calls
include libc/runtime/BUILD.mk # │
include libc/crt/BUILD.mk # │
include third_party/dlmalloc/BUILD.mk #─┘
include libc/mem/BUILD.mk #─┐
include third_party/gdtoa/BUILD.mk # ├──DYNAMIC RUNTIME
include third_party/nsync/mem/BUILD.mk # │ You can now use stdio
include libc/proc/BUILD.mk # │ You can now use threads
include libc/dlopen/BUILD.mk # │ You can now use processes
include libc/thread/BUILD.mk # │ You can finally call malloc()
include third_party/zlib/BUILD.mk # │
include libc/stdio/BUILD.mk # │
include tool/hello/BUILD.mk # │
include third_party/tz/BUILD.mk # │
include net/BUILD.mk # │
include third_party/vqsort/BUILD.mk # │
include libc/log/BUILD.mk # │
include third_party/getopt/BUILD.mk # │
include third_party/bzip2/BUILD.mk # │
include dsp/core/BUILD.mk # │
include third_party/zlib/gz/BUILD.mk # │
include third_party/intel/BUILD.mk # │
include third_party/aarch64/BUILD.mk # │
include libc/BUILD.mk #─┘
include libc/sock/BUILD.mk #─┐
include net/http/BUILD.mk # ├──ONLINE RUNTIME
include third_party/musl/BUILD.mk # │ You can communicate with the network
include third_party/regex/BUILD.mk # │
include third_party/tr/BUILD.mk # │
include third_party/sed/BUILD.mk # │
include libc/system/BUILD.mk # │
include libc/x/BUILD.mk # │
include dsp/scale/BUILD.mk # │
include dsp/mpeg/BUILD.mk # │
include dsp/tty/BUILD.mk # │
include dsp/audio/BUILD.mk # │
include dsp/prog/BUILD.mk # │
include dsp/BUILD.mk # │
include third_party/stb/BUILD.mk # │
include third_party/mbedtls/BUILD.mk # │
include third_party/ncurses/BUILD.mk # │
include third_party/readline/BUILD.mk # │
include third_party/libunwind/BUILD.mk # |
include third_party/libcxxabi/BUILD.mk # |
include third_party/double-conversion/BUILD.mk # │
include ctl/BUILD.mk # │
include third_party/libcxx/BUILD.mk # │
include third_party/openmp/BUILD.mk # │
include third_party/pcre/BUILD.mk # │
include third_party/less/BUILD.mk # │
include net/https/BUILD.mk #─┘
include third_party/tidy/BUILD.mk
include third_party/BUILD.mk
include third_party/nsync/testing/BUILD.mk
include libc/testlib/BUILD.mk
include tool/viz/lib/BUILD.mk
include tool/args/BUILD.mk
include test/math/BUILD.mk
include test/posix/BUILD.mk
include test/ctl/BUILD.mk
include test/libcxx/BUILD.mk
include test/tool/args/BUILD.mk
include third_party/linenoise/BUILD.mk
include third_party/maxmind/BUILD.mk
include net/finger/BUILD.mk
include third_party/double-conversion/test/BUILD.mk
include third_party/lua/BUILD.mk
include third_party/tree/BUILD.mk
include third_party/zstd/BUILD.mk
include third_party/awk/BUILD.mk
include third_party/hiredis/BUILD.mk
include third_party/make/BUILD.mk
include third_party/ctags/BUILD.mk
include third_party/finger/BUILD.mk
include third_party/argon2/BUILD.mk
include third_party/smallz4/BUILD.mk
include third_party/sqlite3/BUILD.mk
include third_party/mbedtls/test/BUILD.mk
include third_party/lz4cli/BUILD.mk
include third_party/zip/BUILD.mk
include third_party/xxhash/BUILD.mk
include third_party/unzip/BUILD.mk
include tool/build/lib/BUILD.mk
include third_party/chibicc/BUILD.mk
include third_party/chibicc/test/BUILD.mk
include third_party/python/BUILD.mk
include tool/build/BUILD.mk
include tool/curl/BUILD.mk
include third_party/qemu/BUILD.mk
include third_party/libcxxabi/test/BUILD.mk
include examples/BUILD.mk
include examples/pyapp/BUILD.mk
include examples/pylife/BUILD.mk
include tool/decode/lib/BUILD.mk
include tool/decode/BUILD.mk
include tool/lambda/lib/BUILD.mk
include tool/lambda/BUILD.mk
include tool/plinko/lib/BUILD.mk
include tool/plinko/BUILD.mk
include test/tool/plinko/BUILD.mk
include tool/net/BUILD.mk
include tool/viz/BUILD.mk
include tool/BUILD.mk
include net/turfwar/BUILD.mk
include test/libc/tinymath/BUILD.mk
include test/libc/intrin/BUILD.mk
include test/libc/mem/BUILD.mk
include test/libc/nexgen32e/BUILD.mk
include test/libc/runtime/BUILD.mk
include test/libc/thread/BUILD.mk
include test/libc/sock/BUILD.mk
include test/libc/str/BUILD.mk
include test/libc/log/BUILD.mk
include test/libc/str/BUILD.mk
include test/libc/calls/BUILD.mk
include test/libc/x/BUILD.mk
include test/libc/xed/BUILD.mk
include test/libc/fmt/BUILD.mk
include test/libc/time/BUILD.mk
include test/libc/proc/BUILD.mk
include test/libc/stdio/BUILD.mk
include test/libc/system/BUILD.mk
include test/libc/BUILD.mk
include test/net/http/BUILD.mk
include test/net/https/BUILD.mk
include test/net/finger/BUILD.mk
include test/net/BUILD.mk
include test/tool/build/lib/BUILD.mk
include test/tool/build/BUILD.mk
include test/tool/viz/lib/BUILD.mk
include test/tool/viz/BUILD.mk
include test/tool/net/BUILD.mk
include test/tool/BUILD.mk
include test/dsp/core/BUILD.mk
include test/dsp/scale/BUILD.mk
include test/dsp/tty/BUILD.mk
include test/dsp/BUILD.mk
include examples/package/lib/BUILD.mk
include examples/package/BUILD.mk
include build/online.mk # │
include libc/stubs/stubs.mk #─┘
include libc/nexgen32e/nexgen32e.mk #─┐
include libc/sysv/sysv.mk # ├──SYSTEM SUPPORT
include libc/nt/nt.mk # │ You can do math
include libc/intrin/intrin.mk # │ You can use the stack
include libc/linux/linux.mk # │ You can manipulate arrays
include libc/tinymath/tinymath.mk # │ You can issue raw system calls
include third_party/compiler_rt/compiler_rt.mk # │
include libc/str/str.mk # │
include third_party/xed/xed.mk # │
include third_party/zlib/zlib.mk # │
include libc/elf/elf.mk # │
include ape/ape.mk # │
include libc/fmt/fmt.mk #─┘
include libc/calls/calls.mk #─┐
include libc/runtime/runtime.mk # ├──SYSTEMS RUNTIME
include libc/crt/crt.mk # │ You can issue system calls
include third_party/dlmalloc/dlmalloc.mk #─┘
include libc/mem/mem.mk #─┐
include libc/zipos/zipos.mk # ├──DYNAMIC RUNTIME
include third_party/gdtoa/gdtoa.mk # │ You can now use stdio
include libc/time/time.mk # │ You can finally call malloc()
include libc/thread/thread.mk # │
include libc/stdio/stdio.mk # │
include third_party/libcxx/libcxx.mk # │
include net/net.mk # │
include libc/log/log.mk # │
include third_party/bzip2/bzip2.mk # │
include dsp/core/core.mk # │
include libc/x/x.mk # │
include third_party/stb/stb.mk # │
include dsp/scale/scale.mk # │
include dsp/mpeg/mpeg.mk # │
include dsp/dsp.mk # │
include third_party/zlib/gz/gz.mk # │
include third_party/musl/musl.mk # │
include third_party/getopt/getopt.mk # │
include libc/libc.mk #─┘
include libc/sock/sock.mk #─┐
include dsp/tty/tty.mk # ├──ONLINE RUNTIME
include libc/dns/dns.mk # │ You can communicate with the network
include net/http/http.mk # │
include third_party/mbedtls/mbedtls.mk # │
include net/https/https.mk # │
include third_party/regex/regex.mk #─┘
include third_party/tidy/tidy.mk
include third_party/third_party.mk
include libc/testlib/testlib.mk
include tool/viz/lib/vizlib.mk
include tool/args/args.mk
include test/tool/args/test.mk
include third_party/linenoise/linenoise.mk
include third_party/maxmind/maxmind.mk
include net/finger/finger.mk
include third_party/double-conversion/double-conversion.mk
include third_party/lua/lua.mk
include third_party/make/make.mk
include third_party/finger/finger.mk
include third_party/argon2/argon2.mk
include third_party/smallz4/smallz4.mk
include third_party/sqlite3/sqlite3.mk
include third_party/mbedtls/test/test.mk
include third_party/quickjs/quickjs.mk
include third_party/lz4cli/lz4cli.mk
include third_party/zip/zip.mk
include third_party/unzip/unzip.mk
include tool/build/lib/buildlib.mk
include third_party/chibicc/chibicc.mk
include third_party/chibicc/test/test.mk
include third_party/python/python.mk
include tool/build/emucrt/emucrt.mk
include tool/build/emubin/emubin.mk
include tool/build/build.mk
include examples/examples.mk
include examples/pyapp/pyapp.mk
include examples/pylife/pylife.mk
include tool/decode/lib/decodelib.mk
include tool/decode/decode.mk
include tool/lambda/lib/lib.mk
include tool/lambda/lambda.mk
include tool/plinko/lib/lib.mk
include tool/plinko/plinko.mk
include test/tool/plinko/test.mk
include tool/hash/hash.mk
include tool/net/net.mk
include tool/viz/viz.mk
include tool/tool.mk
include test/libc/tinymath/test.mk
include test/libc/intrin/test.mk
include test/libc/mem/test.mk
include test/libc/nexgen32e/test.mk
include test/libc/runtime/test.mk
include test/libc/thread/test.mk
include test/libc/sock/test.mk
include test/libc/str/test.mk
include test/libc/log/test.mk
include test/libc/str/test.mk
include test/libc/calls/test.mk
include test/libc/x/test.mk
include test/libc/xed/test.mk
include test/libc/fmt/test.mk
include test/libc/dns/test.mk
include test/libc/time/test.mk
include test/libc/stdio/test.mk
include test/libc/release/test.mk
include test/libc/test.mk
include test/net/http/test.mk
include test/net/https/test.mk
include test/net/finger/test.mk
include test/net/test.mk
include test/tool/build/lib/test.mk
include test/tool/build/test.mk
include test/tool/viz/lib/test.mk
include test/tool/viz/test.mk
include test/tool/net/test.mk
include test/tool/test.mk
include test/dsp/core/test.mk
include test/dsp/scale/test.mk
include test/dsp/tty/test.mk
include test/dsp/test.mk
include examples/package/lib/build.mk
include examples/package/build.mk
#-φ-examples/package/new.sh
include test/BUILD.mk
include test/test.mk
OBJS = $(foreach x,$(PKGS),$($(x)_OBJS))
SRCS := $(foreach x,$(PKGS),$($(x)_SRCS))
@ -407,164 +244,130 @@ tags: TAGS HTAGS
o/$(MODE)/.x:
@$(COMPILE) -AMKDIR -tT$@ $(MKDIR) $(@D)
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x)))) $(SRCS)
o/$(MODE)/srcs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@,$(SRCS))
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x)))) $(HDRS) $(INCS)
o/$(MODE)/hdrs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@,$(HDRS) $(INCS))
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x)))) $(INCS) $(INCS)
o/$(MODE)/incs.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(INCS) $(INCS),$(dir $(x))))
$(file >$@,$(INCS))
o/$(MODE)/depend: o/$(MODE)/.x o/$(MODE)/srcs.txt o/$(MODE)/hdrs.txt o/$(MODE)/incs.txt $(SRCS) $(HDRS) $(INCS)
$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -s -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
@$(COMPILE) -AMKDEPS -L320 $(MKDEPS) -o $@ -r o/$(MODE)/ @o/$(MODE)/srcs.txt @o/$(MODE)/hdrs.txt @o/$(MODE)/incs.txt
o/$(MODE)/srcs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(SRCS),$(dir $(x))))
$(file >$@) $(foreach x,$(SRCS),$(file >>$@,$(x)))
o/$(MODE)/hdrs-old.txt: o/$(MODE)/.x $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x))))
$(file >$@) $(foreach x,$(HDRS) $(INCS),$(file >>$@,$(x)))
TAGS: private .UNSANDBOXED = 1
TAGS: o/$(MODE)/srcs-old.txt $(SRCS) #o/$(MODE)/third_party/ctags/ctags
TAGS: .UNSANDBOXED = 1
TAGS: o/$(MODE)/srcs-old.txt $(SRCS)
@$(RM) $@
@o/$(MODE)/third_party/ctags/ctags $(TAGSFLAGS) -L $< -o $@
@$(TAGS) $(TAGSFLAGS) -L $< -o $@
HTAGS: private .UNSANDBOXED = 1
HTAGS: o/$(MODE)/hdrs-old.txt $(filter-out third_party/libcxx/%,$(HDRS)) #o/$(MODE)/third_party/ctags/ctags
HTAGS: .UNSANDBOXED = 1
HTAGS: o/$(MODE)/hdrs-old.txt $(HDRS)
@$(RM) $@
@build/htags o/$(MODE)/third_party/ctags/ctags -L $< -o $@
@build/htags -L $< -o $@
loc: private .UNSANDBOXED = 1
loc: o/$(MODE)/tool/build/summy
find -name \*.h -or -name \*.hpp -or -name \*.c -or -name \*.cc -or -name \*.cpp -or -name \*.S -or -name \*.mk | \
loc: .UNSANDBOXED = 1
loc: o/$(MODE)/tool/build/summy.com
find -name \*.h -or -name \*.c -or -name \*.S | \
$(XARGS) wc -l | grep total | awk '{print $$1}' | $<
COSMOPOLITAN = \
CTL \
DSP_AUDIO \
LIBC_CALLS \
LIBC_DLOPEN \
LIBC_ELF \
LIBC_FMT \
LIBC_INTRIN \
LIBC_IRQ \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT_ADVAPI32 \
LIBC_NT_BCRYPTPRIMITIVES \
LIBC_NT_COMDLG32 \
LIBC_NT_GDI32 \
LIBC_NT_IPHLPAPI \
LIBC_NT_KERNEL32 \
LIBC_NT_NTDLL \
LIBC_NT_PDH \
LIBC_NT_POWRPROF \
LIBC_NT_PSAPI \
LIBC_NT_REALTIME \
LIBC_NT_SHELL32 \
LIBC_NT_SYNCHRONIZATION \
LIBC_NT_USER32 \
LIBC_NT_WS2_32 \
LIBC_PROC \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_STR \
LIBC_SYSTEM \
LIBC_SYSV \
LIBC_SYSV_CALLS \
LIBC_THREAD \
LIBC_TINYMATH \
LIBC_VGA \
LIBC_X \
NET_HTTP \
THIRD_PARTY_COMPILER_RT \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_DOUBLECONVERSION \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
THIRD_PARTY_MUSL \
THIRD_PARTY_NSYNC \
THIRD_PARTY_NSYNC_MEM \
THIRD_PARTY_OPENMP \
THIRD_PARTY_PUFF \
THIRD_PARTY_REGEX \
THIRD_PARTY_TZ \
THIRD_PARTY_XED \
THIRD_PARTY_ZLIB \
THIRD_PARTY_ZLIB_GZ \
TOOL_ARGS \
COSMOPOLITAN_OBJECTS = \
NET_HTTP \
LIBC_DNS \
LIBC_SOCK \
LIBC_NT_WS2_32 \
LIBC_NT_IPHLPAPI \
LIBC_NT_MSWSOCK \
LIBC_X \
THIRD_PARTY_GETOPT \
LIBC_LOG \
LIBC_TIME \
LIBC_ZIPOS \
THIRD_PARTY_ZLIB \
THIRD_PARTY_MUSL \
LIBC_STDIO \
THIRD_PARTY_GDTOA \
THIRD_PARTY_REGEX \
LIBC_MEM \
THIRD_PARTY_DLMALLOC \
LIBC_RUNTIME \
LIBC_ELF \
LIBC_CALLS \
LIBC_SYSV_CALLS \
LIBC_NT_PSAPI \
LIBC_NT_POWRPROF \
LIBC_NT_PDH \
LIBC_NT_GDI32 \
LIBC_NT_COMDLG32 \
LIBC_NT_URL \
LIBC_NT_USER32 \
LIBC_NT_NTDLL \
LIBC_NT_ADVAPI32 \
LIBC_FMT \
THIRD_PARTY_COMPILER_RT \
LIBC_THREAD \
LIBC_TINYMATH \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_INTRIN \
LIBC_NT_KERNEL32 \
LIBC_NEXGEN32E
COSMOPOLITAN_H_PKGS = \
APE \
DSP_AUDIO \
LIBC \
LIBC_CALLS \
LIBC_ELF \
LIBC_FMT \
LIBC_DLOPEN \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
LIBC_PROC \
THIRD_PARTY_NSYNC \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TINYMATH \
LIBC_X \
LIBC_VGA \
NET_HTTP \
TOOL_ARGS \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_ZLIB_GZ \
COSMOPOLITAN_HEADERS = \
APE \
LIBC \
LIBC_CALLS \
LIBC_DNS \
LIBC_ELF \
LIBC_FMT \
LIBC_INTRIN \
LIBC_LOG \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_NT \
LIBC_RUNTIME \
LIBC_SOCK \
LIBC_STDIO \
THIRD_PARTY_XED \
LIBC_STR \
LIBC_SYSV \
LIBC_THREAD \
LIBC_TIME \
LIBC_TINYMATH \
LIBC_X \
LIBC_ZIPOS \
NET_HTTP \
THIRD_PARTY_DLMALLOC \
THIRD_PARTY_GDTOA \
THIRD_PARTY_GETOPT \
THIRD_PARTY_MUSL \
THIRD_PARTY_ZLIB \
THIRD_PARTY_ZLIB_GZ \
THIRD_PARTY_REGEX
COSMOCC_PKGS = \
$(COSMOPOLITAN_H_PKGS) \
CTL \
THIRD_PARTY_AARCH64 \
THIRD_PARTY_LIBCXX \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
THIRD_PARTY_OPENMP \
THIRD_PARTY_INTEL
o/$(MODE)/cosmopolitan.a: \
$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_A_OBJS))
o/$(MODE)/cosmopolitan.a: \
$(call reverse,$(call uniq,$(foreach x,$(COSMOPOLITAN),$($(x)))))
o/cosmopolitan.h: \
o/$(MODE)/tool/build/rollup.com \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)) \
$(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_INCS))
$(file >$(TMPDIR)/$(subst /,_,$@),libc/integral/normalize.inc $(foreach x,$(COSMOPOLITAN_HEADERS),$($(x)_HDRS)))
@$(COMPILE) -AROLLUP -T$@ o/$(MODE)/tool/build/rollup.com @$(TMPDIR)/$(subst /,_,$@) >$@
COSMOCC_HDRS = \
$(wildcard libc/integral/*) \
$(foreach x,$(COSMOCC_PKGS),$($(x)_HDRS)) \
$(foreach x,$(COSMOCC_PKGS),$($(x)_INCS))
o/cosmocc.h.txt: Makefile libc $(MAKEFILES) $(call uniq,$(foreach x,$(HDRS) $(INCS),$(dir $(x)))) $(HDRS) $(INCS)
$(file >$@, $(call uniq,$(COSMOCC_HDRS)))
COSMOPOLITAN_H_ROOT_HDRS = \
libc/integral/normalize.inc \
$(foreach x,$(COSMOPOLITAN_H_PKGS),$($(x)_HDRS))
o/cosmopolitan.html: private .UNSANDBOXED = 1
o/cosmopolitan.html: \
o/$(MODE)/third_party/chibicc/chibicc.dbg \
o/$(MODE)/third_party/chibicc/chibicc.com.dbg \
$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))) \
$(filter-out %.cpp,$(filter-out %.cc,$(SRCS))) \
$(SRCS) \
$(HDRS)
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.cpp,$(filter-out %.cc,$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))))
o/$(MODE)/third_party/chibicc/chibicc.dbg -J \
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter-out %.s,$(foreach x,$(COSMOPOLITAN_OBJECTS),$($(x)_SRCS))))
o/$(MODE)/third_party/chibicc/chibicc.com.dbg -J \
-fno-common -include libc/integral/normalize.inc -o $@ \
-DCOSMO @$(TMPDIR)/$(subst /,_,$@)
@$(TMPDIR)/$(subst /,_,$@)
$(SRCS): \
libc/integral/normalize.inc \
@ -574,50 +377,6 @@ $(SRCS): \
libc/integral/lp64arg.inc \
libc/integral/lp64.inc
ifeq ($(ARCH), x86_64)
TOOLCHAIN_ARTIFACTS = \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/ape/ape.elf \
o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape-copy-self.o \
o/$(MODE)/ape/ape-no-modify-self.o \
o/$(MODE)/cosmopolitan.a \
o/$(MODE)/third_party/libcxx/libcxx.a \
o/$(MODE)/tool/build/march-native \
o/$(MODE)/tool/build/ar \
o/$(MODE)/tool/build/mktemper \
o/$(MODE)/tool/build/fixupobj \
o/$(MODE)/tool/build/zipcopy \
o/$(MODE)/tool/build/apelink \
o/$(MODE)/tool/build/pecheck
else
TOOLCHAIN_ARTIFACTS = \
o/$(MODE)/ape/ape.elf \
o/$(MODE)/ape/aarch64.lds \
o/$(MODE)/libc/crt/crt.o \
o/$(MODE)/cosmopolitan.a \
o/$(MODE)/third_party/libcxx/libcxx.a \
o/$(MODE)/tool/build/march-native \
o/$(MODE)/tool/build/fixupobj \
o/$(MODE)/tool/build/zipcopy
endif
.PHONY: toolchain
toolchain: $(TOOLCHAIN_ARTIFACTS)
.PHONY: clean_toolchain
clean_toolchain:
$(RM) $(TOOLCHAIN_ARTIFACTS)
aarch64: private .INTERNET = true
aarch64: private .UNSANDBOXED = true
aarch64:
$(MAKE) m=aarch64
clean:
$(RM) -r o
# UNSPECIFIED PREREQUISITES TUTORIAL
#
# A build rule must exist for all files that make needs to consider in
@ -642,9 +401,9 @@ $(SRCS):
$(HDRS):
$(INCS):
.DEFAULT:
@$(ECHO)
@$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@
@$(ECHO)
@$(ECHO) >&2
@$(ECHO) NOTE: deleting o/$(MODE)/depend because of an unspecified prerequisite: $@ >&2
@$(ECHO) >&2
$(RM) o/$(MODE)/depend
-include o/$(MODE)/depend

320
README.md
View file

@ -3,170 +3,200 @@
[![build](https://github.com/jart/cosmopolitan/actions/workflows/build.yml/badge.svg)](https://github.com/jart/cosmopolitan/actions/workflows/build.yml)
# Cosmopolitan
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C/C++
[Cosmopolitan Libc](https://justine.lol/cosmopolitan/index.html) makes C
a build-once run-anywhere language, like Java, except it doesn't need an
interpreter or virtual machine. Instead, it reconfigures stock GCC and
Clang to output a POSIX-approved polyglot format that runs natively on
Linux + Mac + Windows + FreeBSD + OpenBSD 7.3 + NetBSD + BIOS with the
best possible performance and the tiniest footprint imaginable.
Linux + Mac + Windows + FreeBSD + OpenBSD + NetBSD + BIOS with the best
possible performance and the tiniest footprint imaginable.
## Background
For an introduction to this project, please read the [actually portable
executable](https://justine.lol/ape.html) blog post and [cosmopolitan
For an introduction to this project, please read the [αcτµαlly pδrταblε
εxεcµταblε](https://justine.lol/ape.html) blog post and [cosmopolitan
libc](https://justine.lol/cosmopolitan/index.html) website. We also have
[API
documentation](https://justine.lol/cosmopolitan/documentation.html).
[API documentation](https://justine.lol/cosmopolitan/documentation.html).
## Getting Started
You can start by obtaining a release of our `cosmocc` compiler from
<https://cosmo.zip/pub/cosmocc/>.
If you're doing your development work on Linux or BSD then you need just
five files to get started. Here's what you do on Linux:
```sh
mkdir -p cosmocc
cd cosmocc
wget https://cosmo.zip/pub/cosmocc/cosmocc.zip
unzip cosmocc.zip
wget https://justine.lol/cosmopolitan/cosmopolitan.zip
unzip cosmopolitan.zip
printf 'main() { printf("hello world\\n"); }\n' >hello.c
gcc -g -Os -static -nostdlib -nostdinc -fno-pie -no-pie -mno-red-zone \
-fno-omit-frame-pointer -pg -mnop-mcount -mno-tls-direct-seg-refs \
-o hello.com.dbg hello.c -fuse-ld=bfd -Wl,-T,ape.lds \
-include cosmopolitan.h crt.o ape-no-modify-self.o cosmopolitan.a
objcopy -S -O binary hello.com.dbg hello.com
```
Here's an example program we can write:
```c
// hello.c
#include <stdio.h>
int main() {
printf("hello world\n");
}
```
It can be compiled as follows:
You now have a portable program.
```sh
cosmocc -o hello hello.c
./hello
./hello.com
bash -c './hello.com' # zsh/fish workaround (we patched them in 2021)
```
The Cosmopolitan Libc runtime links some heavyweight troubleshooting
features by default, which are very useful for developers and admins.
Here's how you can log system calls:
Since we used the `ape-no-modify-self.o` bootloader (rather than
`ape.o`) your executable will not modify itself when it's run. What
it'll instead do, is extract a 4kb program to `${TMPDIR:-${HOME:-.}}`
that maps your program into memory without needing to copy it. It's
possible to install the APE loader systemwide as follows.
```sh
./hello --strace
# System-Wide APE Install
# for Linux, Darwin, and BSDs
# 1. Copies APE Loader to /usr/bin/ape
# 2. Registers w/ binfmt_misc too if Linux
ape/apeinstall.sh
# System-Wide APE Uninstall
# for Linux, Darwin, and BSDs
ape/apeuninstall.sh
```
Here's how you can get a much more verbose log of function calls:
It's also possible to convert APE binaries into the system-local format
by using the `--assimilate` flag. Please note that if binfmt_misc is in
play, you'll need to unregister it temporarily before doing this, since
the assimilate feature is part of the shell script header.
```sh
./hello --ftrace
$ file hello.com
hello.com: DOS/MBR boot sector
./hello.com --assimilate
$ file hello.com
hello.com: ELF 64-bit LSB executable
```
You can use the Cosmopolitan's toolchain to build conventional open
source projects which use autotools. This strategy normally works:
Now that you're up and running with Cosmopolitan Libc and APE, here's
some of the most important troubleshooting tools APE offers that you
should know, in case you encounter any issues:
```sh
export CC=x86_64-unknown-cosmo-cc
export CXX=x86_64-unknown-cosmo-c++
./configure --prefix=/opt/cosmos/x86_64
make -j
make install
./hello.com --strace # log system calls to stderr
./hello.com --ftrace # log function calls to stderr
```
## Cosmopolitan Source Builds
Do you love tiny binaries? If so, you may not be happy with Cosmo adding
heavyweight features like tracing to your binaries by default. In that
case, you may want to consider using our build system:
Cosmopolitan can be compiled from source on any of our supported
platforms. The Makefile will download cosmocc automatically.
```sh
make -j8 MODE=tiny
```
It's recommended that you install a systemwide APE Loader. This command
requires `sudo` access to copy the `ape` command to a system folder and
register with binfmt_misc on Linux, for even more performance.
Which will cause programs such as `hello.com` and `life.com` to shrink
from 60kb in size to about 16kb. There's also a prebuilt amalgamation
online <https://justine.lol/cosmopolitan/cosmopolitan-tiny.zip> hosted
on our download page <https://justine.lol/cosmopolitan/download.html>.
### MacOS
If you're developing on MacOS you can install the GNU compiler
collection for x86_64-elf via homebrew:
```sh
brew install x86_64-elf-gcc
```
Then in the above scripts just replace `gcc` and `objcopy` with
`x86_64-elf-gcc` and `x86_64-elf-objcopy` to compile your APE binary.
### Windows
If you're developing on Windows then you need to download an
x86_64-pc-linux-gnu toolchain beforehand. See the [Compiling on
Windows](https://justine.lol/cosmopolitan/windows-compiling.html)
tutorial. It's needed because the ELF object format is what makes
universal binaries possible.
Cosmopolitan officially only builds on Linux. However, one highly
experimental (and currently broken) thing you could try, is building the
entire cosmo repository from source using the cross9 toolchain.
```
mkdir -p o/third_party
rm -rf o/third_party/gcc
wget https://justine.lol/linux-compiler-on-windows/cross9.zip
unzip cross9.zip
mv cross9 o/third_party/gcc
build/bootstrap/make.com
```
## Source Builds
Cosmopolitan can be compiled from source on any Linux distro. First, you
need to download or clone the repository.
```sh
wget https://justine.lol/cosmopolitan/cosmopolitan.tar.gz
tar xf cosmopolitan.tar.gz # see releases page
cd cosmopolitan
```
This will build the entire repository and run all the tests:
```sh
build/bootstrap/make.com -j16
o//examples/hello.com
find o -name \*.com | xargs ls -rShal | less
```
If you get an error running make.com then it's probably because you have
WINE installed to `binfmt_misc`. You can fix that by installing the the
APE loader as an interpreter. It'll improve build performance too!
```sh
ape/apeinstall.sh
```
You can now build the mono repo with any modern version of GNU Make. To
bootstrap your build, you can install Cosmopolitan Make from this site:
https://cosmo.zip/pub/cosmos/bin/make
E.g.:
```sh
curl -LO https://cosmo.zip/pub/cosmos/bin/make
./make -j8
o//examples/hello
```
After you've built the repo once, you can also use the make from your
cosmocc at `.cosmocc/current/bin/make`. You might even prefer to alias
make to `$COSMO/.cosmocc/current/bin/make`.
Since the Cosmopolitan repository is very large, you might only want to
build one particular thing. Here's an example of a target that can be
compiled relatively quickly, which is a simple POSIX test that only
depends on core LIBC packages.
build a particular thing. Cosmopolitan's build config does a good job at
having minimal deterministic builds. For example, if you wanted to build
only hello.com then you could do that as follows:
```sh
rm -rf o//libc o//test
.cosmocc/current/bin/make o//test/posix/signal_test
o//test/posix/signal_test
build/bootstrap/make.com -j16 o//examples/hello.com
```
Sometimes it's desirable to build a subset of targets, without having to
list out each individual one. For example if you wanted to build and run
all the unit tests in the `TEST_POSIX` package, you could say:
list out each individual one. You can do that by asking make to build a
directory name. For example, if you wanted to build only the targets and
subtargets of the chibicc package including its tests, you would say:
```sh
.cosmocc/current/bin/make o//test/posix
build/bootstrap/make.com -j16 o//third_party/chibicc
o//third_party/chibicc/chibicc.com --help
```
Cosmopolitan provides a variety of build modes. For example, if you want
really tiny binaries (as small as 12kb in size) then you'd say:
```sh
.cosmocc/current/bin/make m=tiny
build/bootstrap/make.com -j16 MODE=tiny
```
You can furthermore cut out the bloat of other operating systems, and
have Cosmopolitan become much more similar to Musl Libc.
Here's some other build modes you can try:
```sh
.cosmocc/current/bin/make m=tinylinux
build/bootstrap/make.com -j16 MODE=dbg # asan + ubsan + debug
build/bootstrap/make.com -j16 MODE=asan # production memory safety
build/bootstrap/make.com -j16 MODE=opt # -march=native optimizations
build/bootstrap/make.com -j16 MODE=rel # traditional release binaries
build/bootstrap/make.com -j16 MODE=optlinux # optimal linux-only performance
build/bootstrap/make.com -j16 MODE=tinylinux # tiniest linux-only 4kb binaries
```
For further details, see [//build/config.mk](build/config.mk).
## Debugging
To print a log of system calls to stderr:
```sh
cosmocc -o hello hello.c
./hello --strace
```
To print a log of function calls to stderr:
```sh
cosmocc -o hello hello.c
./hello --ftrace
```
Both strace and ftrace use the unbreakable kprintf() facility, which is
able to be sent to a file by setting an environment variable.
```sh
export KPRINTF_LOG=log
./hello --strace
```
## GDB
Here's the recommended `~/.gdbinit` config:
```gdb
```
set host-charset UTF-8
set target-charset UTF-8
set target-wide-charset UTF-8
@ -186,83 +216,25 @@ end
src
```
You normally run the `.dbg` file under gdb. If you need to debug the
`` file itself, then you can load the debug symbols independently as
You normally run the `.com.dbg` file under gdb. If you need to debug the
`.com` file itself, then you can load the debug symbols independently as
```sh
gdb foo -ex 'add-symbol-file foo.dbg 0x401000'
```
## Platform Notes
### Shells
If you use zsh and have trouble running APE programs try `sh -c ./prog`
or simply upgrade to zsh 5.9+ (since we patched it two years ago). The
same is the case for Python `subprocess`, old versions of fish, etc.
### Linux
Some Linux systems are configured to launch MZ executables under WINE.
Other distros configure their stock installs so that APE programs will
print "run-detectors: unable to find an interpreter". For example:
```sh
jart@ubuntu:~$ wget https://cosmo.zip/pub/cosmos/bin/dash
jart@ubuntu:~$ chmod +x dash
jart@ubuntu:~$ ./dash
run-detectors: unable to find an interpreter for ./dash
gdb foo.com -ex 'add-symbol-file foo.com.dbg 0x401000'
```
You can fix that by registering APE with `binfmt_misc`:
```sh
sudo wget -O /usr/bin/ape https://cosmo.zip/pub/cosmos/bin/ape-$(uname -m).elf
sudo chmod +x /usr/bin/ape
sudo sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
sudo sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register"
```
You should be good now. APE will not only work, it'll launch executables
400µs faster now too. However if things still didn't work out, it's also
possible to disable `binfmt_misc` as follows:
```sh
sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/cli' # remove Ubuntu's MZ interpreter
sudo sh -c 'echo -1 > /proc/sys/fs/binfmt_misc/status' # remove ALL binfmt_misc entries
```
### WSL
It's normally unsafe to use APE in a WSL environment, because it tries
to run MZ executables as WIN32 binaries within the WSL environment. In
order to make it safe to use Cosmopolitan software on WSL, run this:
```sh
sudo sh -c "echo -1 > /proc/sys/fs/binfmt_misc/WSLInterop"
```
## Discord Chatroom
The Cosmopolitan development team collaborates on the Redbean Discord
server. You're welcome to join us! <https://discord.gg/FwAVVu7eJ4>
## Support Vector
| Platform | Min Version | Circa |
| :--- | ---: | ---: |
| AMD | K8 | 2003 |
| Intel | Core | 2006 |
| Linux | 2.6.18 | 2007 |
| Windows | 8 [1] | 2012 |
| Darwin (macOS) | 23.1.0+ | 2023 |
| OpenBSD | 7.3 or earlier | 2023 |
| FreeBSD | 13 | 2020 |
| NetBSD | 9.2 | 2021 |
[1] See our [vista branch](https://github.com/jart/cosmopolitan/tree/vista)
for a community supported version of Cosmopolitan that works on Windows
Vista and Windows 7.
| Platform | Min Version | Circa |
| :--- | ---: | ---: |
| AMD | K8 Venus | 2005 |
| Intel | Core | 2006 |
| Windows | Vista | 2006 |
| Linux | 2.6.18 | 2007 |
| Mac OS X | 15.6 | 2018 |
| FreeBSD | 13 | 2020 |
| OpenBSD | 6.4 | 2018 |
| NetBSD | 9.2 | 2021 |
## Special Thanks
@ -270,10 +242,8 @@ Funding for this project is crowdsourced using
[GitHub Sponsors](https://github.com/sponsors/jart) and
[Patreon](https://www.patreon.com/jart). Your support is what makes this
project possible. Thank you! We'd also like to give special thanks to
the following groups and individuals:
the following individuals:
- [Joe Drumgoole](https://github.com/jdrumgoole)
- [Rob Figueiredo](https://github.com/robfig)
- [Wasmer](https://wasmer.io/)
For publicly sponsoring our work at the highest tier.

View file

@ -1,287 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
#
# OVERVIEW
#
# αcτµαlly pδrταblε εxεcµταblε
#
# DESCRIPTION
#
# This file defines the libraries, runtimes, and build rules needed to
# create executables from your Linux workstation that'll run anywhere.
# Loading this package will make certain systemic modifications to the
# build like turning off the System V "Red Zone" optimization, because
# αcτµαlly pδrταblε εxεcµταblεs need to be able to run in kernelspace.
PKGS += APE
APE_FILES := $(wildcard ape/*.*)
APE_HDRS = $(filter %.h,$(APE_FILES))
APE_INCS = $(filter %.inc,$(APE_FILES))
ifeq ($(ARCH), aarch64)
APE = o/$(MODE)/ape/aarch64.lds
APELINK = \
$(COMPILE) \
-ALINK.ape \
$(LINK) \
$(LINKARGS) \
$(OUTPUT_OPTION) && \
$(COMPILE) \
-AFIXUP.ape \
-wT$@ \
$(FIXUPOBJ) \
$@
APE_SRCS = ape/ape.S ape/start.S ape/launch.S ape/systemcall.S
APE_OBJS = o/$(MODE)/ape/ape.o
APE_NO_MODIFY_SELF = $(APE)
APE_COPY_SELF = $(APE)
.PHONY: o/$(MODE)/ape
o/$(MODE)/ape: $(APE)
o/$(MODE)/ape/aarch64.lds: \
ape/aarch64.lds \
libc/zip.h \
libc/thread/tls.h \
libc/calls/struct/timespec.h \
libc/macros.h \
libc/str/str.h
APE_LOADER_LDFLAGS = \
-pie \
-static \
-nostdlib \
--no-dynamic-linker \
-z norelro \
-z common-page-size=0x4000 \
-z max-page-size=0x4000
APE_LOADER_FLAGS = \
-DNDEBUG \
-iquote. \
-Wall \
-Wextra \
-fpie \
-Os \
-ffreestanding \
-mgeneral-regs-only \
-fno-asynchronous-unwind-tables \
-fno-stack-protector \
-fno-ident \
-fno-gnu-unique \
-c \
$(OUTPUT_OPTION) \
$<
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
@$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -g $< $@
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/$(MODE)/ape/ape.elf.dbg: \
o/$(MODE)/ape/start.o \
o/$(MODE)/ape/loader.o \
o/$(MODE)/ape/launch.o \
o/$(MODE)/ape/systemcall.o
@$(COMPILE) -ALINK.elf $(LD) $(APE_LOADER_LDFLAGS) -o $@ $(patsubst %.lds,-T %.lds,$^)
o/$(MODE)/ape/loader.o: ape/loader.c ape/ape.h
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=33 -g $(APE_LOADER_FLAGS)
o/$(MODE)/ape/start.o: ape/start.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/ape/launch.o: ape/launch.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/ape/systemcall.o: ape/systemcall.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
.PHONY: o/$(MODE)/ape
o/$(MODE)/ape: o/$(MODE)/ape/ape.elf
else
APE = o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape.lds
APELINK = \
$(COMPILE) \
-ALINK.ape \
$(LINK) \
$(LINKARGS) \
$(OUTPUT_OPTION) && \
$(COMPILE) \
-AFIXUP.ape \
-wT$@ \
$(FIXUPOBJ) \
$@
APE_NO_MODIFY_SELF = \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/ape/ape-no-modify-self.o
APE_COPY_SELF = \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/ape/ape-copy-self.o
APE_LOADER_FLAGS = \
-DNDEBUG \
-iquote. \
-Wall \
-Wextra \
-Werror \
-pedantic-errors \
-fpie \
-Os \
-ffreestanding \
-mgeneral-regs-only \
-fno-stack-protector \
-fno-ident \
-fno-gnu-unique \
-c \
$(OUTPUT_OPTION) \
$<
APE_SRCS_C = ape/loader.c
APE_SRCS_S = $(filter %.S,$(APE_FILES))
APE_SRCS = $(APE_SRCS_C) $(APE_SRCS_S)
APE_OBJS = $(APE_SRCS_S:%.S=o/$(MODE)/%.o)
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
o/ape/idata.inc: \
ape/idata.internal.h \
ape/relocations.h
o/$(MODE)/ape/ape-no-modify-self.o: \
ape/ape.S \
ape/ape.h \
ape/macros.internal.h \
ape/relocations.h \
ape/ape.internal.h \
libc/dce.h \
libc/elf/def.h \
libc/thread/tls.h \
libc/macho.h \
libc/macros.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h \
libc/nt/pedef.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/runtime/pc.internal.h \
libc/sysv/consts/prot.h \
o/$(MODE)/ape/ape.elf
@$(COMPILE) \
-AOBJECTIFY.S \
$(OBJECTIFY.S) \
$(OUTPUT_OPTION) \
-DAPE_NO_MODIFY_SELF \
-DAPE_LOADER='"o/$(MODE)/ape/ape.elf"' $<
o/$(MODE)/ape/ape-copy-self.o: \
ape/ape.S \
ape/ape.h \
ape/macros.internal.h \
ape/relocations.h \
ape/ape.internal.h \
libc/dce.h \
libc/elf/def.h \
libc/thread/tls.h \
libc/macho.h \
libc/macros.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h \
libc/nt/pedef.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/runtime/pc.internal.h \
libc/sysv/consts/prot.h
@$(COMPILE) \
-AOBJECTIFY.S \
$(OBJECTIFY.S) \
$(OUTPUT_OPTION) \
-DAPE_NO_MODIFY_SELF $<
o/$(MODE)/ape/loader.o: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=121 -g $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-gcc.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=121 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-clang.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=121 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-xnu.o: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=8 -g $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-xnu-gcc.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=8 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=8 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
@$(COMPILE) -AOBJBINCOPY -w $(OBJBINCOPY) -f -o $@ $<
o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.elf.dbg
@$(COMPILE) -AOBJBINCOPY -w $(OBJBINCOPY) -fm -o $@ $<
APE_LOADER_LDFLAGS = \
-static \
-nostdlib \
--no-dynamic-linker \
-z separate-code \
-z common-page-size=0x1000 \
-z max-page-size=0x10000
o/$(MODE)/ape/ape.elf.dbg: \
o/$(MODE)/ape/loader-macho.o \
o/$(MODE)/ape/start.o \
o/$(MODE)/ape/loader.o \
o/$(MODE)/ape/launch.o \
o/$(MODE)/ape/systemcall.o \
ape/loader.lds
@$(COMPILE) -ALINK.elf $(LD) $(APE_LOADER_LDFLAGS) -o $@ $(patsubst %.lds,-T %.lds,$^)
.PHONY: o/$(MODE)/ape
o/$(MODE)/ape: $(APE_CHECKS) \
o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/ape/ape.elf \
o/$(MODE)/ape/ape.macho \
endif
# these assembly files are safe to build on aarch64
o/$(MODE)/ape/ape.o: \
ape/ape.S \
ape/ape.h \
libc/dce.h \
libc/elf/def.h \
ape/relocations.h \
libc/thread/tls.h \
ape/ape.internal.h \
ape/macros.internal.h \
libc/macho.h \
libc/macros.h \
libc/sysv/consts/prot.h \
libc/nt/pedef.internal.h \
libc/runtime/pc.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/nexgen32e/uart.internal.h \
libc/calls/metalfile.internal.h
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) -c $<
o/$(MODE)/ape/ape.lds: \
ape/ape.lds \
ape/macros.internal.h \
ape/relocations.h \
ape/ape.internal.h \
libc/thread/tls.h \
libc/calls/struct/timespec.h \
libc/thread/thread.h \
libc/dce.h \
libc/elf/def.h \
libc/elf/pf2prot.internal.h \
libc/macros.h \
libc/nt/pedef.internal.h \
libc/str/str.h \
libc/zip.h

View file

@ -1,301 +0,0 @@
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
│ vi: set et sts=2 sw=2 fenc=utf-8 :vi │
╚─────────────────────────────────────────────────────────────────────────────*/
#include "libc/sysv/consts/prot.h"
#include "libc/thread/tls.h"
ENTRY(_start)
OUTPUT_ARCH(aarch64)
OUTPUT_FORMAT("elf64-littleaarch64",
"elf64-bigaarch64",
"elf64-littleaarch64")
SECTIONS {
. = SEGMENT_START("text-segment", 0x000800000000);
__executable_start = .;
. += SIZEOF_HEADERS;
.interp : { *(.interp) }
.note.gnu.build-id : { *(.note.gnu.build-id) }
.hash : { *(.hash) }
.gnu.hash : { *(.gnu.hash) }
.dynsym : { *(.dynsym) }
.dynstr : { *(.dynstr) }
.gnu.version : { *(.gnu.version) }
.gnu.version_d : { *(.gnu.version_d) }
.gnu.version_r : { *(.gnu.version_r) }
.rela.init : { *(.rela.init) }
.rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) }
.rela.fini : { *(.rela.fini) }
.rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) }
.rela.data.rel.ro : { *(.rela.data.rel.ro .rela.data.rel.ro.* .rela.gnu.linkonce.d.rel.ro.*) }
.rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) }
.rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) }
.rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) }
.rela.ctors : { *(.rela.ctors) }
.rela.dtors : { *(.rela.dtors) }
.rela.got : { *(.rela.got) }
.rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) }
.rela.ifunc : { *(.rela.ifunc) }
.rela.plt : {
*(.rela.plt)
__rela_iplt_start = .;
*(.rela.iplt)
__rela_iplt_end = .;
}
.init : {
*(.start)
KEEP(*(.initprologue))
KEEP(*(SORT_NONE(.init)))
KEEP(*(.initepilogue))
} =0x1f2003d5
.plt : ALIGN(16) {
*(.plt)
*(.iplt)
}
.text : {
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
*(.text.antiquity .text.antiquity.*)
*(.text.exit .text.exit.*)
*(.text.startup .text.startup.*)
*(.text.hot .text.hot.*)
*(.text.modernity .text.modernity.*)
*(.text .stub .text.* .gnu.linkonce.t.*)
*(.gnu.warning)
} =0x1f2003d5
.fini : {
KEEP(*(SORT_NONE(.fini)))
} =0x1f2003d5
. += CONSTANT(MAXPAGESIZE);
.privileged : {
__privileged_start = ABSOLUTE(.) & -CONSTANT(MAXPAGESIZE);
*(.privileged*)
} =0x1f2003d6
.rodata : {
KEEP(*(.rodata.pytab.0));
KEEP(*(.rodata.pytab.1));
KEEP(*(.rodata.pytab.2));
KEEP(*(SORT_BY_NAME(.sort.rodata.*)))
*(.rodata .rodata.* .gnu.linkonce.r.*)
*(.ubsan.types)
*(.ubsan.data)
}
.notice : {
__notices = .;
KEEP(*(.notice))
BYTE(0);
BYTE(10);
BYTE(10);
}
.eh_frame_hdr : {
*(.eh_frame_hdr)
*(.eh_frame_entry .eh_frame_entry.*)
}
__eh_frame_hdr_start = SIZEOF(.eh_frame_hdr) > 0 ? ADDR(.eh_frame_hdr) : 0;
__eh_frame_hdr_end = SIZEOF(.eh_frame_hdr) > 0 ? . : 0;
.gcc_except_table : ONLY_IF_RO {
*(.gcc_except_table .gcc_except_table.*)
}
.gnu_extab : ONLY_IF_RO {
*(.gnu_extab*)
}
.exception_ranges : ONLY_IF_RO {
*(.exception_ranges*)
}
__etext = .;
_etext = .;
PROVIDE(etext = .);
. += CONSTANT(MAXPAGESIZE);
. = DATA_SEGMENT_ALIGN(CONSTANT(MAXPAGESIZE), CONSTANT(COMMONPAGESIZE));
.eh_frame : {
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
}
.gnu_extab : ONLY_IF_RW {
*(.gnu_extab)
}
.gcc_except_table : ONLY_IF_RW {
*(.gcc_except_table .gcc_except_table.*)
}
.exception_ranges : ONLY_IF_RW {
*(.exception_ranges*)
}
.tdata : {
_tdata_start = .;
__tdata_start = .;
*(.tdata .tdata.* .gnu.linkonce.td.*)
_tdata_end = .;
}
.tbss : {
_tbss_start = .;
*(.tbss .tbss.* .gnu.linkonce.tb.*)
*(.tcommon)
_tbss_end = .;
}
.init_array : {
__init_array_start = .;
KEEP(*(.preinit_array))
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)
SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP(*(.init_array))
KEEP(*(.ctors))
__init_array_end = .;
}
.fini_array : {
__fini_array_start = .;
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP(*(.fini_array EXCLUDE_FILE(*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
__fini_array_end = .;
}
.data.rel.ro : {
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
*(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*)
*(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*)
}
.dynamic : {
*(.dynamic)
}
.got : {
*(.got)
*(.igot)
}
. = DATA_SEGMENT_RELRO_END(24, .);
.got.plt : {
*(.got.plt)
*(.igot.plt)
}
.data : {
__data_start = .;
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
*(.data .data.* .gnu.linkonce.d.*)
KEEP(*(SORT_BY_NAME(.sort.data.*)))
SORT(CONSTRUCTORS)
}
_edata = .;
PROVIDE(edata = .);
. = .;
__bss_start = .;
__bss_start__ = .;
.bss : {
*(.dynbss)
*(.bss .bss.* .gnu.linkonce.b.*)
KEEP(*(SORT_BY_NAME(.piro.bss.sort.*)))
*(COMMON)
. = ALIGN(CONSTANT(COMMONPAGESIZE));
}
_bss_end__ = .;
__bss_end__ = .;
. = ALIGN(64 / 8);
. = SEGMENT_START("ldata-segment", .);
. = ALIGN(64 / 8);
__end__ = .;
_end = .;
PROVIDE(end = .);
. = DATA_SEGMENT_END(.);
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.ARM.attributes 0 : { KEEP(*(.ARM.attributes)) KEEP(*(.gnu.attributes)) }
.note.gnu.arm.ident 0 : { KEEP(*(.note.gnu.arm.ident)) }
.zip 0 : {
KEEP(*(.zip.file))
__zip_cdir_start = .;
KEEP(*(.zip.cdir))
__zip_cdir_size = . - __zip_cdir_start;
KEEP(*(.zip.eocd))
}
/DISCARD/ : {
*(__patchable_function_entries)
*(.GCC.command.line)
*(.note.GNU-stack)
*(.gnu_debuglink)
*(.text.windows)
*(.gnu.lto_*)
*(.eh_frame)
*(.idata.*)
*(.yoink)
*(.head)
}
}
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 8 * 1024 * 1024;
ape_stack_prot = PROT_READ | PROT_WRITE;
_tls_size = _tbss_end - _tdata_start;
_tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));

File diff suppressed because it is too large Load diff

1269
ape/ape.S

File diff suppressed because it is too large Load diff

View file

@ -1,13 +0,0 @@
#ifndef COSMOPOLITAN_APE_APE_H_
#define COSMOPOLITAN_APE_APE_H_
#define APE_VERSION_MAJOR 1
#define APE_VERSION_MINOR 10
#define APE_VERSION_STR APE_VERSION_STR_(APE_VERSION_MAJOR, APE_VERSION_MINOR)
#define APE_VERSION_NOTE APE_VERSION_NOTE_(APE_VERSION_MAJOR, APE_VERSION_MINOR)
#define APE_VERSION_STR__(x, y) #x "." #y
#define APE_VERSION_STR_(x, y) APE_VERSION_STR__(x, y)
#define APE_VERSION_NOTE_(x, y) (100000000 * (x) + 1000000 * (y))
#endif /* COSMOPOLITAN_APE_APE_H_ */

View file

@ -1,9 +0,0 @@
#ifndef COSMOPOLITAN_APE_APE_INTERNAL_H_
#define COSMOPOLITAN_APE_APE_INTERNAL_H_
#include "libc/dce.h"
#if SupportsWindows() || SupportsMetal() || SupportsXnu()
#define APE_IS_SHELL_SCRIPT
#endif
#endif /* COSMOPOLITAN_APE_APE_INTERNAL_H_ */

View file

@ -1,5 +1,5 @@
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
vi: set et sts=2 sw=2 fenc=utf-8 :vi
vi: set et sts=2 tw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2020 Justine Alexandra Roberts Tunney │
│ │
@ -180,40 +180,16 @@
#include "libc/elf/def.h"
#include "libc/elf/pf2prot.internal.h"
#include "libc/nt/pedef.internal.h"
#include "libc/thread/tls.h"
#include "ape/ape.internal.h"
/* uncomment if .com.dbg won't execute on your kernel (will break .com file) */
/* #define APE_FIX_COM_DBG */
#ifdef __x86__
#define CODE_GRANULE 1
#else
#define CODE_GRANULE 4
#endif
#ifdef APE_FIX_COM_DBG
#define SKEW SIZEOF_HEADERS
#else
#define SKEW 0
#endif
#ifndef IMAGE_BASE_VIRTUAL
#define IMAGE_BASE_VIRTUAL 0x400000
#endif
#if IMAGE_BASE_VIRTUAL > 0xffffffff
#error "please use 32-bit addresses for image data"
#endif
#include "libc/zip.h"
ENTRY(_start)
PHDRS {
Head PT_LOAD FLAGS(PF_X|PF_R);
Cod PT_LOAD FLAGS(PF_X|PF_R);
Rom PT_LOAD FLAGS(PF_R);
Tls PT_TLS FLAGS(PF_W|PF_R);
Rom PT_LOAD FLAGS(PF_X|PF_R);
Ram PT_LOAD FLAGS(PF_W|PF_R);
Tls PT_TLS FLAGS(PF_W|PF_R);
Bss PT_LOAD FLAGS(PF_W|PF_R);
stack PT_GNU_STACK FLAGS(PF_W|PF_R);
}
@ -224,44 +200,42 @@ SECTIONS {
/*BEGIN: linux addressability guarantee */
/*BEGIN: bsd addressability guarantee */
.head SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) + SKEW : AT(IMAGE_BASE_REAL) {
__executable_start = .;
.head SEGMENT_START("text-segment", IMAGE_BASE_VIRTUAL) : AT(IMAGE_BASE_REAL) {
HIDDEN(_base = .);
/* Real Mode */
KEEP(*(.head))
KEEP(*(.apesh))
KEEP(*(.head2))
KEEP(*(.text.head))
/* Executable & Linkable Format */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
ape_phdrs = .;
. = ALIGN(__SIZEOF_POINTER__);
HIDDEN(ape_phdrs = .);
KEEP(*(.elf.phdrs))
ape_phdrs_end = .;
HIDDEN(ape_phdrs_end = .);
/* OpenBSD */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
ape_note = .;
. = ALIGN(__SIZEOF_POINTER__);
HIDDEN(ape_note = .);
KEEP(*(.note.openbsd.ident))
KEEP(*(.note.netbsd.ident))
ape_note_end = .;
HIDDEN(ape_note_end = .);
/* Portable Executable */
KEEP(*(.pe.header))
ape_pe_sections = .;
HIDDEN(ape_pe_sections = .);
KEEP(*(.pe.sections))
ape_pe_sections_end = .;
HIDDEN(ape_pe_sections_end = .);
/* Mach-O */
KEEP(*(.macho))
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
ape_macho_end = .;
/* APE loader */
KEEP(*(.ape.loader))
. = ALIGN(. != 0 ? CODE_GRANULE : 0);
. = ALIGN(__SIZEOF_POINTER__);
HIDDEN(ape_macho_end = .);
KEEP(*(.ape.pad.head))
. = ALIGN(. != 0 ? (SupportsWindows() || SupportsMetal() ? CONSTANT(COMMONPAGESIZE) : 16) : 0);
_ehead = .;
. = ALIGN(SupportsWindows() || SupportsMetal() ? PAGESIZE : 16);
HIDDEN(_ehead = .);
} :Head
/*BEGIN: nt addressability guarantee */
@ -271,10 +245,12 @@ SECTIONS {
/* Code that needs to be addressable in Real Mode */
*(.text.real)
KEEP(*(SORT_BY_NAME(.sort.text.real.*)))
_ereal = .;
/* Code we want earlier in the binary w/o modifications */
KEEP(*(.ape.loader))
HIDDEN(_ereal = .);
/*END: realmode addressability guarantee */
/*BEGIN: morphable code */
. += CODE_GRANULE;
. += 1;
/* Normal Code */
*(.start)
@ -282,9 +258,12 @@ SECTIONS {
KEEP(*(SORT_BY_NAME(.init.*)))
KEEP(*(.init))
KEEP(*(.initepilogue))
KEEP(*(.pltprologue))
*(.plt)
KEEP(*(.pltepilogue))
KEEP(*(.pltgotprologue))
*(.plt.got)
*(.iplt)
KEEP(*(.pltgotepilogue))
*(.text.startup .text.startup.*)
*(.text.exit .text.exit.*)
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
@ -307,20 +286,17 @@ SECTIONS {
/* Privileged code invulnerable to magic */
KEEP(*(.ape.pad.privileged));
. = ALIGN(__privileged_end > __privileged_start ? CONSTANT(COMMONPAGESIZE) : 0);
. += . > 0 ? 1 : 0;
/*END: morphable code */
__privileged_start = .;
*(.privileged .privileged.*)
__privileged_end = .;
KEEP(*(.ape.pad.text))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: Read Only Data (only needed for initialization) */
} :Cod
HIDDEN(__privileged_start = .);
. += . > 0 ? 1 : 0;
*(.privileged)
HIDDEN(__privileged_end = .);
. += . > 0 ? 1 : 0;
/*BEGIN: Read Only Data */
.rodata ALIGN(CONSTANT(COMMONPAGESIZE)) : {
KEEP(*(.ape.pad.rodata));
KEEP(*(.rodata.pytab.0));
KEEP(*(.rodata.pytab.1));
KEEP(*(.rodata.pytab.2));
@ -329,139 +305,116 @@ SECTIONS {
*(.ubsan.types)
*(.ubsan.data)
__eh_frame_hdr_start_actual = .;
*(.eh_frame_hdr)
__eh_frame_hdr_end_actual = .;
/* Unit Test & Fixture Registry */
/*BEGIN: Read only data that needn't be mapped after initialization */
/* Legal Notices */
__notices = .;
KEEP(*(.notice))
BYTE(0);
BYTE(10);
BYTE(10);
#if !defined(IM_FEELING_NAUGHTY) || defined(EMBED_NOTICES)
KEEP(*(.commentprologue))
KEEP(*(.comment))
KEEP(*(.commentepilogue))
#endif
/*BEGIN: read-only data that's only needed for initialization */
#if SupportsWindows()
/* Windows DLL Import Directory */
KEEP(*(.idata.ro));
KEEP(*(SORT_BY_NAME(.idata.ro.*)))
#endif
. = ALIGN(__SIZEOF_POINTER__);
PROVIDE_HIDDEN(__init_array_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)
SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP(*(.ctors))
KEEP(*(.init_array))
KEEP(*(.preinit_array))
PROVIDE_HIDDEN(__init_array_end = .);
. = ALIGN(__SIZEOF_POINTER__);
PROVIDE_HIDDEN(__fini_array_start = .);
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*)
SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP(*(.dtors))
PROVIDE_HIDDEN(__fini_array_end = .);
/* Encoded Data Structures w/ Linear Initialization Order */
KEEP(*(.initroprologue))
KEEP(*(SORT_BY_NAME(.initro.*)))
KEEP(*(.initroepilogue))
KEEP(*(SORT_BY_NAME(.sort.rodata.*)))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0); /* don't delete this line :o */
/*END: read-only data that's only needed for initialization */
KEEP(*(.ape.pad.text))
. = ALIGN(PAGESIZE);
HIDDEN(_etext = .);
PROVIDE_HIDDEN(etext = .);
/*END: Read Only Data (only needed for initialization) */
/*END: Read Only Data */
} :Rom
/* initialization image for thread-local storage, this is copied */
/* out to actual TLS areas at runtime, so just make it read-only */
.data ALIGN(PAGESIZE) : {
/*BEGIN: Read/Write Data */
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)))
/*BEGIN: NT FORK COPYING */
KEEP(*(.dataprologue))
*(.data .data.*)
KEEP(*(SORT_BY_NAME(.sort.data.*)))
. += . > 0 ? 1 : 0;
KEEP(*(.gotprologue))
*(.got)
KEEP(*(.gotepilogue))
KEEP(*(.gotpltprologue))
*(.got.plt)
KEEP(*(.gotpltepilogue))
/*BEGIN: Post-Initialization Read-Only */
. = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
PROVIDE_HIDDEN(__relo_end = .);
. = ALIGN(__SIZEOF_POINTER__);
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
KEEP(*(.piro.pad.data))
KEEP(*(.dataepilogue))
/*END: NT FORK COPYING */
HIDDEN(_edata = .);
PROVIDE_HIDDEN(edata = .);
KEEP(*(SORT_BY_NAME(.zip.*)))
HIDDEN(_ezip = .);
} :Ram
.tdata . : {
_tdata_start = .;
*(SORT_BY_ALIGNMENT(.tdata))
*(SORT_BY_ALIGNMENT(.tdata.*))
. = ALIGN(16);
_tdata_end = .;
KEEP(*(.ape.pad.rodata))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
_etext = .;
PROVIDE(etext = .);
} :Tls :Rom
/*END: Read Only Data */
. = ALIGN(PAGESIZE);
} :Tls
. = ALIGN(PAGESIZE);
. = ALIGN(CONSTANT(COMMONPAGESIZE));
/*END: file content that's loaded by o/s */
/*BEGIN: bss memory void */
/* this only tells the linker about the layout of uninitialized */
/* TLS data, and does not advance the linker's location counter */
.tbss : {
.tbss . : {
_tbss_start = .;
*(SORT_BY_ALIGNMENT(.tbss))
*(SORT_BY_ALIGNMENT(.tbss.*))
KEEP(*(.fstls))
. = ALIGN(16);
/* the %fs register is based on this location */
_tbss_end = .;
} :Tls
.eh_frame : {
__eh_frame_start = .;
KEEP(*(.eh_frame))
*(.eh_frame.*)
__eh_frame_end = .;
} :Ram
.data . : {
/*BEGIN: Read/Write Data */
#if SupportsWindows()
KEEP(*(SORT_BY_NAME(.piro.data.sort.iat.*)))
#endif
/*BEGIN: NT FORK COPYING */
KEEP(*(.dataprologue))
*(.data .data.*)
*(.gnu_extab)
*(.gcc_except_table .gcc_except_table.*)
*(.exception_ranges*)
*(.PyRuntime) /* for python */
*(.subrs) /* for emacs */
KEEP(*(SORT_BY_NAME(.sort.data.*)))
. += . > 0 ? CODE_GRANULE : 0;
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
__got_start = .;
*(.got)
__got_end = .;
*(.got.plt)
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
__init_array_start = .;
KEEP(*(.preinit_array))
KEEP(*(SORT_BY_INIT_PRIORITY(.init_array.*)
SORT_BY_INIT_PRIORITY(.ctors.*)))
KEEP(*(.init_array))
KEEP(*(.ctors))
__init_array_end = .;
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
__fini_array_start = .;
KEEP(*(SORT_BY_INIT_PRIORITY(.fini_array.*)
SORT_BY_INIT_PRIORITY(.dtors.*)))
KEEP(*(.fini_array))
KEEP(*(.dtors))
__fini_array_end = .;
/*BEGIN: Post-Initialization Read-Only */
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
KEEP(*(SORT_BY_NAME(.piro.relo.sort.*)))
. = ALIGN(. != 0 ? __SIZEOF_POINTER__ : 0);
KEEP(*(SORT_BY_NAME(.piro.data.sort.*)))
KEEP(*(.piro.pad.data))
*(.igot.plt)
KEEP(*(.dataepilogue))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: NT FORK COPYING */
_edata = .;
PROVIDE(edata = .);
_ezip = .; /* <-- very deprecated */
} :Ram
. = ALIGN(CONSTANT(COMMONPAGESIZE));
/*END: file content that's loaded by o/s */
/*END: file content */
/*BEGIN: bss memory that's addressable */
.bss : {
.bss ALIGN(64) : {
/*BEGIN: NT FORK COPYING */
KEEP(*(.bssprologue))
KEEP(*(SORT_BY_NAME(.piro.bss.init.*)))
*(.piro.bss)
KEEP(*(SORT_BY_NAME(.piro.bss.sort.*)))
__piro_end = .;
. += . > 0 ? CODE_GRANULE : 0;
HIDDEN(__piro_end = .);
. += . > 0 ? 1 : 0;
/*END: Post-Initialization Read-Only */
/* Statically Allocated Empty Space */
@ -472,15 +425,11 @@ SECTIONS {
KEEP(*(SORT_BY_NAME(.sort.bss.*)))
KEEP(*(.bssepilogue))
. = ALIGN(. != 0 ? CONSTANT(COMMONPAGESIZE) : 0);
/*END: NT FORK COPYING */
} :Ram
. = ALIGN(CONSTANT(COMMONPAGESIZE));
_end = .;
PROVIDE(end = .);
. = ALIGN(FRAMESIZE); /* for brk()/sbrk() allocation */
HIDDEN(_end = .);
PROVIDE_HIDDEN(end = .);
} :Bss
/*END: nt addressability guarantee */
/*END: bsd addressability guarantee */
@ -508,7 +457,6 @@ SECTIONS {
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
.debug_weaknames 0 : { *(.debug_weaknames) }
@ -517,43 +465,19 @@ SECTIONS {
.debug_varnames 0 : { *(.debug_varnames) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_names 0 : { *(.debug_names) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_str_offsets 0 : { *(.debug_str_offsets) }
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
.GCC.command.line 0 : { *(.GCC.command.line) }
.zip 0 : {
KEEP(*(.zip.file))
__zip_cdir_start = .;
KEEP(*(.zip.cdir))
__zip_cdir_size = . - __zip_cdir_start;
KEEP(*(.zip.eocd))
}
/DISCARD/ : {
#if !SupportsWindows()
*(.idata.ro);
*(.idata.ro.*)
*(.piro.data.sort.iat.*)
#endif
*(__patchable_function_entries)
*(.note.gnu.property)
*(__mcount_loc)
*(.rela.dyn)
*(.discard)
*(.yoink)
*(.*)
}
}
ape_pe_filealignment = 512;
ape_pe_sectionalignment = 4096;
ape_pe_sizeofheaders = SIZEOF(.head);
ape_pe_sizeofimage = ROUNDUP(_end - __executable_start, ape_pe_sectionalignment);
PFSTUB8(ape_elf_entry, _start);
PFSTUB8(ape_elf_phoff, RVA(ape_phdrs));
PFSTUB8(ape_elf_shoff, 0);
@ -561,61 +485,68 @@ PFSTUB4(ape_elf_phnum, (ape_phdrs_end - ape_phdrs) / 56);
PFSTUB4(ape_elf_shnum, 0);
PFSTUB4(ape_elf_shstrndx, 0);
_tls_size = _tbss_end - _tdata_start;
_tdata_size = _tdata_end - _tdata_start;
_tbss_size = _tbss_end - _tbss_start;
_tbss_offset = _tbss_start - _tdata_start;
_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start);
_tdata_align = ALIGNOF(.tdata);
_tbss_align = ALIGNOF(.tbss);
_tls_align = MAX(TLS_ALIGNMENT, MAX(ALIGNOF(.tdata), ALIGNOF(.tbss)));
HIDDEN(_tdata_size = _tdata_end - _tdata_start);
HIDDEN(_tls_size = _tbss_end - _tdata_start);
HIDDEN(_tls_content = (_tdata_end - _tdata_start) + (_tbss_end - _tbss_start));
ape_cod_offset = 0;
ape_cod_vaddr = ADDR(.head);
ape_cod_paddr = LOADADDR(.head);
ape_cod_filesz = ADDR(.rodata) - ADDR(.head);
ape_cod_memsz = ape_cod_filesz;
ape_cod_align = CONSTANT(COMMONPAGESIZE);
ape_cod_rva = RVA(ape_cod_vaddr);
HIDDEN(__privileged_addr = ROUNDDOWN(__privileged_start, PAGESIZE));
HIDDEN(__privileged_size = (ROUNDUP(__privileged_end, PAGESIZE) -
ROUNDDOWN(__privileged_start, PAGESIZE)));
ape_rom_vaddr = ADDR(.rodata);
ape_rom_offset = ape_rom_vaddr - __executable_start;
ape_rom_paddr = LOADADDR(.rodata);
ape_rom_filesz = ADDR(.tbss) - ADDR(.rodata);
ape_rom_memsz = ape_rom_filesz;
ape_rom_align = CONSTANT(COMMONPAGESIZE);
ape_rom_rva = RVA(ape_rom_vaddr);
HIDDEN(ape_rom_offset = 0);
HIDDEN(ape_rom_vaddr = ADDR(.head));
HIDDEN(ape_rom_paddr = LOADADDR(.head));
HIDDEN(ape_rom_filesz = LOADADDR(.data) - ape_rom_paddr);
HIDDEN(ape_rom_memsz = ADDR(.data) - ADDR(.head));
HIDDEN(ape_rom_align = PAGESIZE);
HIDDEN(ape_rom_rva = RVA(ape_rom_vaddr));
ape_ram_vaddr = ADDR(.eh_frame);
ape_ram_offset = ape_ram_vaddr - __executable_start;
ape_ram_paddr = LOADADDR(.eh_frame);
ape_ram_filesz = ADDR(.bss) - ADDR(.eh_frame);
ape_ram_memsz = _end - ADDR(.eh_frame);
ape_ram_align = CONSTANT(COMMONPAGESIZE);
ape_ram_rva = RVA(ape_ram_vaddr);
HIDDEN(ape_ram_offset = ape_rom_offset + ape_rom_filesz);
HIDDEN(ape_ram_vaddr = ADDR(.data));
HIDDEN(ape_ram_paddr = LOADADDR(.data));
HIDDEN(ape_ram_filesz = SIZEOF(.data) + SIZEOF(.tdata));
HIDDEN(ape_ram_memsz = ADDR(.bss) + SIZEOF(.bss) - ape_ram_vaddr);
HIDDEN(ape_ram_align = PAGESIZE);
HIDDEN(ape_ram_rva = RVA(ape_ram_vaddr));
ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W;
ape_stack_prot = _PF2PROT(ape_stack_pf);
ape_stack_offset = 0;
ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000;
ape_stack_paddr = ape_ram_paddr + ape_ram_filesz;
ape_stack_filesz = 0;
ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : 4 * 1024 * 1024;
HIDDEN(ape_stack_pf = DEFINED(ape_stack_pf) ? ape_stack_pf : PF_R | PF_W);
HIDDEN(ape_stack_prot = _PF2PROT(ape_stack_pf));
HIDDEN(ape_stack_offset = ape_ram_offset + ape_ram_filesz);
HIDDEN(ape_stack_vaddr = DEFINED(ape_stack_vaddr) ? ape_stack_vaddr : 0x700000000000);
HIDDEN(ape_stack_paddr = ape_ram_paddr + ape_ram_filesz);
HIDDEN(ape_stack_filesz = 0);
HIDDEN(ape_stack_memsz = DEFINED(ape_stack_memsz) ? ape_stack_memsz : STACKSIZE);
HIDDEN(ape_stack_align = 16);
ape_note_offset = ape_cod_offset + (ape_note - ape_cod_vaddr);
ape_note_filesz = ape_note_end - ape_note;
ape_note_memsz = ape_note_filesz;
HIDDEN(ape_note_offset = ape_rom_offset + (ape_note - ape_rom_vaddr));
HIDDEN(ape_note_vaddr = ape_note);
HIDDEN(ape_note_paddr = ape_rom_paddr + ape_note_offset);
HIDDEN(ape_note_filesz = ape_note_end - ape_note);
HIDDEN(ape_note_memsz = ape_note_filesz);
HIDDEN(ape_note_align = __SIZEOF_POINTER__);
ape_text_vaddr = ADDR(.text);
ape_text_offset = ape_text_vaddr - __executable_start;
ape_text_paddr = LOADADDR(.text);
ape_text_filesz = ADDR(.rodata) - ADDR(.text);
ape_text_memsz = ape_text_filesz;
ape_text_align = CONSTANT(COMMONPAGESIZE);
ape_text_rva = RVA(ape_text_vaddr);
HIDDEN(ape_text_offset = ape_rom_offset + LOADADDR(.text) - ape_rom_paddr);
HIDDEN(ape_text_paddr = LOADADDR(.text));
HIDDEN(ape_text_vaddr = ADDR(.text));
HIDDEN(ape_text_filesz = SIZEOF(.text));
HIDDEN(ape_text_memsz = SIZEOF(.text));
HIDDEN(ape_text_align = PAGESIZE);
HIDDEN(ape_text_rva = RVA(ape_text_vaddr));
__eh_frame_hdr_start = __eh_frame_hdr_end_actual > __eh_frame_hdr_start_actual ? __eh_frame_hdr_start_actual : 0;
__eh_frame_hdr_end = __eh_frame_hdr_end_actual > __eh_frame_hdr_start_actual ? __eh_frame_hdr_end_actual : 0;
HIDDEN(ape_data_offset = ape_ram_offset + LOADADDR(.data) - ape_ram_paddr);
HIDDEN(ape_data_paddr = LOADADDR(.data));
HIDDEN(ape_data_vaddr = ADDR(.data));
HIDDEN(ape_data_filesz = SIZEOF(.data) + SIZEOF(.tdata));
HIDDEN(ape_data_memsz = SIZEOF(.data) + SIZEOF(.tdata));
HIDDEN(ape_data_align = PAGESIZE);
HIDDEN(ape_data_rva = RVA(ape_data_vaddr));
HIDDEN(ape_bss_offset = ape_ram_offset + LOADADDR(.bss) - ape_ram_paddr);
HIDDEN(ape_bss_paddr = LOADADDR(.bss));
HIDDEN(ape_bss_vaddr = ADDR(.bss));
HIDDEN(ape_bss_filesz = 0);
HIDDEN(ape_bss_memsz = SIZEOF(.bss));
HIDDEN(ape_bss_align = PAGESIZE);
/* we roundup here because xnu wants the file load segments page-aligned */
/* but we don't want to add the nop padding to the ape program, so we'll */
@ -623,19 +554,26 @@ __eh_frame_hdr_end = __eh_frame_hdr_end_actual > __eh_frame_hdr_start_actual ? _
SHSTUB2(ape_loader_dd_skip, DEFINED(ape_loader) ? RVA(ape_loader) / 64 : 0);
SHSTUB2(ape_loader_dd_count,
DEFINED(ape_loader_end)
? ROUNDUP(ape_loader_end - ape_loader, CONSTANT(COMMONPAGESIZE)) / 64
? ROUNDUP(ape_loader_end - ape_loader, PAGESIZE) / 64
: 0);
#if SupportsMetal()
v_ape_realsectors = MIN(0x70000 - IMAGE_BASE_REAL, ROUNDUP(RVA(_ezip), 512)) / 512;
v_ape_realbytes = v_ape_realsectors * 512;
v_ape_realdwords = v_ape_realsectors * (512 / 4);
v_ape_allsectors = ROUNDUP(RVA(_ezip), 512) / 512;
v_ape_allbytes = v_ape_allsectors * 512;
v_ape_highsectors = MIN(0xffff, v_ape_allsectors - v_ape_realsectors);
TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
HIDDEN(v_ape_realsectors =
MIN(0x70000 - IMAGE_BASE_REAL,
ROUNDUP(RVA(_edata), 4096)) / 512);
HIDDEN(v_ape_realpages = v_ape_realsectors / (4096 / 512));
HIDDEN(v_ape_highsectors =
(ROUNDUP(RVA(_edata), 512) / 512) - v_ape_realsectors);
#endif
/* ZIP End of Central Directory header */
#define ZIPCONST(NAME, VAL) HIDDEN(NAME = DEFINED(__zip_start) ? VAL : 0);
ZIPCONST(v_zip_cdoffset, __zip_start - IMAGE_BASE_VIRTUAL);
ZIPCONST(v_zip_cdirsize, __zip_end - __zip_start);
ASSERT(v_zip_cdirsize % kZipCdirHdrLinkableSize == 0, "bad zip cdir");
ZIPCONST(v_zip_records, v_zip_cdirsize / kZipCdirHdrLinkableSize);
ZIPCONST(v_zip_commentsize, _ezip - __zip_end - kZipCdirHdrMinSize);
#if SupportsXnu()
/* Generates deterministic ID. */
#define PHI 0x9e3779b9925d4c17
@ -654,8 +592,19 @@ TSSDESCSTUB2(_tss, _tss, _tss_end ? _tss_end - _tss - 1 : 0);
KMH(ape_uuid1, X); \
XORSHIFT(ape_uuid2, X); \
KMH(ape_uuid2, X)
ape_uuid1 = 88172645463325252;
ape_uuid2 = 88172645463325252;
HIDDEN(ape_uuid1 = 88172645463325252);
HIDDEN(ape_uuid2 = 88172645463325252);
CHURN(ape_bss_align);
CHURN(ape_bss_filesz);
CHURN(ape_bss_memsz);
CHURN(ape_bss_offset);
CHURN(ape_bss_paddr);
CHURN(ape_data_filesz);
CHURN(ape_data_memsz);
CHURN(ape_data_offset);
CHURN(ape_data_paddr);
CHURN(ape_data_rva);
CHURN(ape_data_vaddr);
CHURN(ape_elf_entry);
CHURN(ape_elf_phnum);
CHURN(ape_elf_phoff);
@ -664,10 +613,13 @@ CHURN(ape_elf_shoff);
CHURN(ape_elf_shstrndx);
CHURN(ape_macho_end);
CHURN(ape_note);
CHURN(ape_note_align);
CHURN(ape_note_end);
CHURN(ape_note_filesz);
CHURN(ape_note_memsz);
CHURN(ape_note_offset);
CHURN(ape_note_paddr);
CHURN(ape_note_vaddr);
CHURN(ape_ram_align);
CHURN(ape_ram_filesz);
CHURN(ape_ram_memsz);
@ -681,14 +633,7 @@ CHURN(ape_rom_memsz);
CHURN(ape_rom_offset);
CHURN(ape_rom_paddr);
CHURN(ape_rom_rva);
CHURN(ape_cod_vaddr);
CHURN(ape_cod_align);
CHURN(ape_cod_filesz);
CHURN(ape_cod_memsz);
CHURN(ape_cod_offset);
CHURN(ape_cod_paddr);
CHURN(ape_cod_rva);
CHURN(ape_cod_vaddr);
CHURN(ape_rom_vaddr);
CHURN(ape_text_align);
CHURN(ape_text_filesz);
CHURN(ape_text_memsz);
@ -700,7 +645,7 @@ CHURN(ADDR(.bss));
CHURN(_start);
CHURN(ape_phdrs);
#if SupportsMetal()
CHURN(v_ape_allsectors);
CHURN(v_ape_realsectors);
#endif
#if SupportsXnu()
CHURN(ape_macho);
@ -721,22 +666,22 @@ CHURN(WinMain);
#if SupportsWindows() || SupportsMetal()
#define LINK_WINDOWS (SupportsWindows() && !DEFINED(EfiMain))
PFSTUB4(ape_pe_offset, ape_pe - ape_mz);
ape_pe_optsz = ape_pe_sections - (ape_pe + 24);
ASSERT(ape_pe_optsz % 8 == 0, "SizeOfOptionalHeader must be multiple of 8");
ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40;
ape_pe_base = IMAGE_BASE_VIRTUAL;
ape_idataz = LINK_WINDOWS ? RVA(ape_idata_iat) : 0;
ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0;
ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0;
ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0;
v_ntdllchar = LINK_WINDOWS ? 288 : 0;
v_ntsubversion = LINK_WINDOWS ? 6 : 5;
v_ntsubsystem = (LINK_WINDOWS
? (DEFINED(GetMessage)
? kNtImageSubsystemWindowsGui
: kNtImageSubsystemWindowsCui)
: kNtImageSubsystemEfiApplication);
ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain;
HIDDEN(ape_pe_optsz = ape_pe_sections - (ape_pe + 24));
HIDDEN(ape_pe_shnum = (ape_pe_sections_end - ape_pe_sections) / 40);
HIDDEN(ape_pe_base = IMAGE_BASE_VIRTUAL);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_iat) : 0);
HIDDEN(ape_idata_iatsize = LINK_WINDOWS ? ape_idata_iatend - ape_idata_iat : 0);
HIDDEN(ape_idata = LINK_WINDOWS ? RVA(ape_idata_idt) : 0);
HIDDEN(ape_idata_idtsize = LINK_WINDOWS ? ape_idata_idtend - ape_idata_idt : 0);
HIDDEN(v_ntversion = LINK_WINDOWS ? 6 : 1);
HIDDEN(v_ntdllchar = LINK_WINDOWS ? 288 : 0);
HIDDEN(v_ntsubversion = LINK_WINDOWS ? 6 : 5);
HIDDEN(v_ntsubsystem = (LINK_WINDOWS
? (DEFINED(GetMessage)
? kNtImageSubsystemWindowsGui
: kNtImageSubsystemWindowsCui)
: kNtImageSubsystemEfiApplication));
HIDDEN(ape_pe_entry = LINK_WINDOWS ? WinMain : EfiMain);
#endif
#if SupportsXnu()
@ -754,16 +699,17 @@ ASSERT(((DEFINED(__init_rodata_end) ? __init_rodata_end : 0) %
ASSERT((!DEFINED(ape_grub) ? 1 : RVA(ape_grub) < 8192),
"grub stub needs to be in first 8kb of image");
ASSERT(DEFINED(_start) || DEFINED(_start16),
"please link a _start() or _start16() entrypoint");
ASSERT(!DEFINED(_start16) || REAL(_end) < 65536,
"ape won't support non-tiny real mode programs");
ASSERT(IS2POW(ape_stack_memsz),
"ape_stack_memsz must be a two power");
ASSERT(ape_stack_vaddr % ape_stack_memsz == 0,
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000040000 & -ape_stack_memsz);");
ASSERT(ALIGNOF(.tdata) <= TLS_ALIGNMENT && ALIGNOF(.tbss) <= TLS_ALIGNMENT,
"_Thread_local _Alignof can't exceed TLS_ALIGNMENT");
ASSERT(DEFINED(main), "main() function not defined");
ASSERT(!(ape_stack_vaddr & (ape_stack_memsz - 1)),
"ape_stack_vaddr must have ape_stack_memsz alignment; try using STATIC_STACK_ADDR(0x700000000000 - ape_stack_memsz);");
/* Let's not be like Knight Capital. */
/* NOCROSSREFS_TO(.test .text) */

169
ape/ape.mk Normal file
View file

@ -0,0 +1,169 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# OVERVIEW
#
# αcτµαlly pδrταblε εxεcµταblε
#
# DESCRIPTION
#
# This file defines the libraries, runtimes, and build rules needed to
# create executables from your Linux workstation that'll run anywhere.
# Loading this package will make certain systemic modifications to the
# build like turning off the System V "Red Zone" optimization, because
# αcτµαlly pδrταblε εxεcµταblεs need to be able to run in kernelspace.
PKGS += APE
APE = o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape.lds
APE_NO_MODIFY_SELF = \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/ape/ape-no-modify-self.o
APE_COPY_SELF = \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/ape/ape-copy-self.o
APELINK = \
$(COMPILE) \
-ALINK.ape \
$(LINK) \
$(LINKARGS) \
$(OUTPUT_OPTION)
APE_LOADER_FLAGS = \
-DNDEBUG \
-iquote. \
-Wall \
-Wextra \
-fpie \
-Os \
-ffreestanding \
-mgeneral-regs-only \
-mno-red-zone \
-fno-ident \
-fno-gnu-unique \
-c \
$(OUTPUT_OPTION) \
$<
APE_FILES := $(wildcard ape/*.*)
APE_HDRS = $(filter %.h,$(APE_FILES))
APE_INCS = $(filter %.inc,$(APE_FILES))
APE_SRCS_C = ape/loader.c
APE_SRCS_S = $(filter %.S,$(APE_FILES))
APE_SRCS = $(APE_SRCS_C) $(APE_SRCS_S)
APE_OBJS = $(APE_SRCS_S:%.S=o/$(MODE)/%.o)
APE_CHECKS = $(APE_HDRS:%=o/%.ok)
o/$(MODE)/ape/ape.lds: \
ape/ape.lds \
ape/macros.internal.h \
ape/relocations.h \
libc/intrin/bits.h \
libc/calls/struct/timespec.h \
libc/dce.h \
libc/elf/def.h \
libc/elf/pf2prot.internal.h \
libc/macros.internal.h \
libc/nt/pedef.internal.h \
libc/str/str.h \
libc/zip.h
o/ape/idata.inc: \
ape/idata.internal.h \
ape/relocations.h
o/$(MODE)/ape/ape-no-modify-self.o: \
ape/ape.S \
ape/macros.internal.h \
ape/notice.inc \
ape/relocations.h \
libc/dce.h \
libc/elf/def.h \
libc/intrin/asancodes.h \
libc/macho.internal.h \
libc/macros-cpp.internal.inc \
libc/macros.internal.h \
libc/macros.internal.inc \
libc/nexgen32e/uart.internal.h \
libc/nexgen32e/vidya.internal.h \
libc/nt/pedef.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/runtime/pc.internal.h \
libc/runtime/symbolic.h \
libc/sysv/consts/prot.h \
o/$(MODE)/ape/ape.elf
@$(COMPILE) \
-AOBJECTIFY.S \
$(OBJECTIFY.S) \
$(OUTPUT_OPTION) \
-DAPE_NO_MODIFY_SELF \
-DAPE_LOADER='"o/$(MODE)/ape/ape.elf"' $<
o/$(MODE)/ape/ape-copy-self.o: \
ape/ape.S \
ape/macros.internal.h \
ape/notice.inc \
ape/relocations.h \
libc/dce.h \
libc/elf/def.h \
libc/intrin/asancodes.h \
libc/macho.internal.h \
libc/macros-cpp.internal.inc \
libc/macros.internal.h \
libc/macros.internal.inc \
libc/nexgen32e/uart.internal.h \
libc/nexgen32e/vidya.internal.h \
libc/nt/pedef.internal.h \
libc/runtime/e820.internal.h \
libc/runtime/mman.internal.h \
libc/runtime/pc.internal.h \
libc/runtime/symbolic.h \
libc/sysv/consts/prot.h
@$(COMPILE) \
-AOBJECTIFY.S \
$(OBJECTIFY.S) \
$(OUTPUT_OPTION) \
-DAPE_NO_MODIFY_SELF $<
o/$(MODE)/ape/loader.o: ape/loader.c ape/loader.h
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -g $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-gcc.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b01111001 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-clang.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=0b01111001 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-xnu.o: ape/loader.c ape/loader.h
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b00001000 -g $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-xnu-gcc.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CC) -DSUPPORT_VECTOR=0b00001000 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/loader-xnu-clang.asm: ape/loader.c
@$(COMPILE) -AOBJECTIFY.c $(CLANG) -DSUPPORT_VECTOR=0b00001000 -S -g0 $(APE_LOADER_FLAGS)
o/$(MODE)/ape/ape.elf: o/$(MODE)/ape/ape.elf.dbg
o/$(MODE)/ape/ape.macho: o/$(MODE)/ape/ape.macho.dbg
o/$(MODE)/ape/ape.elf.dbg: \
o/$(MODE)/ape/loader.o \
o/$(MODE)/ape/loader-elf.o \
ape/loader.lds
@$(ELFLINK) -z max-page-size=0x10
o/$(MODE)/ape/ape.macho.dbg: \
o/$(MODE)/ape/loader-xnu.o \
o/$(MODE)/ape/loader-macho.o \
ape/loader-macho.lds
@$(ELFLINK) -z max-page-size=0x10
.PHONY: o/$(MODE)/ape
o/$(MODE)/ape: $(APE_CHECKS) \
o/$(MODE)/ape/ape.o \
o/$(MODE)/ape/ape.lds \
o/$(MODE)/ape/ape.elf \
o/$(MODE)/ape/ape.macho \
o/$(MODE)/ape/ape-copy-self.o \
o/$(MODE)/ape/ape-no-modify-self.o

View file

@ -1,107 +1,62 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
TMPDIR=${TMPDIR:-/tmp}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ -x .cosmocc/current/bin/make ]; then
MAKE=.cosmocc/current/bin/make
else
MAKE=make
fi
if [ "$(id -u)" -eq 0 ]; then
if [ $UID -eq 0 ]; then
SUDO=
elif command -v sudo >/dev/null 2>&1; then
else
SUDO=sudo
elif command -v doas >/dev/null 2>&1; then
SUDO=doas
else
echo "need root or sudo" >&2
exit
fi
if command -v install >/dev/null 2>&1; then
if [ x"$(uname -s)" = xLinux ]; then
INSTALL="install -o root -g root -m 755"
else
INSTALL="install -o root -g wheel -m 755"
fi
else
INSTALL="cp -f"
fi
echo "Actually Portable Executable (APE) Installer" >&2
echo "Author: Justine Tunney <jtunney@gmail.com>" >&2
# special installation process for apple silicon
if [ x"$(uname -s)" = xDarwin ] && [ x"$(uname -m)" = xarm64 ]; then
echo "cc -O -o $TMPDIR/ape.$$ ape/ape-m1.c" >&2
cc -O -o "$TMPDIR/ape.$$" ape/ape-m1.c || exit
trap 'rm "$TMPDIR/ape.$$"' EXIT
if [ ! -d /usr/local/bin ]; then
echo "$SUDO mkdir -p /usr/local/bin" >&2
$SUDO mkdir -p /usr/local/bin || exit
fi
echo "$SUDO $INSTALL $TMPDIR/ape.$$ /usr/local/bin/ape" >&2
$SUDO $INSTALL "$TMPDIR/ape.$$" /usr/local/bin/ape || exit
exit
fi
if [ x"$(uname -m)" = xarm64 ] || [ x"$(uname -m)" = xaarch64 ]; then
MODE=aarch64
EXT=elf
BEXT=aarch64
elif [ x"$(uname -m)" = xx86_64 ]; then
MODE=
if [ x"$(uname -s)" = xDarwin ]; then
EXT=macho
else
EXT=elf
fi
BEXT=$EXT
else
echo "unsupported architecture $(uname -m)" >&2
exit
fi
################################################################################
# INSTALL APE LOADER SYSTEMWIDE
if [ -f o/$MODE/depend ] && $MAKE -j8 o/$MODE/ape; then
echo "successfully recompiled ape loader" >&2
elif [ -x o/$MODE/ape/ape.$EXT ]; then
echo "using ape loader you compiled earlier" >&2
if [ -f o/depend ]; then
# mkdeps.com build was successfully run so assume we can build
echo >&2
echo "recompiling ape loader" >&2
echo "running: make -j8 o//ape" >&2
make -j8 o//ape || exit
echo "done" >&2
elif [ -d build/bootstrap ]; then
# if make isn't being used then it's unlikely the user changed the sources
# in that case the prebuilt binaries should be completely up-to-date
echo "using prebuilt ape loader from cosmo repo" >&2
mkdir -p o/$MODE/ape || exit
cp -af build/bootstrap/ape.$BEXT o/$MODE/ape/ape.$EXT || exit
mkdir -p o//ape || exit
cp -af build/bootstrap/ape.elf o//ape/ape.elf || exit
cp -af build/bootstrap/ape.macho o//ape/ape.macho || exit
else
echo "no cosmopolitan libc repository here" >&2
echo "fetching ape loader from justine.lol" >&2
mkdir -p o/$MODE/ape || exit
echo "fetching ape loader from justine.lol" >&2
mkdir -p o//ape || exit
if command -v wget >/dev/null 2>&1; then
wget -qO o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
wget -qO o//ape/ape.elf https://justine.lol/ape.elf || exit
wget -qO o//ape/ape.macho https://justine.lol/ape.macho || exit
else
curl -Rso o/$MODE/ape/ape.$EXT https://justine.lol/ape.$BEXT || exit
curl -Rso o//ape/ape.elf https://justine.lol/ape.elf || exit
curl -Rso o//ape/ape.macho https://justine.lol/ape.macho || exit
fi
chmod +x o/$MODE/ape/ape.$EXT || exit
chmod +x o//ape/ape.elf || exit
chmod +x o//ape/ape.macho || exit
fi
if ! [ /usr/bin/ape -nt o/$MODE/ape/ape.$EXT ]; then
echo >&2
echo "installing o/$MODE/ape/ape.$EXT to /usr/bin/ape" >&2
echo "$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape" >&2
$SUDO $INSTALL o/$MODE/ape/ape.$EXT /usr/bin/ape || exit
echo "done" >&2
if [ "$(uname -s)" = "Darwin" ]; then
if ! [ /usr/bin/ape -nt o//ape/ape.macho ]; then
echo >&2
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.macho /usr/bin/ape || exit
echo "done" >&2
fi
else
if ! [ /usr/bin/ape -nt o//ape/ape.elf ]; then
echo >&2
echo "installing o//ape/ape.elf to /usr/bin/ape" >&2
echo "$SUDO mv -f o//ape/ape.elf /usr/bin/ape" >&2
$SUDO cp -f o//ape/ape.elf /usr/bin/ape || exit
echo "done" >&2
fi
fi
################################################################################
@ -137,20 +92,11 @@ if [ x"$(uname -s)" = xLinux ]; then
echo done >&2
fi
uname_r="$(uname -r)"
if printf '%s\n%s\n' 5.12 "$uname_r" | sort -CV; then
FLAGS=FP
else
FLAGS=F
fi
echo >&2
echo registering APE with binfmt_misc >&2
echo you may need to edit configs to persist across reboot >&2
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE-jart:M::jartsr::/usr/bin/ape:'"$FLAGS'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE-jart:M::jartsr::/usr/bin/ape:$FLAGS' >/proc/sys/fs/binfmt_misc/register" || exit
echo '$SUDO sh -c "echo '"'"':APE:M::MZqFpD::/usr/bin/ape:'"'"' >/proc/sys/fs/binfmt_misc/register"' >&2
$SUDO sh -c "echo ':APE:M::MZqFpD::/usr/bin/ape:' >/proc/sys/fs/binfmt_misc/register" || exit
echo done >&2
if [ x"$(cat /proc/sys/fs/binfmt_misc/status)" = xdisabled ]; then

View file

@ -1,68 +1,24 @@
#!/bin/sh
PROG=${0##*/}
MODE=${MODE:-$m}
COSMO=${COSMO:-/opt/cosmo}
COSMOS=${COSMOS:-/opt/cosmos}
if [ ! -f ape/loader.c ]; then
cd "$COSMO" || exit
fi
if [ "$UID" = "0" ]; then
SUDO=
elif command -v sudo >/dev/null 2>&1; then
SUDO=sudo
elif command -v doas >/dev/null 2>&1; then
SUDO=doas
else
echo "need root or sudo" >&2
exit
SUDO=sudo
fi
{
echo
echo "APE Uninstaller intends to run (in pseudo-shell)"
echo "APE Uninstaller intends to run"
echo
echo " sudo echo -1 into /proc/sys/fs/binfmt_misc/APE*"
echo " sudo rm -f /usr/bin/ape ~/.ape /tmp/.ape # etc."
echo " $SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE'"
echo " $SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape /tmp/.ape"
echo
echo "You may then use ape/apeinstall.sh to reinstall it"
echo
} >&2
set -ex
for f in /proc/sys/fs/binfmt_misc/APE*; do
if [ -f $f ]; then
$SUDO sh -c "echo -1 >$f" || exit
fi
done
# system installation
if [ -f /usr/bin/ape ]; then
$SUDO rm -f /usr/bin/ape
if [ -f /proc/sys/fs/binfmt_misc/APE ]; then
$SUDO sh -c 'echo -1 >/proc/sys/fs/binfmt_misc/APE' || exit
fi
if [ -f /usr/local/bin/ape ]; then
$SUDO rm -f /usr/local/bin/ape
fi
# legacy installations
rm -f o/tmp/ape /tmp/ape "${TMPDIR:-/tmp}/ape"
# ad-hoc installations
for x in .ape \
.ape-1.1 \
.ape-1.3 \
.ape-1.4 \
.ape-1.5 \
.ape-1.6 \
.ape-1.7 \
.ape-1.8 \
.ape-1.9 \
.ape-1.10; do
rm -f \
~/$x \
/tmp/$x \
o/tmp/$x \
"${TMPDIR:-/tmp}/$x"
done
$SUDO rm -f /usr/bin/ape ~/.ape o/tmp/.ape o/tmp/ape /tmp/.ape /tmp/ape || exit

10
ape/config.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef COSMOPOLITAN_APE_CONFIG_H_
#define COSMOPOLITAN_APE_CONFIG_H_
#if !(__ASSEMBLER__ + __LINKER__ + 0)
#define STATIC_SYMBOL(NAME, VALUE) \
asm(".equ\t" NAME "," VALUE "\n\t" \
".globl\t" NAME)
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_APE_CONFIG_H_ */

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -31,84 +31,80 @@
// @see libc/nt/master.sh
// @see ape/ape.lds
// @see winimp
.macro .imp dll:req fn:req actual:req
#ifdef __x86_64__
.dll "\dll"
.section ".piro.data.sort.iat.2.\dll\().2.\actual","aw",@progbits
.macro .imp dll:req fn:req actual:req hint
.dll \dll
.section .piro.data.sort.iat.2.\dll\().2.\actual,"aw",@progbits
.type \fn,@object
.align __SIZEOF_POINTER__
\fn: .quad RVA(("\dll\().\actual"))
\fn: .quad RVA((\dll\().\actual))
.size \fn,.-\fn
.globl \fn
.hidden \fn
.previous
.section ".idata.ro.ilt.\dll\().2.\actual","a",@progbits
"idata.ilt.\dll\().\actual":
.quad RVA("\dll\().\actual")
.type "idata.ilt.\dll\().\actual",@object
.size "idata.ilt.\dll\().\actual",.-"idata.ilt.\dll\().\actual"
.section .idata.ro.ilt.\dll\().2.\actual,"a",@progbits
.Lidata.ilt.\dll\().\actual:
.quad RVA((\dll\().\actual))
.type .Lidata.ilt.\dll\().\actual,@object
.size .Lidata.ilt.\dll\().\actual,.-.Lidata.ilt.\dll\().\actual
.previous
.section ".idata.ro.hnt.\dll\().2.\actual","a",@progbits
"\dll\().\actual":
.short 0 // hint
.section .idata.ro.hnt.\dll\().2.\actual,"a",@progbits
\dll\().\actual:
.ifnb \hint # hint i.e. guess function ordinal
.short \hint
.else
.short 0
.endif
.asciz "\actual"
.align 2 // documented requirement
.globl "\dll\().\actual"
.hidden "\dll\().\actual"
.type "\dll\().\actual",@object
.size "\dll\().\actual",.-"\dll\().\actual"
.align 2 # documented requirement
.globl \dll\().\actual
.hidden \dll\().\actual
.type \dll\().\actual,@object
.size \dll\().\actual,.-\dll\().\actual
.previous
#else
.section ".data.nt.\actual","aw",@progbits
.globl "\fn"
.balign 8
.weak "\actual"
"\fn": .quad "\actual"
#endif
.endm
// Defines DLL import.
// @note this is an implementation detail of .imp
.macro .dll name:req
.section ".idata.ro.idt.2.\name","aG",@progbits,"\name",comdat
.equ ".Lidata.idt.\name",.
.long RVA("idata.ilt.\name") // ImportLookupTable
.long 0 // TimeDateStamp
.long 0 // ForwarderChain
.long RVA(".Lidata.str.\name") // DllNameRva
.long RVA("idata.iat.\name") // ImportAddressTable
.type ".Lidata.idt.\name",@object
.size ".Lidata.idt.\name",.-".Lidata.idt.\name"
.section .idata.ro.idt.2.\name,"aG",@progbits,\name,comdat
.equ .Lidata.idt.\name,.
.long RVA(idata.ilt.\name) # ImportLookupTable
.long 0 # TimeDateStamp
.long 0 # ForwarderChain
.long RVA(.Lidata.str.\name) # DllNameRva
.long RVA(idata.iat.\name) # ImportAddressTable
.type .Lidata.idt.\name,@object
.size .Lidata.idt.\name,.-.Lidata.idt.\name
.previous
.section ".idata.ro.ilt.\name\().1","aG",@progbits,"\name",comdat
.balign __SIZEOF_POINTER__
.type "idata.ilt.\name",@object
"idata.ilt.\name":
.section .idata.ro.ilt.\name\().1,"aG",@progbits,\name,comdat
.align __SIZEOF_POINTER__
.type idata.ilt.\name,@object
idata.ilt.\name:
.previous/*
...
decentralized content
...
*/.section ".idata.ro.ilt.\name\().3","aG",@progbits,"\name",comdat
*/.section .idata.ro.ilt.\name\().3,"aG",@progbits,\name,comdat
.quad 0
.previous
.section ".idata.ro.hnt.\name\().1","aG",@progbits,"\name",comdat
.balign __SIZEOF_POINTER__
.type "idata.hnt.\name",@object
.equ "idata.hnt.\name",.
.section .idata.ro.hnt.\name\().1,"aG",@progbits,\name,comdat
.align __SIZEOF_POINTER__
.type idata.hnt.\name,@object
.equ idata.hnt.\name,.
.previous
.section ".piro.data.sort.iat.2.\name\().1","awG",@progbits,"\name",comdat
.balign __SIZEOF_POINTER__
.type "idata.iat.\name",@object
"idata.iat.\name":
.section .piro.data.sort.iat.2.\name\().1,"awG",@progbits,\name,comdat
.align __SIZEOF_POINTER__
.type idata.iat.\name,@object
idata.iat.\name:
.previous/*
...
decentralized content
...
*/.section ".piro.data.sort.iat.2.\name\().3","awG",@progbits,"\name",comdat
*/.section .piro.data.sort.iat.2.\name\().3,"awG",@progbits,\name,comdat
.quad 0
.previous
.section .rodata.str1.1,"aSM",@progbits,1
".Lidata.str.\name":
.Lidata.str.\name:
.asciz "\name\().dll"
.previous
.endm

View file

@ -1,90 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
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
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/macros.h"
// Calls _start() function of loaded program.
//
// When the program entrypoint is called, all registers shall be
// cleared, with the exception of (1) %rdi will be equal to %rsp
// on FreeBSD and (2) %cl will contain the detected host OS code
//
// We clear all the general registers we can to have some wiggle
// room, to extend the behavior of this loader in the future. We
// don't need to clear the XMM registers because your APE loader
// should be compiled using gcc/clang's -mgeneral-regs-only flag
//
// @param rdi is passed through as-is
// @param rsi is address of entrypoint (becomes zero)
// @param rdx is passed through as-is
// @param rcx is passed through as-is
// @param r8 is stack pointer (becomes zero)
// @noreturn
Launch:
#ifdef __aarch64__
mov x16,x1
mov sp,x4
mov x1,0
mov x4,0
mov x5,0
mov x6,0
mov x7,0
mov x8,0
mov x9,0
mov x10,0
mov x11,0
mov x12,0
mov x13,0
mov x14,0
mov x15,0
mov x17,0
mov x19,0
mov x20,0
mov x21,0
mov x22,0
mov x23,0
mov x24,0
mov x25,0
mov x26,0
mov x27,0
mov x28,0
mov x29,0
mov x30,0
br x16
#else
mov %r8,%rsp
xor %r8d,%r8d
xor %r9d,%r9d
xor %r10d,%r10d
xor %r11d,%r11d
xor %r12d,%r12d
xor %r13d,%r13d
xor %r14d,%r14d
xor %r15d,%r15d
push %rsi
xor %esi,%esi
xor %ebp,%ebp
xor %ebx,%ebx
xor %eax,%eax
ret
#endif
.endfn Launch,globl

249
ape/loader-elf.S Normal file
View file

@ -0,0 +1,249 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2021 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/def.h"
#include "libc/sysv/consts/prot.h"
#include "libc/macho.internal.h"
#include "libc/dce.h"
#include "libc/macros.internal.h"
// APE Loader Executable Structure
// Linux, FreeBSD, NetBSD, OpenBSD
.align 8
ehdr: .ascii "\177ELF"
.byte ELFCLASS64
.byte ELFDATA2LSB
.byte 1
.byte ELFOSABI_FREEBSD
.quad 0
.word ET_EXEC # e_type
.word EM_NEXGEN32E # e_machine
.long 1 # e_version
.quad _start # e_entry
.quad phdrs - ehdr # e_phoff
.quad 0 # e_shoff
.long 0 # e_flags
.word 64 # e_ehsize
.word 56 # e_phentsize
.word 4 # e_phnum
.word 0 # e_shentsize
.word 0 # e_shnum
.word 0 # e_shstrndx
.endobj ehdr,globl
.align 8
phdrs: .long PT_LOAD # p_type
.long PF_R|PF_X # p_flags
.quad 0 # p_offset
.quad ehdr # p_vaddr
.quad ehdr # p_paddr
.quad filesz # p_filesz
.quad filesz # p_memsz
.quad PAGESIZE # p_align
.long PT_LOAD # p_type
.long PF_R|PF_W # p_flags
.quad 0 # p_offset
.quad bss # p_vaddr
.quad bss # p_paddr
.quad 0 # p_filesz
.quad bsssize # p_memsz
.quad PAGESIZE # p_align
.long PT_GNU_STACK # p_type
.long PF_R|PF_W # p_flags
.quad 0 # p_offset
.quad 0 # p_vaddr
.quad 0 # p_paddr
.quad 0 # p_filesz
.quad 0 # p_memsz
.quad 16 # p_align
.long PT_NOTE # p_type
.long PF_R # p_flags
.quad note - ehdr # p_offset
.quad note # p_vaddr
.quad note # p_paddr
.quad notesize # p_filesz
.quad notesize # p_memsz
.quad 8 # p_align
.endobj phdrs
note: .long 2f-1f
.long 4f-3f
.long 1
1: .asciz "OpenBSD"
2: .align 4
3: .long 0
4: .long 2f-1f
.long 4f-3f
.long 1
1: .asciz "NetBSD"
2: .align 4
3: .long 901000000
4: .endobj note
notesize = . - note
.align 64,0 # for ape.S dd
.org 0x180 # for ape.S dd
// APE Loader XNU Header
//
// This header is dd'd backwards by the APE shell script when
// running on Mac OS X.
//
// @see ape/ape.S
macho: .long 0xFEEDFACE+1
.long MAC_CPU_NEXGEN32E
.long MAC_CPU_NEXGEN32E_ALL
.long MAC_EXECUTE
.long 5 # number of load commands
.long 60f-10f # size of all load commands
.long MAC_NOUNDEFS # flags
.long 0 # reserved
10: .long MAC_LC_SEGMENT_64
.long 20f-10b # unmaps first page dir
.ascin "__PAGEZERO",16 # consistent with linux
.quad 0,0x200000,0,0 # which forbids mem <2m
.long 0,0,0,0
20: .long MAC_LC_SEGMENT_64
.long 30f-20b
.ascin "__TEXT",16
.quad ehdr # vaddr
.quad 4096 # memsz
.quad 0 # file offset
.quad filesz # file size
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
.long PROT_EXEC|PROT_READ # initprot
.long 1 # segment section count
.long 0 # flags
210: .ascin "__text",16 # section name (.text)
.ascin "__TEXT",16
.quad _start # vaddr
.quad textsz # memsz
.long textoff # offset
.long 6 # align 2**6 = 64
.long 0 # reloc table offset
.long 0 # relocation count
.long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes
.long 0,0,0 # reserved
30: .long MAC_LC_SEGMENT_64
.long 40f-30b
.ascin "__DATA",16
.quad bss # vaddr
.quad bsssize # memsz
.quad 0 # offset
.quad 0 # file size
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
.long PROT_READ|PROT_WRITE # initprot
.long 1 # segment section count
.long 0 # flags
310: .ascin "__bss",16 # section name (.bss)
.ascin "__DATA",16
.quad bss # vaddr
.quad bsssize # memsz
.long 0 # offset
.long 12 # align 2**12 = 4096
.long 0 # reloc table offset
.long 0 # relocation count
.long MAC_S_ZEROFILL # section type & attributes
.long 0,0,0 # reserved
40: .long MAC_LC_UUID
.long 50f-40b
.quad 0x3fb29ee4ac6c87aa # uuid1
.quad 0xdd2c9bb866d9eef8 # uuid2
50: .long MAC_LC_UNIXTHREAD
.long 60f-50b # cmdsize
.long MAC_THREAD_NEXGEN32E # flavaflav
.long (520f-510f)/4 # count
510: .quad 0 # rax
.quad 0 # rbx
.quad 0 # rcx
.quad XNU # rdx
.quad 0 # rdi
.quad 0 # rsi
.quad 0 # rbp
.quad 0 # rsp
.quad 0 # r8
.quad 0 # r9
.quad 0 # r10
.quad 0 # r11
.quad 0 # r12
.quad 0 # r13
.quad 0 # r14
.quad 0 # r15
.quad _start # rip
.quad 0 # rflags
.quad 0 # cs
.quad 0 # fs
.quad 0 # gs
520:
60:
.endobj macho
.align 64,0 # for ape.S dd
.org 0x400 # for ape.S dd
// Ape Loader Entrpoint
//
// This is normally called by the operating system. However it may
// be called by the Actually Portable Executables themselves, when
// re-executing a program. Just do this:
//
// memcpy(0x200000, loader)
// lea handoff(%rip),%rcx
// lea argblock(%rip),%rsp
// jmp 0x200400
//
// @see APE_LOADER_ENTRY
// @see ape/loader.h
_start:
// Hack for detecting M1 Rosetta environment.
// https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377
cmp $-1,%ebx
jne 0f
cmp $+1,%edx
jne 0f
mov $XNU,%dl
xor %ecx,%ecx
0: mov %rsp,%rsi
jmp ApeLoader
.endfn _start,globl
// System Call Entrpoint
//
// This function is used by the APE loader to make system calls.
// We also pass a reference to this function to the APE binary's
// _start() function. It's needed because on OpenBSD, msyscall()
// restricts which pages can issue system calls, and it can only
// be called once. Therefore if we want to be load and re-load a
// binary multiple times without calling the system execve(), we
// need to be able to handover the SYSCALL function. We hardcode
// this to a fixed address, but that shouldn't be used, since we
// would ideally want to move it to a random page in the future.
__syscall_loader:
clc
syscall
jc 1f
ret
1: neg %rax
ret
.endfn __syscall_loader,globl

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
vi: set et ft=asm ts=8 tw=8 fenc=utf-8 :vi
Copyright 2021 Justine Alexandra Roberts Tunney
@ -16,80 +16,123 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/macho.h"
#include "libc/macho.internal.h"
#include "libc/sysv/consts/prot.h"
#include "libc/dce.h"
#include "libc/macros.h"
#include "libc/macros.internal.h"
// Apple Mach-O Executable Headers
// Fixups are applied by objbincopy
// There must exist a MAC_LC_SEGMENT_64 for every PT_LOAD
// APE Loader Executable Structure for XNU
.section .macho,"a",@progbits
.balign 64
.long 0xFEEDFACE+1
.align 4096
macho: .long 0xFEEDFACE+1
.long MAC_CPU_NEXGEN32E
.long MAC_CPU_NEXGEN32E_ALL
.long MAC_EXECUTE
.long 5 // number of load commands
.long 60f-10f // size of all load commands
.long MAC_NOUNDEFS|MAC_SPLIT_SEGS // flags
.long 0 // reserved
.long 5 # number of load commands
.long 60f-10f # size of all load commands
.long MAC_NOUNDEFS # flags
.long 0 # reserved
10: .long MAC_LC_SEGMENT_64
.long 20f-10b // unmaps first page dir
.ascin "__PAGEZERO",16 // consistent with linux
.quad 0,0x200000,0,0 // which forbids mem <2m
.long 20f-10b # unmaps first page dir
.ascin "__PAGEZERO",16 # consistent with linux
.quad 0,0x200000,0,0 # which forbids mem <2m
.long 0,0,0,0
20: .long MAC_LC_SEGMENT_64
.long 30f-20b
.ascin "__TEXT",16
.quad 0 // vaddr
.quad 0 // memsz
.quad 0 // file offset
.quad 0 // file size
.long 0 // maxprot
.long 0 // initprot
.long 0 // segment section count
.long 0 // flags
.quad macho # vaddr
.quad 4096 # memsz
.quad 0 # file offset
.quad filesz # file size
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
.long PROT_EXEC|PROT_READ # initprot
.long 1 # segment section count
.long 0 # flags
210: .ascin "__text",16 # section name (.text)
.ascin "__TEXT",16
.quad _start # vaddr
.quad textsz # memsz
.long textoff # offset
.long 6 # align 2**3 = 64
.long 0 # reloc table offset
.long 0 # relocation count
.long MAC_S_ATTR_SOME_INSTRUCTIONS # section type & attributes
.long 0,0,0 # reserved
30: .long MAC_LC_SEGMENT_64
.long 40f-30b
.ascin "__RODATA",16
.quad 0 // vaddr
.quad 0 // memsz
.quad 0 // file offset
.quad 0 // file size
.long 0 // maxprot
.long 0 // initprot
.long 0 // segment section count
.long 0 // flags
.ascin "__DATA",16
.quad bss # vaddr
.quad bsssize # memsz
.quad 0 # offset
.quad 0 # file size
.long PROT_EXEC|PROT_READ|PROT_WRITE # maxprot
.long PROT_READ|PROT_WRITE # initprot
.long 1 # segment section count
.long 0 # flags
310: .ascin "__bss",16 # section name (.bss)
.ascin "__DATA",16
.quad bss # vaddr
.quad bsssize # memsz
.long 0 # offset
.long 12 # align 2**12 = 4096
.long 0 # reloc table offset
.long 0 # relocation count
.long MAC_S_ZEROFILL # section type & attributes
.long 0,0,0 # reserved
40: .long MAC_LC_UUID
.long 50f-40b
.quad 0x4527148ba7a513ef // uuid1
.quad 0x56fa865940665e8f // uuid2
.quad 0x3fb29ee4ac6c87aa # uuid1
.quad 0xdd2c9bb866d9eef8 # uuid2
50: .long MAC_LC_UNIXTHREAD
.long 60f-50b // cmdsize
.long MAC_THREAD_NEXGEN32E // flavaflav
.long (520f-510f)/4 // count
510: .quad 0 // rax
.quad 0 // rbx
.quad 0 // rcx
.quad 0 // rdx
.quad 0 // rdi
.quad 0 // rsi
.quad 0 // rbp
.quad 0 // rsp
.quad 0 // r8
.quad 0 // r9
.quad 0 // r10
.quad 0 // r11
.quad 0 // r12
.quad 0 // r13
.quad 0 // r14
.quad 0 // r15
.quad XnuEntrypoint // rip
.quad 0 // rflags
.quad 0 // cs
.quad 0 // fs
.quad 0 // gs
.long 60f-50b # cmdsize
.long MAC_THREAD_NEXGEN32E # flavaflav
.long (520f-510f)/4 # count
510: .quad 0 # rax
.quad 0 # rbx
.quad 0 # rcx
.quad XNU # rdx
.quad 0 # rdi
.quad 0 # rsi
.quad 0 # rbp
.quad 0 # rsp
.quad 0 # r8
.quad 0 # r9
.quad 0 # r10
.quad 0 # r11
.quad 0 # r12
.quad 0 # r13
.quad 0 # r14
.quad 0 # r15
.quad _start # rip
.quad 0 # rflags
.quad 0 # cs
.quad 0 # fs
.quad 0 # gs
520:
60:
.endobj macho,globl
.align 64
_start:
// Hack for detecting M1 Rosetta environment.
// https://github.com/jart/cosmopolitan/issues/429#issuecomment-1166704377
cmp $-1,%ebx
jne 0f
cmp $+1,%edx
jne 0f
mov $XNU,%dl
xor %ecx,%ecx
0: mov %rsp,%rsi
jmp ApeLoader
.endfn _start,globl
__syscall_loader:
clc
syscall
jc 1f
ret
1: neg %rax
ret
.endfn __syscall_loader,globl

42
ape/loader-macho.lds Normal file
View file

@ -0,0 +1,42 @@
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
│vi: set et sts=2 tw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2021 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. │
╚─────────────────────────────────────────────────────────────────────────────*/
ENTRY(_start)
SECTIONS {
. = 0x200000;
.text : {
*(.text)
*(.rodata .rodata.*)
. = ALIGN(4096);
}
filesz = . - macho;
textsz = . - _start;
.bss ALIGN(4096) : {
bss = .;
*(.bss)
. = ALIGN(4096);
}
memsz = . - macho;
/DISCARD/ : {
*(.*)
}
}
bsssize = SIZEOF(.bss);
textoff = _start - macho;

File diff suppressed because it is too large Load diff

20
ape/loader.h Normal file
View file

@ -0,0 +1,20 @@
#ifndef COSMOPOLITAN_APE_LOADER_H_
#define COSMOPOLITAN_APE_LOADER_H_
#define APE_LOADER_BASE 0x200000
#define APE_LOADER_SIZE 0x200000
#define APE_LOADER_ENTRY 0x200400
#define APE_LOADER_BSS (PAGESIZE * 2)
#define APE_LOADER_STACK 0x7f0000000000
#define APE_BLOCK_BASE 0x7e0000000000
#define APE_BLOCK_SIZE 0x000200000000
struct ApeLoader {
int fd;
int os;
char *prog;
char *page;
void *syscall;
};
#endif /* COSMOPOLITAN_APE_LOADER_H_ */

View file

@ -1,7 +1,7 @@
/*-*- mode: ld-script; indent-tabs-mode: nil; tab-width: 2; coding: utf-8 -*-│
vi: set et sts=2 sw=2 fenc=utf-8 :vi
vi: set et sts=2 tw=2 fenc=utf-8 :vi│
╞══════════════════════════════════════════════════════════════════════════════╡
│ Copyright 2023 Justine Alexandra Roberts Tunney │
│ Copyright 2021 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 │
@ -16,80 +16,28 @@
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
│ PERFORMANCE OF THIS SOFTWARE. │
╚─────────────────────────────────────────────────────────────────────────────*/
ENTRY(ElfEntrypoint)
PHDRS {
text PT_LOAD FLAGS(1) FILEHDR PHDRS; /* PF_X */
rodata PT_LOAD FLAGS(4); /* PF_R */
stack PT_GNU_STACK FLAGS(6); /* PF_W|PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
}
ENTRY(_start)
SECTIONS {
. = SEGMENT_START("text-segment", 0x7f000000);
__executable_start = .;
. += SIZEOF_HEADERS;
.macho : {
KEEP(*(.macho))
} :text
.note : {
KEEP(*(.note))
} :text :note
. = 0x200000;
.text : {
*(.text .text.* .gnu.linkonce.t.*)
} :text
.rodata ALIGN(CONSTANT(COMMONPAGESIZE)) : {
*(.rodata .rodata.* .gnu.linkonce.r.*)
} :rodata
.stack : {
*(.stack)
} :stack
*(.text)
*(.rodata .rodata.*)
. = ALIGN(64);
}
filesz = . - ehdr;
textsz = . - _start;
.bss ALIGN(4096) : {
bss = .;
*(.bss)
. = ALIGN(4096);
}
_end = .;
.stab 0 : { *(.stab) }
.stabstr 0 : { *(.stabstr) }
.stab.excl 0 : { *(.stab.excl) }
.stab.exclstr 0 : { *(.stab.exclstr) }
.stab.index 0 : { *(.stab.index) }
.stab.indexstr 0 : { *(.stab.indexstr) }
.gnu.build.attributes : { *(.gnu.build.attributes .gnu.build.attributes.*) }
.debug 0 : { *(.debug) }
.line 0 : { *(.line) }
.debug_srcinfo 0 : { *(.debug_srcinfo) }
.debug_sfnames 0 : { *(.debug_sfnames) }
.debug_aranges 0 : { *(.debug_aranges) }
.debug_pubnames 0 : { *(.debug_pubnames) }
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
.debug_abbrev 0 : { *(.debug_abbrev) }
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end) }
.debug_frame 0 : { *(.debug_frame) }
.debug_str 0 : { *(.debug_str) }
.debug_loc 0 : { *(.debug_loc) }
.debug_macinfo 0 : { *(.debug_macinfo) }
.debug_weaknames 0 : { *(.debug_weaknames) }
.debug_funcnames 0 : { *(.debug_funcnames) }
.debug_typenames 0 : { *(.debug_typenames) }
.debug_varnames 0 : { *(.debug_varnames) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.debug_ranges 0 : { *(.debug_ranges) }
.debug_macro 0 : { *(.debug_macro) }
.debug_addr 0 : { *(.debug_addr) }
.debug_loclists 0 : { *(.debug_loclists) }
.debug_rnglists 0 : { *(.debug_rnglists) }
.debug_line_str 0 : { *(.debug_line_str) }
.debug_extra 0 : { *(.debug_line_str) }
.debug_pubtypes 0 : { *(.debug_pubtypes) }
.gnu.attributes 0 : { KEEP(*(.gnu.attributes)) }
memsz = _end - ehdr;
/DISCARD/ : {
*(.*)
}
}
bsssize = SIZEOF(.bss);
textoff = _start - ehdr;

View file

@ -1,5 +1,5 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
vi: set et ft=asm ts=8 sw=8 fenc=utf-8 :vi
Copyright 2020 Justine Alexandra Roberts Tunney
@ -18,10 +18,123 @@
*/
#ifndef APE_MACROS_H_
#define APE_MACROS_H_
#include "libc/macros.h"
#include "libc/macros.internal.h"
#ifdef __ASSEMBLER__
/* clang-format off */
/**
* @fileoverview Macros relevant to αcτµαlly pδrταblε εxεcµταblε.
*/
// Calls near (i.e. pc+pcrel<64kB) FUNCTION.
// @mode long,legacy,real
// @cost 9 bytes overhead
.macro rlcall function:req
.byte 0x50 # push %[er]ax
.byte 0xb8,0,0 # mov $?,%[e]ax
jmp 911f
.byte 0x58 # pop %[er]ax
.byte 0xe8 # call Jvds
.long \function\()-.-4
jmp 912f
911: .byte 0x58 # pop %[er]ax
.byte 0xe8 # call Jvds
.short \function\()-.-2
912:
.endm
// Loads far (i.e. <1mb) abs constexpr ADDRESS into ES:DI+EDX+RDX.
// @mode long,legacy,real
.macro movesdi address:req
.byte 0xbf # mov $0x????xxxx,%[e]di
.short \address>>4
.byte 0x8e,0xc7 # mov %di,%es
.byte 0xbf # mov $0x????xxxx,%[e]di
.short \address&0xf
jmp 297f
.byte 0xbf # mov $0x????xxxx,%edi
.long \address
297:
.endm
// Loads 16-bit CONSTEXPR into Qw-register w/ optional zero-extend.
// @mode long,legacy,real
.macro bbmov constexpr:req abcd abcd.hi:req abcd.lo:req
.ifnb \abcd
.if (\constexpr)<128 && (\constexpr)>=0
pushpop \constexpr,\abcd
.exitm
.endif
.endif
movb $(\constexpr)>>8&0xff,\abcd.hi
movb $(\constexpr)&0xff,\abcd.lo
.endm
// Compares 16-bit CONSTEXPR with Qw-register.
// @mode long,legacy,real
.macro bbcmp constexpr:req abcd.hi:req abcd.lo:req
cmpb $(\constexpr)>>8&0xff,\abcd.hi
jnz 387f
cmpb $(\constexpr)&0xff,\abcd.lo
387:
.endm
// Adds 16-bit CONSTEXPR to Qw-register.
// @mode long,legacy,real
.macro bbadd constexpr:req abcd.hi:req abcd.lo:req
addb $(\constexpr)&0xff,\abcd.lo
.if (\constexpr) != 0
adcb $(\constexpr)>>8&0xff,\abcd.hi
.endif
.endm
// Subtracts 16-bit CONSTEXPR from Qw-register.
// @mode long,legacy,real
.macro bbsub constexpr:req abcd.hi:req abcd.lo:req
subb $(\constexpr)&0xff,\abcd.lo
.if (\constexpr) != 0
sbbb $(\constexpr)>>8&0xff,\abcd.hi
.endif
.endm
// Ands Qw-register with 16-bit CONSTEXPR.
// @mode long,legacy,real
.macro bband constexpr:req abcd.hi:req abcd.lo:req
.if ((\constexpr)&0xff) != 0xff || ((\constexpr)>>8&0xff) == 0xff
andb $(\constexpr)&0xff,\abcd.lo
.endif
.if ((\constexpr)>>8&0xff) != 0xff
andb $(\constexpr)>>8&0xff,\abcd.hi
.endif
.endm
// Ors Qw-register with 16-bit CONSTEXPR.
// @mode long,legacy,real
.macro bbor constexpr:req abcd.hi:req abcd.lo:req
.if ((\constexpr)&0xff) != 0 || ((\constexpr)>>8&0xff) != 0
orb $(\constexpr)&0xff,\abcd.lo
.endif
.if ((\constexpr)>>8&0xff) != 0
orb $(\constexpr)>>8&0xff,\abcd.hi
.endif
.endm
// Performs ACTION only if in real mode.
// @mode long,legacy,real
.macro rlo clobber:req action:vararg
990: mov $0,\clobber
.if .-990b!=3
.error "bad clobber or assembler mode"
.endif
991: \action
.rept 2-(.-991b)
nop
.endr
.if .-991b!=2
.error "ACTION must be 1-2 bytes"
.endif
.endm
// Initializes real mode stack.
// The most holiest of holy code.
// @mode real
@ -67,27 +180,12 @@
.stub \name\()_bcs\n,long
.endm
// Task State Segment Descriptor Entries.
.macro .tssdescstub name:req
.ifndef \name
.weak \name
.set \name,0
.endif
.ifndef \name\()_end
.weak \name\()_end
.set \name\()_end,0
.endif
.stub \name\()_desc_ent0,quad
.stub \name\()_desc_ent1,quad
.endm
/* clang-format on */
#elif defined(__LINKER__)
#define BCX_NIBBLE(X) \
((((X) & 0xf) > 0x9) ? ((X) & 0xf) + 0x37 : ((X) & 0xf) + 0x30)
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
#define BCX_NIBBLE(X) ((((X)&0xf) > 0x9) ? ((X)&0xf) + 0x37 : ((X)&0xf) + 0x30)
#define BCX_OCTET(X) ((BCX_NIBBLE((X) >> 4) << 8) | (BCX_NIBBLE((X) >> 0) << 0))
#define BCX_INT16(X) ((BCX_OCTET((X) >> 8) << 16) | (BCX_OCTET((X) >> 0) << 0))
#define BCXSTUB(SYM, X) \
HIDDEN(SYM##_bcx0 = BCX_INT16((X) >> 48)); \
HIDDEN(SYM##_bcx1 = BCX_INT16((X) >> 32)); \
@ -99,12 +197,12 @@
*
* <p>This allows linker scripts to generate printf commands.
*/
#define BCO_OCTET(X) (((X) & 0x7) + 0x30)
#define BCO_OCTET(X) (((X)&0x7) + 0x30)
#define BCOB_UNIT(X) \
((BCO_OCTET((X) >> 0) << 24) | (BCO_OCTET((X) >> 3) << 16) | \
(BCO_OCTET(((X) & 0xff) >> 6) << 8) | 0x5c)
(BCO_OCTET(((X)&0xff) >> 6) << 8) | 0x5c)
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I) * 8)))
#define PFBYTE(SYM, X, I) HIDDEN(SYM##_bcs##I = BCOB_UNIT((X) >> ((I)*8)))
#define PFSTUB2(SYM, X) \
HIDDEN(SYM = (X)); \
PFBYTE(SYM, X, 0); \
@ -123,47 +221,44 @@
/**
* Binary coded decimal support.
*
* <p>This allows linker scripts to generate dd commands, e.g. ape.lds.
* There are a few ways to pad each number to the necessary 8 bytes.
* Spaces cannot be prepended because busybox refuses to parse them.
* Zeros cannot be prepended because Mac will take numbers as octal.
* That leaves appending spaces. The user's shell ought to treat any
* unquoted run of spaces as if there was only one, so this is safe.
* <p>This allows linker scripts to generate dd commands. Leading spaces
* need to be inserted so Mac doesn't consider them octal; therefore,
* parameters must be quoted; and eight digits should be good enough.
*/
#define SHSTUB2(SYM, X) \
HIDDEN(SYM##_bcs0 = BCD_LEFT(X)); \
HIDDEN(SYM##_bcs1 = BCD_RIGHT(X))
#define BCD_SMEAR(X) ((X) + (X) * 10000)
#define BCD_LEFT(X) \
(((X)) < 10000 ? BCD_RIGHT(BCD_SMEAR(X)) | 0x10 \
: (X) < 100000 ? BCD_RIGHT(BCD_SMEAR((X) / 10)) \
: (X) < 1000000 ? BCD_RIGHT(BCD_SMEAR((X) / 100)) \
: (X) < 10000000 ? BCD_RIGHT(BCD_SMEAR((X) / 1000)) \
: (X) < 100000000 ? BCD_RIGHT(BCD_SMEAR((X) / 10000)) \
: 0xffffffffffffffff)
#define BCD_RIGHT(X) \
(((X)) < 10000 ? 0x20202020 \
: (X) < 100000 ? 0x20202030 + (X) % 10 \
: (X) < 1000000 ? 0x20203030 + ((X) / 10) % 10 + (X) % 10 * 0x100 \
: (X) < 10000000 ? 0x20303030 + ((X) / 100) % 10 + \
((X) / 10) % 10 * 0x100 + (X) % 10 * 0x10000 \
: (X) < 100000000 \
? 0x30303030 + ((X) / 1000) % 10 + ((X) / 100) % 10 * 0x100 + \
((X) / 10) % 10 * 0x10000 + (X) % 10 * 0x1000000 \
: 0xffffffffffffffff)
/**
* Laying out the GDT entries for a TSS for bare metal operation.
*/
#define TSSDESCSTUB2(SYM, BASE, LIM) \
HIDDEN(SYM##_desc_ent0 = TSSDESC_ENT0(BASE, LIM)); \
HIDDEN(SYM##_desc_ent1 = TSSDESC_ENT1(BASE)); \
ASSERT((LIM) >= 0 && (LIM) <= 0xffff, "bare metal TSS is suspiciously fat")
#define TSSDESC_ENT0(BASE, LIM) \
(((LIM) << 0 & 0x000000000000ffff) | ((BASE) << 16 & 0x000000ffffff0000) | \
0x89 << 40 | ((LIM) >> 16 << 48 & 0x000f000000000000) | 0x2 << 52 | \
((BASE) >> 24 << 56 & 0xff00000000000000))
#define TSSDESC_ENT1(BASE) ((BASE) >> 32 << 0 & 0x00000000ffffffff)
#define SHSTUB2(SYM, X) \
HIDDEN(SYM##_bcs0 = BCD10K(X)); \
HIDDEN(SYM##_bcs1 = BCD(X))
#define BCD(X) \
((X) == 0 \
? 0x20202030 \
: (X) < 10 ? 0x30202020 + (((X) % 10) << 24) \
: (X) < 100 ? 0x30302020 + (((X) % 10) << 24) + \
(((X) / 10 % 10) << 16) \
: (X) < 1000 ? 0x30303020 + (((X) % 10) << 24) + \
(((X) / 10 % 10) << 16) + \
(((X) / 100 % 10) << 8) \
: 0x30303030 + (((X) % 10) << 24) + \
(((X) / 10 % 10) << 16) + \
(((X) / 100 % 10) << 8) + \
(((X) / 1000 % 10) << 0))
#define BCD10K(X) \
((X) < 10000 \
? 0x20202020 \
: (X) < 100000 \
? 0x30202020 + (((X) / 10000 % 10) << 24) \
: (X) < 1000000 \
? 0x30302020 + (((X) / 10000 % 10) << 24) + \
(((X) / 100000 % 10) << 16) \
: (X) < 10000000 \
? 0x30303020 + (((X) / 10000 % 10) << 24) + \
(((X) / 100000 % 10) << 16) + \
(((X) / 1000000 % 10) << 8) \
: (X) < 100000000 \
? 0x30303030 + (((X) / 10000 % 10) << 24) + \
(((X) / 100000 % 10) << 16) + \
(((X) / 1000000 % 10) << 8) + \
(((X) / 10000000 % 10) << 0) \
: 0xffffffffffffffff)
#endif /* __ASSEMBLER__ */
#endif /* APE_MACROS_H_ */

View file

@ -1 +0,0 @@
#include "ape/ape.lds"

View file

@ -36,8 +36,8 @@
*/
#define REAL(x) ((x) - (IMAGE_BASE_VIRTUAL - IMAGE_BASE_REAL))
#if IMAGE_BASE_VIRTUAL % 0x1000 != 0
#error "IMAGE_BASE_VIRTUAL must be 4kb aligned"
#if IMAGE_BASE_VIRTUAL % 0x200000 != 0
#error "IMAGE_BASE_VIRTUAL must be 2mb aligned"
#endif
#if IMAGE_BASE_PHYSICAL % 0x1000 != 0
#error "IMAGE_BASE_PHYSICAL must be 4kb aligned"

View file

@ -1,32 +0,0 @@
#ifndef COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
#define COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_
COSMOPOLITAN_C_START_
extern const char __notices[] __attribute__((__weak__));
extern unsigned char __executable_start[] __attribute__((__weak__));
extern unsigned char __privileged_start[] __attribute__((__weak__));
extern unsigned char _ehead[] __attribute__((__weak__));
extern unsigned char _etext[] __attribute__((__weak__));
extern unsigned char _edata[] __attribute__((__weak__));
extern unsigned char _ezip[] __attribute__((__weak__));
extern unsigned char _end[] __attribute__((__weak__));
extern unsigned char _ereal[] __attribute__((__weak__));
extern unsigned char _tdata_start[] __attribute__((__weak__));
extern unsigned char _tdata_end[] __attribute__((__weak__));
extern unsigned char _tbss_start[] __attribute__((__weak__));
extern unsigned char _tbss_end[] __attribute__((__weak__));
extern unsigned char _tls_align[] __attribute__((__weak__));
extern unsigned char _tdata_align[] __attribute__((__weak__));
extern unsigned char _tbss_align[] __attribute__((__weak__));
extern unsigned char __test_start[] __attribute__((__weak__));
extern unsigned char __ro[] __attribute__((__weak__));
extern unsigned char __data_start[] __attribute__((__weak__));
extern unsigned char __data_end[] __attribute__((__weak__));
extern unsigned char __bss_start[] __attribute__((__weak__));
extern unsigned char __bss_end[] __attribute__((__weak__));
extern unsigned long __got_start[] __attribute__((__weak__));
extern unsigned long __got_end[] __attribute__((__weak__));
extern unsigned char ape_phdrs[] __attribute__((__weak__));
COSMOPOLITAN_C_END_
#endif /* COSMOPOLITAN_APE_SECTIONS_INTERNAL_H_ */

View file

@ -1,703 +0,0 @@
# Actually Portable Executable Specification v0.1
Actually Portable Executable (APE) is an executable file format that
polyglots the Windows Portable Executable (PE) format with a UNIX Sixth
Edition style shell script that doesn't have a shebang. This makes it
possible to produce a single file binary that executes on the stock
installations of the many OSes and architectures.
## Supported OSes and Architectures
- AMD64
- Linux
- MacOS
- Windows
- FreeBSD
- OpenBSD
- NetBSD
- BIOS
- ARM64
- Linux
- MacOS
- FreeBSD
- Windows (non-native)
## File Header
APE defines three separate file magics, all of which are 8 characters
long. Any file that starts with one of these magic values can be
considered an APE program.
### (1) APE MZ Magic
- ASCII: `MZqFpD='`
- Hex: 4d 5a 71 46 70 44 3d 27
This is the canonical magic used by almost all APE programs. It enables
maximum portability between OSes. When interpreted as a shell script, it
is assigning a single quoted string to an unused variable. The shell
will then ignore subsequent binary content that's placed inside the
string.
It is strongly recommended that this magic value be immediately followed
by a newline (\n or hex 0a) character. Some shells, e.g. FreeBSD SH and
Zsh impose a binary safety check before handing off files that don't
have a shebang to `/bin/sh`. That check applies to the first line, which
can't contain NUL characters.
The letters were carefully chosen so as to be valid x86 instructions in
all operating modes. This makes it possible to store a BIOS bootloader
disk image inside an APE binary. For example, simple CLI programs built
with Cosmopolitan Libc will boot from BIOS into long mode if they're
treated as a floppy disk image.
The letters also allow for the possibility of being treated on x86-64 as
a flat executable, where the PE / ELF / Mach-O executable structures are
ignored, and execution simply begins at the beginning of the file,
similar to how MS-DOS .COM binaries work.
The 0x4a relative offset of the magic causes execution to jump into the
MS-DOS stub defined by Portable Executable. APE binaries built by Cosmo
Libc use tricks in the MS-DOS stub to check the operating mode and then
jump to the appropriate entrypoint, e.g. `_start()`.
#### Decoded as i8086
```asm
dec %bp
pop %dx
jno 0x4a
jo 0x4a
```
#### Decoded as i386
```asm
push %ebp
pop %edx
jno 0x4a
jo 0x4a
```
#### Decoded as x86-64
```asm
rex.WRB
pop %r10
jno 0x4a
jo 0x4a
```
### (2) APE UNIX-Only Magic
- ASCII: `jartsr='`
- Hex: 6a 61 72 74 73 72 3d 27
Being a novel executable format that was first published in 2020, the
APE file format is less understood by industry tools compared to the PE,
ELF, and Mach-O executable file formats, which have been around for
decades. For this reason, APE programs that use the MZ magic above can
attract attention from Windows AV software, which may be unwanted by
developers who aren't interested in targeting the Windows platform.
Therefore the `jartsr='` magic is defined which enables the creation of
APE binaries that can safely target all non-Windows platforms. Even
though this magic is less common, APE interpreters and binfmt-misc
installations MUST support this.
It is strongly recommended that this magic value be immediately followed
by a newline (\n or hex 0a) character. Some shells, e.g. FreeBSD SH and
Zsh impose a binary safety check before handing off files that don't
have a shebang to `/bin/sh`. That check applies to the first line, which
can't contain NUL characters.
The letters were carefully chosen so as to be valid x86 instructions in
all operating modes. This makes it possible to store a BIOS bootloader
disk image inside an APE binary. For example, simple CLI programs built
with Cosmopolitan Libc will boot from BIOS into long mode if they're
treated as a floppy disk image.
The letters also allow for the possibility of being treated on x86-64 as
a flat executable, where the PE / ELF / Mach-O executable structures are
ignored, and execution simply begins at the beginning of the file,
similar to how MS-DOS .COM binaries work.
The 0x78 relative offset of the magic causes execution to jump into the
MS-DOS stub defined by Portable Executable. APE binaries built by Cosmo
Libc use tricks in the MS-DOS stub to check the operating mode and then
jump to the appropriate entrypoint, e.g. `_start()`.
#### Decoded as i8086 / i386 / x86-64
```asm
push $0x61
jb 0x78
jae 0x78
```
### (3) APE Debug Magic
- ASCII: `APEDBG='`
- Hex: 41 50 45 44 42 47 3d 27
While APE files must be valid shell scripts, in practice, UNIX systems
will oftentimes be configured to provide a faster safer alternative to
loading an APE binary through `/bin/sh`. The Linux Kernel can be patched
to have execve() recognize the APE format and directly load its embedded
ELF header. Linux systems can also use binfmt-misc to recognize APE's MZ
and jartsr magic, and pass them to a userspace program named `ape` that
acts as an interpreter. In such environments, the need sometimes arises
to be able to test that the `/bin/sh` is working correctly, in which
case the `APEDBG='` magic is RECOMMENDED.
APE interpreters, execve() implementations, and binfmt-misc installs
MUST ignore this magic. If necessary, steps can be taken to help files
with this magic be passed to `/bin/sh` like a normal shebang-less shell
script for execution.
## Embedded ELF Header
APE binaries MAY embed an ELF header inside them. Unlike conventional
executable file formats, this header is not stored at a fixed offset.
It's instead encoded as octal escape codes in a shell script `printf`
statement. For example:
```
printf '\177ELF\2\1\1\011\0\0\0\0\0\0\0\0\2\0\076\0\1\0\0\0\166\105\100\000\000\000\000\000\060\013\000\000\000\000\000\000\000\000\000\000\000\000\000\000\165\312\1\1\100\0\070\0\005\000\0\0\000\000\000\000'
```
This `printf` statement MUST appear in the first 8192 bytes of the APE
executable, so as to limit how much of the initial portion of a file an
interpreter must load.
Multiple such `printf` statements MAY appear in the first 8192 bytes, in
order to specify multiple architectures. For example, fat binaries built
by the `apelink` program (provided by Cosmo Libc) will have two encoded
ELF headers, for AMD64 and ARM64, each of which point into the proper
file offsets for their respective native code. Therefore, kernels and
interpreters which load the APE format directly MUST check the
`e_machine` field of the `Elf64_Ehdr` that's decoded from the octal
codes, before accepting a `printf` shell statement as valid.
These printf statements MUST always use only unescaped ASCII characters
or octal escape codes. These printf statements MUST NOT use space saving
escape codes such as `\n`. For example, rather than saying `\n` it would
be valid to say `\012` instead. It's also valid to say `\12` but only if
the encoded characters that follow aren't an octal digit.
For example, the following algorithm may be used for parsing octal:
```c
static int ape_parse_octal(const unsigned char page[8192], int i, int *pc)
{
int c;
if ('0' <= page[i] && page[i] <= '7') {
c = page[i++] - '0';
if ('0' <= page[i] && page[i] <= '7') {
c *= 8;
c += page[i++] - '0';
if ('0' <= page[i] && page[i] <= '7') {
c *= 8;
c += page[i++] - '0';
}
}
*pc = c;
}
return i;
}
```
APE aware interpreters SHOULD only take `e_machine` into consideration.
It is the responsibility of the `_start()` function to detect the OS.
Therefore, multiple `printf` statements are only embedded in the shell
script for different CPU architectures.
The OS ABI field of an APE embedded `Elf64_Ehdr` SHOULD be set to
`ELFOSABI_FREEBSD`, since it's the only UNIX OS APE supports that
actually checks the field. However different values MAY be chosen for
binaries that don't intend to have FreeBSD in their support vector.
Counter-intuitively, the ARM64 ELF header is used on the MacOS ARM64
platform when loading from fat binaries.
## Embedded Mach-O Header (x86-64 only)
APE shell scripts that support MacOS on AMD64 must use the `dd` command
in a very specific way to specify how the embedded binary Macho-O header
is copied backward to the start of the file. For example:
```
dd if="$o" of="$o" bs=8 skip=433 count=66 conv=notrunc
```
These `dd` statements have traditionally been generated by the GNU as
and ld.bfd programs by encoding ASCII into 64-bit linker relocations,
which necessitated a fixed width for integer values. It took several
iterations over APE's history before we eventually got it right:
- `arg=" 9293"` is how we originally had ape do it
- `arg=$(( 9293))` b/c busybox sh disliked quoted space
- `arg=9293 ` is generated by modern apelink program
Software that parses the APE file format, which needs to extract the
Macho-O x86-64 header SHOULD support the old binaries that use the
previous encodings. To make backwards compatibility simple the following
regular expression may be used, which generalizes to all defined
formats:
```c
regcomp(&rx,
"bs=" // dd block size arg
"(['\"] *)?" // #1 optional quote w/ space
"(\\$\\(\\( *)?" // #2 optional math w/ space
"([[:digit:]]+)" // #3
"( *\\)\\))?" // #4 optional math w/ space
"( *['\"])?" // #5 optional quote w/ space
" +" //
"skip=" // dd skip arg
"(['\"] *)?" // #6 optional quote w/ space
"(\\$\\(\\( *)?" // #7 optional math w/ space
"([[:digit:]]+)" // #8
"( *\\)\\))?" // #9 optional math w/ space
"( *['\"])?" // #10 optional quote w/ space
" +" //
"count=" // dd count arg
"(['\"] *)?" // #11 optional quote w/ space
"(\\$\\(\\( *)?" // #12 optional math w/ space
"([[:digit:]]+)", // #13
REG_EXTENDED);
```
For further details, see the canonical implementation in
`cosmopolitan/tool/build/assimilate.c`.
## Static Linking
Actually Portable Executables are always statically linked. This
revision of the specification does not define any facility for storing
code in dynamic shared objects.
Cosmopolitan Libc provides a solution that enables APE binaries have
limited access to dlopen(). By manually loading a platform-specific
executable and asking the OS-specific libc's dlopen() to load
OS-specific libraries, it becomes possible to use GPUs and GUIs. This
has worked great for AI projects like llamafile.
There is no way for an Actually Portable Executable to interact with
OS-specific dynamic shared object extension modules to programming
languages. For example, a Lua interpreter compiled as an Actually
Portable Executable would have no way of linking extension libraries
downloaded from the Lua Rocks package manager. This is primarily because
different OSes define incompatible ABIs.
While it was possible to polyglot PE+ELF+MachO to create multi-OS
executables, it simply isn't possible to do that same thing for
DLL+DYLIB+SO. Therefore, in order to have DSOs, APE would need to either
choose one of the existing formats or invent one of its own, and then
develop its own parallel ecosystem of extension software. In the future,
the APE specification may expand to encompass this. However the focus to
date has been exclusively on executables with limited dlopen() support.
## Application Binary Interface (ABI)
APE binaries use the System V ABI, as defined by:
- [System V ABI - AMD64 Architecture Processor Supplement](https://gitlab.com/x86-psABIs/x86-64-ABI)
- AARCH64 has a uniform consensus defined by ARM Limited
There are however a few changes we've had to make.
### No Red Zone
Actually Portable Executables that have Windows and/or bare metal in
their support vector MUST be compiled using `-mno-red-zone`. This is
because, on Windows, DLLs and other software lurking in the va-space
might use tricks like SetThreadContext() to take control of a thread
whereas on bare metal, it's also generally accepted that kernel-mode
code cannot assume a red zone either due to hardware interrupts that
pull the exact same kinds of stunts.
APE software that only has truly System V ABI conformant OSes (e.g.
Linux) in their support vector MAY use the red zone optimization.
### Thread Local Storage
#### aarch64
Here's the TLS memory layout on aarch64:
```
x28
%tpidr_el0
│ _Thread_local
┌───┼───┬──────────┬──────────┐
│tib│dtv│ .tdata │ .tbss │
├───┴───┴──────────┴──────────┘
__get_tls()
```
The ARM64 code in actually portable executables use the `x28` register
to store the address of the thread information block. All aarch64 code
linked into these executables SHOULD be compiled with `-ffixed-x28`
which is supported by both Clang and GCC.
The runtime library for an actually portable executables MAY choose to
use `tpidr_el0` instead, if OSes like MacOS aren't being targeted. For
example, if the goal is to create a Linux-only fat binary linker program
for Musl Libc, then choosing to use the existing `tpidr_el0` convention
would be friction-free alternative.
It's not possible for an APE runtime that targets the full range of OSes
to use the `tpidr_el0` register for TLS because Apple won't allow it. On
MacOS ARM64 systems, this register can only be used by a runtime to
implement the `sched_getcpu()` system call. It's reserved by MacOS.
#### x86-64
Here's the TLS memory layout on x86_64:
```
__get_tls()
%fs OpenBSD/NetBSD
_Thread_local │
┌───┬──────────┬──────────┼───┐
│pad│ .tdata │ .tbss │tib│
└───┴──────────┴──────────┼───┘
Linux/FreeBSD/Windows/Mac %gs
```
Quite possibly the greatest challenge in Actually Portable Executable
working, has been overcoming the incompatibilities between OSes in how
thread-local storage works on x86-64. The AMD64 architecture defines two
special segment registers. Every OS uses one of these segment registers
to implement TLS support. However not all OSes agree on which register
to use. Some OSes grant userspace the power to define either of these
registers to hold any value that is desired. Some OSes only effectively
allow a single one of them to be changed. Lastly, some OSes, e.g.
Windows, claim ownership of the memory layout these registers point
towards too.
Here's a breakdown on how much power is granted to userspace runtimes by
each OS when it comes to changing amd64 segment registers.
| | %fs | %gs |
|---------|--------------|--------------|
| Linux | unrestricted | unrestricted |
| MacOS | inaccessible | unrestricted |
| Windows | inaccessible | restricted |
| FreeBSD | unrestricted | unrestricted |
| NetBSD | unrestricted | broken |
| OpenBSD | unrestricted | inaccessible |
Therefore, regardless of which register one we choose, some OSes are
going to be incompatible.
APE binaries are always built with a Linux compiler. So another issue
arises in the fact that our Linux-flavored GCC and Clang toolchains
(which are used to produce cross-OS binaries) are also only capable of
producing TLS instructions that use the %fs convention.
To solve these challenges, the `cosmocc` compiler will rewrite binary
objects after they've been compiled by GCC, so that the `%gs` register
is used, rather than `%fs`. Morphing x86-64 binaries after they've been
compiled is normally difficult, due to the complexity of the machine
instruction language. However GCC provides `-mno-tls-direct-seg-refs`
which greatly reduces the complexity of this task. This flag forgoes
some optimizations to make the generated code simpler. Rather than doing
clever arithmetic with `%fs` prefixes, the compiler will always generate
the thread information block address load as a separate instruction.
```c
// Change AMD code to use %gs:0x30 instead of %fs:0
// We assume -mno-tls-direct-seg-refs has been used
static void ChangeTlsFsToGs(unsigned char *p, size_t n) {
unsigned char *e = p + n - 9;
while (p <= e) {
// we're checking for the following expression:
// 0144 == p[0] && // %fs
// 0110 == (p[1] & 0373) && // rex.w (and ignore rex.r)
// (0213 == p[2] || // mov reg/mem → reg (word-sized)
// 0003 == p[2]) && // add reg/mem → reg (word-sized)
// 0004 == (p[3] & 0307) && // mod/rm (4,reg,0) means sib → reg
// 0045 == p[4] && // sib (5,4,0) → (rbp,rsp,0) → disp32
// 0000 == p[5] && // displacement (von Neumann endian)
// 0000 == p[6] && // displacement
// 0000 == p[7] && // displacement
// 0000 == p[8] // displacement
uint64_t w = READ64LE(p) & READ64LE("\377\373\377\307\377\377\377\377");
if ((w == READ64LE("\144\110\213\004\045\000\000\000") ||
w == READ64LE("\144\110\003\004\045\000\000\000")) &&
!p[8]) {
p[0] = 0145; // change %fs to %gs
p[5] = 0x30; // change 0 to 0x30
p += 9;
} else {
++p;
}
}
}
```
By favoring `%gs` we've now ensured friction-free compatibility for the
APE runtime on MacOS, Linux, and FreeBSD which are all able to conform
easily to this convention. However additional work needs to be done at
runtime when an APE program is started on Windows, OpenBSD, and NetBSD.
On these platforms, all executable pages must be faulted and morphed to
fixup the TLS instructions.
On OpenBSD and NetBSD, this is as simple as undoing the example
operation above. Earlier at compile-time we turned `%fs` into `%gs`.
Now, at runtime, `%gs` must be turned back into `%fs`. Since the
executable is morphing itself, this is easier said than done.
OpenBSD for example enforces a `W^X` invariant. Code that's executing
can't modify itself at the same time. The way Cosmopolitan solves this
is by defining a special part of the binary called `.text.privileged`.
This section is aligned to page boundaries. A GNU ld linker script is
used to ensure that code which morphs code is placed into this section,
through the use of a header-defined cosmo-specific keyword `privileged`.
Additionally, the `fixupobj` program is used by the Cosmo build system
to ensure that compiled objects don't contain privileged functions that
call non-privileged functions. Needless to say, `mprotect()` needs to be
a privileged function, so that it can be used to disable the execute bit
on all other parts of the executable except for the privileged section,
thereby making it writable. Once this has been done, code can change.
On Windows the displacement bytes of the TLS instruction are changed to
use the `%gs:0x1480+i*8` ABI where `i` is a number assigned by the WIN32
`TlsAlloc()` API. This avoids the need to call `TlsGetValue()` which is
implemented this exact same way under the hood. Even though 0x1480 isn't
explicitly documented by MSDN, this ABI is believed to be stable because
MSVC generates binaries that use this offset directly. The only caveat
is that `TlsAlloc()` must be called as early in the runtime init as
possible, to ensure an index less than 64 is returned.
### Thread Information Block (TIB)
The Actually Portable Executable Thread Information Block (TIB) is
defined by this version of the specification as follows:
- The 64-bit TIB self-pointer is stored at offset 0x00.
- The 64-bit TIB self-pointer is also stored at offset 0x30.
- The 32-bit `errno` value is stored at offset 0x3c.
All other parts of the thread information block should be considered
unspecified and therefore reserved for future specifications.
The APE thread information block is aligned on a 64-byte boundary.
Cosmopolitan Libc v3.5.8 (c. 2024-07-21) currently implements a thread
information block that's 512 bytes in size.
### Foreign Function Calls
Even though APE programs always use the System V ABI, there arises the
occasional need to interface with foreign functions, e.g. WIN32. The
`__attribute__((__ms_abi__))` annotation introduced by GCC v6 is used
for this purpose.
The ability to change a function's ABI on a case-by-case basis is
surprisingly enough supported by GCC, Clang, NVCC, and even the AMD HIP
compilers for both UNIX systems and Windows. All of these compilers
support both the System V ABI and the Microsoft x64 ABI.
APE binaries will actually favor the Microsoft ABI even when running on
UNIX OSes for certain dlopen() use-cases. For example, if we control the
code to a CUDA module, which we compile on each OS separately from our
main APE binary, then any function that's inside the APE binary whose
pointer may be passed into a foreign module SHOULD be compiled to use
the Microsoft ABI. This is because in practice the OS-specific module
may need to be compiled by MSVC, where MS ABI is the *only* ABI, which
forces our UNIX programs to partially conform. Thankfully, all UNIX
compilers support doing it on a case-by-case basis.
### Char Signedness
Actually Portable Executable defines `char` as signed.
Therefore conformant APE software MUST use `-fsigned-char` when building
code for aarch64, as well as any other architecture that (unlike x86-64)
would otherwise define `char` as being `unsigned char` by default.
This decision was one of the cases where it made sense to offer a more
consistent runtime experience for fat multi-arch binaries. However you
SHOULD still write code to assume `char` can go either way. But if all
you care about is using APE, then you CAN assume `char` is signed.
### Long Double
On AMD64 platforms, APE binaries define `long double` as 80-bit.
On ARM64 platforms, APE binaries define `long double` as 128-bit.
We accept inconsistency in this case, because hardware acceleration is
far more valuable than stylistic consistency in the case of mathematics.
One challenge arises on AMD64 for supporting `long double` across OSes.
Unlike UNIX systems, the Windows Executive on x86-64 initializes the x87
FPU to have double (64-bit) precision rather than 80-bit. That's because
code compiled by MSVC treats `long double` as though it were `double` to
prefer always using the more modern SSE instructions. However System V
requires genuine 80-bit `long double` support on AMD64.
Therefore, if an APE program detects that it's been started on a Windows
x86-64 system, then it SHOULD use the following assembly to initialize
the x87 FPU in System V ABI mode.
```asm
fldcw 1f(%rip)
.rodata
.balign 2
// 8087 FPU Control Word
// IM: Invalid Operation ───────────────┐
// DM: Denormal Operand ───────────────┐│
// ZM: Zero Divide ───────────────────┐││
// OM: Overflow ─────────────────────┐│││
// UM: Underflow ───────────────────┐││││
// PM: Precision ──────────────────┐│││││
// PC: Precision Control ───────┐ ││││││
// {float,∅,double,long double}│ ││││││
// RC: Rounding Control ──────┐ │ ││││││
// {even, →-∞, →+∞, →0} │┌┤ ││││││
// ┌┤││ ││││││
// d││││rr││││││
1: .short 0b00000000000000000001101111111
.previous
```
## Executable File Alignment
Actually Portable Executable is a statically-linked flat executable file
format that is, as a thing in itself, agnostic to file alignments. For
example, the shell script payload at the beginning of the file and its
statements have no such requirements. Alignment requirements are however
imposed by the executable formats that APE wraps.
1. ELF requires that file offsets be congruent with virtual addresses
modulo the CPU page size. So when we add a shell script to the start
of an executable, we need to round up to the page size in order to
maintain ELF's invariant. Although no such roundup is required on the
program segments once the invariant is restored. ELF loaders will
happily map program headers from arbitrary file intervals (which may
overlap) onto arbitrarily virtual intervals (which don't need to be
contiguous). In order to do that, the loaders will generally use
UNIX's mmap() function which is more restrictive and only accepts
addresses and offsets that are page aligned. To make it possible to
map an unaligned ELF program header that could potentially start and
stop at any byte, ELF loaders round-out the intervals, which means
adjacent unrelated data might also get mapped, which may need to be
explicitly zero'd. Thanks to the cleverness of ELF, it's possible to
have an executable file be very tiny, without needing any alignment
bytes, and it'll be loaded into a properly aligned virtual space
where segments can be as sparse as we want them to be.
2. PE doesn't care about congruence and instead defines two separate
kinds of alignment. First, PE requires that the layout of segment
memory inside the file be aligned on at minimum the classic 512 byte
MS-DOS page size. This means that, unlike ELF, some alignment padding
may need to be encoded into the file, making it slightly larger. Next
PE imposes an alignment restriction on segments once they've been
mapped into the virtual address space, which must be rounded to the
system page size. Like ELF, PE segments need to be properly ordered
but they're allowed to drift apart once mapped in a non-contiguous
sparsely mapped way. When inserting shell script content at the start
of a PE file, the most problematic thing is the need to round up to
the 64kb system granularity, which results in a lot of needless bytes
of padding being inserted by a naive second-pass linker.
3. Apple's Mach-O format is the strictest of them all. While both ELF
and PE are defined in such a way that invites great creativity, XNU
will simply refuse to an executable that does anything creative with
alignment. All loaded segments need to both start and end on a page
aligned address. XNU also wants segments to be contiguous similar to
portable executable, except it applies to both the file and virtual
spaces, which must follow the same structure.
Actually Portable Executables must conform to the strictest requirements
demanded by the support vector. Therefore an APE binary that has headers
for all three of the above executable formats MUST conform to the Apple
way of doing things. GNU ld linker scripts aren't very good at producing
ELF binaries that rigidly conform to this simple naive layout. There are
so many ways things can go wrong, where third party code might slip its
own custom section name in-between the linker script sections that are
explicitly defined, thereby causing ELF's powerful features to manifest
and the resulting content overlapping. The best `ld` flag that helps is
`--orphan-handling=error` which can help with explaining such mysteries.
While Cosmopolitan was originally defined to just use stock GNU tools,
this proved intractable over time, and the project has been evolving in
the direction of building its own. Inventing the `apelink` program was
what enabled the project to achieve multi-architecture binaries whereas
previously it was only possible to do multi-OS binaries. In the future,
our hope is that a fast power linker like Mold can be adapted to produce
fat APE binaries directly from object files in one pass.
## Position Independent Code
APE doesn't currently support position independent executable formats.
This is because APE was originally written for the GNU linker, where PIC
and PIE were after-thoughts and never fully incorporated with the older
more powerful linker script techniques upon which APE relies. Future
iterations of this specification are intended to converge on modern
standards, as our tooling becomes developed enough to support it.
However this only applies to the wrapped executable formats themselves.
While our convention to date has been to always load ELF programs at the
4mb mark, this is not guaranteed across OSes and architectures. Programs
should have no expectations that a program will be loaded to any given
address. For example, Cosmo currently implements APE on AARCH64 as
loading executables to a starting address of 0x000800000000. This
address occupies a sweet spot of requirements.
## Address Space
In order to create a single binary that supports as many platforms as
possible without needing to be recompiled, there's a very narrow range
of addresses that can be used. That range is somewhere between 32 bits
and 39 bits.
- Embedded devices that claim to be 64-bit will oftentimes only support
a virtual address space that's 39 bits in size.
- We can't load executable images on AARCH64 beneath 0x100000000 (4gb)
because Apple forbids doing that, possibly in an effort to enforce a
best practice for spotting 32-bit to 64-bit transition bugs. Please
note that this restriction only applies to Apple ARM64 systems. The
x86-64 version of XNU will happily load APE binaries to 0x00400000.
- The AMD64 architecture on desktops and servers can usually be counted
upon to provide a 47-bit address space. The Linux Kernel for instance
grants each userspace program full dominion over addresses 0x00200000
through 0x00007fffffffffff provided the hardware supports this. On
modern workstations supporting Intel and AMD's new PML5T feature which
virtualizes memory using a radix trie that's five layers deep, Linux
is able to offer userspace its choice of fixed addresses from
0x00200000 through 0x00ffffffffffffff. The only exception to this rule
we've encountered so far is that Windows 7 and Windows Vista behaved
similar to embedded devices in reducing the number of va bits.
## Page Size
APE software MUST be page size agnostic. For many years the industry had
converged on a strong consensus of having a page size that's 4096 bytes.
However this convention was never guaranteed. New computers have become
extremely popular, such as Apple Silicon, that use a 16kb page size.
By convention, Cosmopolitan Libc currently generates ELF headers for
x86-64 that are strictly aligned on a 4096-byte page size. On ARM64
Cosmopolitan is currently implemented to always generate ELF headers
aligned on a 16kb page size.
In addition to being page size agnostic, APE software that cares about
working correctly on Windows needs to be aware of the concept of
allocation granularity. While the page size on Windows is generally 4kb
in size, memory mappings can only be created on addresses that aligned
to the system allocation granularity, which is generally 64kb. If you
use a function like mmap() with Cosmopolitan Libc, then the `addr` and
`offset` parameters need to be aligned to `sysconf(_SC_GRANSIZE)` or
else your software won't work on Windows. Windows has other limitations
too, such as lacking the ability to carve or punch holes in mappings.

View file

@ -1,74 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
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
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/dce.h"
#include "ape/ape.h"
#include "libc/macros.h"
#ifdef __aarch64__
_start: mov x1,sp
and sp,x1,#-16
mov x29,0
bl ApeLoader
.endfn _start,globl
#else
XnuEntrypoint:
mov $_HOSTXNU,%dl // xnu's not unix!
ElfEntrypoint:
mov %rsp,%rsi // save real stack
andq $-16,%rsp // force SSE alignment
call ApeLoader
.endfn ElfEntrypoint,globl
.endfn XnuEntrypoint,globl
.section .note,"a",@progbits
.balign 4
openbsd.ident:
.long 2f-1f
.long 4f-3f
.long 1
1: .asciz "OpenBSD"
2: .balign 4
3: .long 0
4: .size openbsd.ident,.-openbsd.ident
.type openbsd.ident,@object
.balign 4
netbsd.ident:
.long 2f-1f
.long 4f-3f
.long 1
1: .asciz "NetBSD"
2: .balign 4
3: .long 901000000
4: .size netbsd.ident,.-netbsd.ident
.type netbsd.ident,@object
.balign 4
ape.ident:
.long 2f-1f
.long 4f-3f
.long 1
1: .asciz "APE"
2: .balign 4
3: .long APE_VERSION_NOTE
4: .size ape.ident,.-ape.ident
.type ape.ident,@object
#endif

View file

@ -1,49 +0,0 @@
/*-*- mode:unix-assembly; indent-tabs-mode:t; tab-width:8; coding:utf-8 -*-│
vi: set noet ft=asm ts=8 sw=8 fenc=utf-8 :vi
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
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/macros.h"
// Invokes system call.
//
// This function has eight parameters. The first seven are for
// arguments passed along to the system call. The eight is for
// the magic number that indicates which system call is called
//
// The return value follows the Linux kernel convention, where
// errors are returned as `-errno`. BSD systems are normalized
// to follow this convention automatically.
SystemCall:
#ifdef __aarch64__
mov x8,x7
mov x9,0
adds x9,x9,0
svc 0
bcs 1f
ret
1: neg x0,x0
ret
#else
mov %rcx,%r10
mov 16(%rsp),%eax
clc
syscall
jnc 1f
neg %rax
1: ret
#endif
.endfn SystemCall,globl

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
build/bootstrap/ar.com Executable file

Binary file not shown.

Binary file not shown.

BIN
build/bootstrap/cocmd.com Executable file

Binary file not shown.

BIN
build/bootstrap/compile.com Executable file

Binary file not shown.

BIN
build/bootstrap/cp.com Executable file

Binary file not shown.

BIN
build/bootstrap/echo.com Executable file

Binary file not shown.

BIN
build/bootstrap/fixupobj.com Executable file

Binary file not shown.

View file

@ -1,58 +0,0 @@
--nocompress-debug-sections
--noexecstack
-Wa,--nocompress-debug-sections
-Wa,--noexecstack
-Wa,-msse2avx
-Werror=maybe-uninitialized
-Wno-literal-suffix
-Wno-unused-but-set-variable
-Wunsafe-loop-optimizations
-fbranch-target-load-optimize
-fcx-limited-range
-fdelete-dead-exceptions
-femit-struct-debug-baseonly
-ffp-int-builtin-inexact
-finline-functions-called-once
-fipa-pta
-fivopts
-flimit-function-alignment
-fmerge-constants
-fmodulo-sched
-fmodulo-sched-allow-regmoves
-fno-align-jumps
-fno-align-labels
-fno-align-loops
-fno-code-hoisting
-fno-cx-limited-range
-fno-fp-int-builtin-inexact
-fno-gnu-unique
-fno-inline-functions-called-once
-fno-instrument-functions
-fno-schedule-insns2
-fno-whole-program
-fopt-info-vec
-fopt-info-vec-missed
-freg-struct-return
-freschedule-modulo-scheduled-loops
-frounding-math
-fsched2-use-superblocks
-fschedule-insns
-fschedule-insns2
-fshrink-wrap
-fshrink-wrap-separate
-fsignaling-nans
-fstack-clash-protection
-ftracer
-ftrapv
-ftree-loop-im
-ftree-loop-vectorize
-funsafe-loop-optimizations
-fversion-loops-for-strides
-fwhole-program
-gdescribe-dies
-gstabs
-mcall-ms2sysv-xlogues
-mdispatch-scheduler
-mfpmath=sse+387
-mmitigate-rop
-mno-fentry

BIN
build/bootstrap/gzip.com Executable file

Binary file not shown.

BIN
build/bootstrap/make.com Executable file

Binary file not shown.

BIN
build/bootstrap/mkdeps.com Executable file

Binary file not shown.

BIN
build/bootstrap/mkdir.com Executable file

Binary file not shown.

BIN
build/bootstrap/package.com Executable file

Binary file not shown.

BIN
build/bootstrap/pwd.com Executable file

Binary file not shown.

BIN
build/bootstrap/rm.com Executable file

Binary file not shown.

BIN
build/bootstrap/touch.com Executable file

Binary file not shown.

BIN
build/bootstrap/unbundle.com Executable file

Binary file not shown.

BIN
build/bootstrap/zipobj.com Executable file

Binary file not shown.

View file

@ -1,68 +1,23 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set et ft=make ts=8 sw=8 fenc=utf-8 :vi ──────────────────────┘
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
# Default Mode
#
# - `make`
# - Optimized
# - Backtraces
# - Syscall tracing
# - Function tracing
#
# - Reasonably small
# - Reasonably optimized
# - Reasonably debuggable
ifeq ($(MODE),)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), x86_64)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += -O2 $(BACKTRACES)
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
# Zero Optimization Mode
#
# - Goes 2x slower
# - Supports --strace
# - Unsupports --ftrace
# - Better GDB debugging
#
ifeq ($(MODE), zero)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
ifeq ($(MODE), aarch64-zero)
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0 -fdce
OVERRIDE_CXXFLAGS += -O0 -fdce
CONFIG_CPPFLAGS += -DSYSDEBUG
endif
# Fast Build Mode
#
# - `make MODE=fastbuild`
# - No debugging
# - Syscall tracing
# - Function tracing
# - Some optimizations
# - Limited Backtraces
#
ifeq ($(MODE), fastbuild)
ENABLE_FTRACE = 1
CONFIG_CCFLAGS += $(BACKTRACES) -O
CONFIG_CPPFLAGS += -DSYSDEBUG -DDWARFLESS
CONFIG_LDFLAGS += -S
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-DSYSDEBUG \
-O2
TARGET_ARCH ?= \
-msse3
endif
# Optimized Mode
@ -76,17 +31,22 @@ endif
# - No memory corruption detection
# - assert() / CHECK_xx() may leak code into binary for debuggability
# - GCC 8+ hoists check fails into .text.cold, thus minimizing impact
#
ifeq ($(MODE), opt)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG
CONFIG_CCFLAGS += $(BACKTRACES) -O3 -fmerge-all-constants
CONFIG_TARGET_ARCH ?= -march=native
CONFIG_CPPFLAGS += \
-DNDEBUG \
-msse2avx \
-Wa,-msse2avx
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-DSYSDEBUG \
-O3 \
-fmerge-all-constants
TARGET_ARCH ?= \
-march=native
endif
# Optimized Linux Mode
# The Fastest Mode of All
#
# - `make MODE=optlinux`
# - Turns on red zone
@ -94,26 +54,18 @@ endif
# - Turns off function tracing
# - Turns off support for older cpu models
# - Turns off support for other operating systems
#
ifeq ($(MODE), optlinux)
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
CONFIG_TARGET_ARCH ?= -march=native
endif
ifeq ($(MODE), x86_64-optlinux)
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
CONFIG_TARGET_ARCH ?= -march=native
endif
ifeq ($(MODE), aarch64-optlinux)
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CPPFLAGS += -DNDEBUG -DSYSDEBUG -DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += -O3 -fmerge-all-constants
CONFIG_COPTS += -mred-zone
CONFIG_CPPFLAGS += \
-DNDEBUG \
-msse2avx \
-Wa,-msse2avx \
-DSUPPORT_VECTOR=1
CONFIG_CCFLAGS += \
-O3 -fmerge-all-constants
DEFAULT_COPTS += \
-mred-zone
TARGET_ARCH ?= \
-march=native
endif
# Release Mode
@ -124,76 +76,68 @@ endif
# - More optimized
# - Reasonably small
# - Numeric backtraces
# - No DWARF data bloat
# - Toilsome debuggability
# - assert() statements removed
# - DCHECK_xx() statements removed
# - No memory corruption detection
# - CHECK_xx() won't leak strings into binary
#
ifeq ($(MODE), rel)
CONFIG_CPPFLAGS += -DNDEBUG -DDWARFLESS
CONFIG_CCFLAGS += $(BACKTRACES) -O2
PYFLAGS += -O1
CONFIG_CPPFLAGS += \
-DNDEBUG
CONFIG_CCFLAGS += \
$(BACKTRACES) \
-O2
TARGET_ARCH ?= \
-msse3
PYFLAGS += \
-O1
endif
# Asan Mode
#
# Safer binaries good for backend production serving.
#
# - `make MODE=asan`
# - Memory safety
# - Production worthy
# - Backtraces
# - Debuggability
# - Larger binaries
ifeq ($(MODE), asan)
CONFIG_CCFLAGS += \
$(BACKTRACES) \
-O2
CONFIG_COPTS += \
-fsanitize=address
TARGET_ARCH ?= \
-msse3
endif
# Debug Mode
#
# - `make MODE=dbg`
# - Backtraces
# - Enables ubsan
# - Enables asan
# - Enables ubsan (TODO)
# - Stack canaries
# - No optimization
# - No optimization (TODO)
# - Enormous binaries
#
ifeq ($(MODE), dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
CONFIG_COPTS += -fsanitize=undefined
OVERRIDE_CCFLAGS += -fno-pie
QUOTA ?= -C64 -L300
endif
ifeq ($(MODE), x86_64-dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0
OVERRIDE_CXXFLAGS += -O0
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
CONFIG_COPTS += -fsanitize=undefined
OVERRIDE_CCFLAGS += -fno-pie
QUOTA ?= -C64 -L300
endif
ifeq ($(MODE), aarch64-dbg)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
OVERRIDE_CFLAGS += -O0 -fdce
OVERRIDE_CXXFLAGS += -O0 -fdce
CONFIG_CPPFLAGS += -DMODE_DBG -D__SANITIZE_UNDEFINED__ -Wno-unused-variable -Wno-unused-but-set-variable
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG
CONFIG_COPTS += -fsanitize=undefined
QUOTA ?= -C64 -L300
endif
# System Five Mode
#
# - `make MODE=sysv`
# - Optimized
# - Backtraces
# - Debuggable
# - Syscall tracing
# - Function tracing
# - No Windows bloat!
#
ifeq ($(MODE), sysv)
ENABLE_FTRACE = 1
CONFIG_OFLAGS ?= -g -ggdb
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DSUPPORT_VECTOR=121
CONFIG_CPPFLAGS += \
-DMODE_DBG
CONFIG_CCFLAGS += \
$(BACKTRACES) \
$(FTRACE) \
-DSYSDEBUG \
-O2 \
-fno-inline
CONFIG_COPTS += \
-fsanitize=address \
-fsanitize=undefined
TARGET_ARCH ?= \
-msse3
OVERRIDE_CCFLAGS += \
-fno-pie
endif
# Tiny Mode
@ -207,7 +151,6 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
#
ifeq ($(MODE), tiny)
CONFIG_CPPFLAGS += \
-DTINY \
@ -220,48 +163,11 @@ CONFIG_CCFLAGS += \
-fno-align-labels \
-fno-align-loops \
-fschedule-insns2 \
-fomit-frame-pointer \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls \
-DDWARFLESS
PYFLAGS += \
-O2 \
-B
endif
ifeq ($(MODE), x86_64-tiny)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops \
-fschedule-insns2 \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls \
-DDWARFLESS
PYFLAGS += \
-O2 \
-B
endif
ifeq ($(MODE), aarch64-tiny)
# TODO(jart): -mcmodel=tiny
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops \
-fschedule-insns2 \
-momit-leaf-frame-pointer \
-foptimize-sibling-calls \
-DDWARFLESS
-foptimize-sibling-calls
TARGET_ARCH ?= \
-msse3
PYFLAGS += \
-O2 \
-B
@ -279,20 +185,22 @@ endif
# - No portability
# - No algorithmics
# - YOLO
#
ifeq ($(MODE), tinylinux)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=1 \
-DDWARFLESS
-DSUPPORT_VECTOR=1
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
TARGET_ARCH ?= \
-msse3
endif
# Linux+BSD Tiny Mode
@ -308,20 +216,22 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
#
ifeq ($(MODE), tinylinuxbsd)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=113 \
-DDWARFLESS
-DSUPPORT_VECTOR=113
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
TARGET_ARCH ?= \
-msse3
endif
# Unix Tiny Mode
@ -336,20 +246,22 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
#
ifeq ($(MODE), tinysysv)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=121 \
-DDWARFLESS
-DSUPPORT_VECTOR=121
DEFAULT_COPTS += \
-mred-zone
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
TARGET_ARCH ?= \
-msse3
endif
# Tiny Metallic Unix Mode
@ -364,54 +276,26 @@ endif
# - No backtraces
# - No algorithmics
# - YOLO
#
ifeq ($(MODE), tinynowin)
CONFIG_CPPFLAGS += \
-DTINY \
-DNDEBUG \
-DTRUSTWORTHY \
-DSUPPORT_VECTOR=251 \
-DDWARFLESS
-DSUPPORT_VECTOR=251
CONFIG_CCFLAGS += \
-Os \
-fno-align-functions \
-fno-align-jumps \
-fno-align-labels \
-fno-align-loops
endif
# no x87 instructions mode
#
# export MODE=nox87
# make -j8 toolchain
# cosmocc -o /tmp/hello.com hello.c
#
# lets you shave ~23kb off blink
#
# git clone https://github.com/jart/blink
# cd blink
# ./configure --disable-x87
# make -j8
# o//blink/blink /tmp/hello.com
#
ifeq ($(MODE), nox87)
ENABLE_FTRACE = 1
CONFIG_COPTS += -mlong-double-64
CONFIG_CCFLAGS += $(BACKTRACES) -O2
CONFIG_CPPFLAGS += -DSYSDEBUG -DNOX87
TARGET_ARCH ?= \
-msse3
endif
# LLVM Mode
#
# We aim to support:
#
# make -j8 m=llvm o/llvm/libc
#
# The rest of the monorepo may not work with llvm.
#
ifeq ($(MODE), llvm)
.STRICT = 0
CONFIG_CCFLAGS += $(BACKTRACES) -DSYSDEBUG -O2
TARGET_ARCH ?= -msse3
CONFIG_CCFLAGS += $(BACKTRACES) $(FTRACE) -DSYSDEBUG -O2
AS = clang
CC = clang
CXX = clang++
@ -449,66 +333,12 @@ endif
# such as MSVC or XCode. You can run your binary objects through a tool
# like objconv to convert them to COFF or MachO. Then use ANSI mode to
# rollup one header file that'll enable linkage with minimal issues.
ifeq ($(MODE), ansi)
CONFIG_CFLAGS += -std=c11
#CONFIG_CPPFLAGS += -ansi
CONFIG_CXXFLAGS += -std=c++11
endif
TARGET_ARCH ?= -msse3
ifneq ($(ENABLE_FTRACE),)
CONFIG_CPPFLAGS += -DFTRACE
FTRACE_CCFLAGS = -fno-inline-functions-called-once
OVERRIDE_CFLAGS += $(FTRACE_CCFLAGS)
OVERRIDE_CXXFLAGS += $(FTRACE_CCFLAGS)
# function prologue nops for --ftrace
ifeq ($(ARCH), x86_64)
# this flag causes gcc to generate functions like this
#
# nop nop nop nop nop nop nop nop nop
# func:
# nop nop
# ...
#
# which tool/build/fixupobj.c improves at build time like this
#
# nop nop nop nop nop nop nop nop nop
# func:
# xchg %ax,%ax
# ...
#
# which --ftrace morphs at runtime like this
#
# ud2 # 2 bytes
# call ftrace_hook # 5 bytes
# jmp +2 # 2 bytes
# func:
# jmp -7 # 2 bytes
# ...
#
CONFIG_CCFLAGS += -fpatchable-function-entry=18,16
endif
ifeq ($(ARCH), aarch64)
# this flag causes gcc to generate functions like this
#
# nop nop nop nop nop nop
# func:
# nop
# ...
#
# which --ftrace morphs at runtime like this
#
# brk #31337
# stp x29,x30,[sp,#-16]!
# mov x29,sp
# bl ftrace_hook
# ldp x29,x30,[sp],#16
# b +1
# func:
# b -5
# ...
#
CONFIG_CCFLAGS += -fpatchable-function-entry=7,6
endif
endif
TARGET_ARCH ?= $(CONFIG_TARGET_ARCH)

View file

@ -1,5 +1,5 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set et ft=make ts=8 sw=8 fenc=utf-8 :vi ──────────────────────┘
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
@ -33,43 +33,98 @@
#
# VARIABLES
#
# Our configuration variables, ordered by increasing preference:
#
# CCFLAGS frontend flags (.i, .c, .cc, .f, .S, .lds, etc.)
# OFLAGS objectify flags (precludes -S and -E)
# CCFLAGS gcc frontend flags (.i, .c, .cc, .f, .S, .lds, etc.)
# CPPFLAGS preprocessor flags (.h, .c, .cc, .S, .inc, .lds, etc.)
# TARGET_ARCH microarchitecture flags (e.g. -march=native)
# COPTS c/c++ flags (.c, .cc)
# CFLAGS c flags (.c only)
# CXXFLAGS c++ flags (.cc only)
# COPTS c/c++ flags (.c, .cc)
# LDFLAGS linker flags (don't use -Wl, frontend prefix)
# ASFLAGS assembler flags (don't use -Wa, frontend prefix)
#
# For each FOO above, there exists (by increasing preference)
#
# DEFAULT_FOO see build/definitions.mk
# CONFIG_FOO see build/config.mk
# FOO set ~/.cosmo.mk and target-specific
# OVERRIDE_FOO set ~/.cosmo.mk and target-specific (use rarely)
#
# TARGET_ARCH microarchitecture flags (e.g. -march=native)
ifeq ($(LANDLOCKMAKE_VERSION),)
TMPSAFE = $(join $(TMPDIR)/,$(subst /,_,$@)).tmp
LC_ALL = C
SOURCE_DATE_EPOCH = 0
TAGS ?= /usr/bin/ctags # emacs source builds or something breaks it
ARFLAGS = rcsD
ZFLAGS ?=
XARGS ?= xargs -P4 -rs8000
DOT ?= dot
CLANG = clang
FC = gfortran #/opt/cross9f/bin/x86_64-linux-musl-gfortran
TMPDIR = o/tmp
AR = build/bootstrap/ar.com
CP = build/bootstrap/cp.com
RM = build/bootstrap/rm.com -f
ECHO = build/bootstrap/echo.com
TOUCH = build/bootstrap/touch.com
PKG = build/bootstrap/package.com
MKDEPS = build/bootstrap/mkdeps.com
ZIPOBJ = build/bootstrap/zipobj.com
FIXUPOBJ = build/bootstrap/fixupobj.com
MKDIR = build/bootstrap/mkdir.com -p
COMPILE = build/bootstrap/compile.com -V9 -P4096 $(QUOTA)
SYMTAB = $(TMPDIR)/$(subst /,_,$@).symtab
COMMA := ,
PWD := $(shell build/bootstrap/pwd.com)
IMAGE_BASE_VIRTUAL ?= 0x400000
IGNORE := $(shell $(ECHO) -2 ♥cosmo)
IGNORE := $(shell $(MKDIR) o/tmp)
ifneq ("$(wildcard o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe)","")
AS = o/third_party/gcc/bin/x86_64-pc-linux-gnu-as.exe
CC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
CXX = o/third_party/gcc/bin/x86_64-pc-linux-gnu-g++.exe
CXXFILT = o/third_party/gcc/bin/x86_64-pc-linux-gnu-c++filt.exe
LD = o/third_party/gcc/bin/x86_64-pc-linux-gnu-ld.bfd.exe
NM = o/third_party/gcc/bin/x86_64-pc-linux-gnu-nm.exe
GCC = o/third_party/gcc/bin/x86_64-pc-linux-gnu-gcc.exe
STRIP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-strip.exe
OBJCOPY = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objcopy.exe
OBJDUMP = o/third_party/gcc/bin/x86_64-pc-linux-gnu-objdump.exe
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-pc-linux-gnu-addr2line.exe
else
TMPSAFE = $(TMPDIR)/
IGNORE := $(shell build/bootstrap/unbundle.com)
AS = o/third_party/gcc/bin/x86_64-linux-musl-as
CC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
CXX = o/third_party/gcc/bin/x86_64-linux-musl-g++
CXXFILT = o/third_party/gcc/bin/x86_64-linux-musl-c++filt
LD = o/third_party/gcc/bin/x86_64-linux-musl-ld.bfd
NM = o/third_party/gcc/bin/x86_64-linux-musl-nm
GCC = o/third_party/gcc/bin/x86_64-linux-musl-gcc
STRIP = o/third_party/gcc/bin/x86_64-linux-musl-strip
OBJCOPY = o/third_party/gcc/bin/x86_64-linux-musl-objcopy
OBJDUMP = o/third_party/gcc/bin/x86_64-linux-musl-objdump
ADDR2LINE = $(PWD)/o/third_party/gcc/bin/x86_64-linux-musl-addr2line
endif
export ADDR2LINE
export LC_ALL
export MKDIR
export MODE
export SOURCE_DATE_EPOCH
export TMPDIR
FTRACE = \
-pg
BACKTRACES = \
-fno-schedule-insns2 \
-fno-omit-frame-pointer \
-fno-optimize-sibling-calls \
-mno-omit-leaf-frame-pointer
SANITIZER = \
-fsanitize=address
NO_MAGIC = \
-ffreestanding \
-mno-fentry \
-fno-stack-protector \
-fwrapv \
-fno-sanitize=all \
-fpatchable-function-entry=0,0
-fno-sanitize=all
OLD_CODE = \
-fno-strict-aliasing \
@ -80,99 +135,77 @@ TRADITIONAL = \
-Wno-return-type \
-Wno-pointer-sign
DEFAULT_CCFLAGS += \
DEFAULT_CCFLAGS = \
-Wall \
-Werror \
-fno-omit-frame-pointer \
-fdebug-prefix-map='$(PWD)'= \
-frecord-gcc-switches
DEFAULT_COPTS ?= \
DEFAULT_OFLAGS = \
-g \
-gdescribe-dies
DEFAULT_COPTS = \
-mno-red-zone \
-fno-math-errno \
-fno-trapping-math \
-fno-fp-int-builtin-inexact \
-fno-ident \
-fno-common \
-fno-gnu-unique \
-fstrict-aliasing \
-fstrict-overflow \
-fno-semantic-interposition
ifeq ($(ARCH), x86_64)
# Microsoft says "[a]ny memory below the stack beyond the red zone
# [note: Windows defines the x64 red zone size as 0] is considered
# volatile and may be modified by the operating system at any time."
# https://devblogs.microsoft.com/oldnewthing/20190111-00/?p=100685
DEFAULT_COPTS += \
-mno-red-zone \
-fno-semantic-interposition \
-mno-tls-direct-seg-refs
endif
ifeq ($(ARCH), aarch64)
#
# - Apple says in "Writing ARM64 code for Apple platforms" that we're
# not allowed to use the x18 register.
#
# - Cosmopolitan Libc uses x28 for thread-local storage because Apple
# forbids us from using tpidr_el0 too.
#
DEFAULT_COPTS += \
-ffixed-x18 \
-ffixed-x28 \
-fsigned-char
endif
MATHEMATICAL = \
-O3 \
-fwrapv
DEFAULT_CPPFLAGS += \
-D_COSMO_SOURCE \
DEFAULT_CPPFLAGS = \
-DCOSMO \
-DMODE='"$(MODE)"' \
-Wno-prio-ctor-dtor \
-Wno-unknown-pragmas \
-DIMAGE_BASE_VIRTUAL=$(IMAGE_BASE_VIRTUAL) \
-nostdinc \
-iquote. \
-isystem libc/isystem
-iquote .
DEFAULT_CFLAGS = \
-std=gnu23
-std=gnu2x
DEFAULT_CXXFLAGS = \
-std=gnu++23 \
-fno-rtti \
-fno-exceptions \
-fuse-cxa-atexit \
-fno-threadsafe-statics \
-Wno-int-in-bool-context \
-Wno-narrowing \
-Wno-literal-suffix \
-isystem third_party/libcxx
-Wno-literal-suffix
DEFAULT_ASFLAGS = \
-W \
-I. \
--noexecstack
--noexecstack \
--nocompress-debug-sections
DEFAULT_LDFLAGS = \
-static \
-nostdlib \
-znorelro \
-melf_x86_64 \
--gc-sections \
-z noexecstack \
--build-id=none \
--no-dynamic-linker
--no-dynamic-linker \
-zmax-page-size=0x1000 #--cref -Map=$@.map
# # generate linker report files
# DEFAULT_LDFLAGS += --cref -Map=$@.map
ZIPOBJ_FLAGS = \
-b$(IMAGE_BASE_VIRTUAL)
ifeq ($(ARCH), aarch64)
DEFAULT_LDFLAGS += \
-zmax-page-size=0x4000 \
-zcommon-page-size=0x4000 \
-znorelro
else
DEFAULT_LDFLAGS += \
-zmax-page-size=0x4000 \
-zcommon-page-size=0x1000
endif
PYFLAGS = \
-b$(IMAGE_BASE_VIRTUAL)
ASONLYFLAGS = \
-c \
-g
-g \
--debug-prefix-map='$(PWD)'=
DEFAULT_LDLIBS =
@ -246,31 +279,40 @@ LD.libs = \
$(CONFIG_LIBS) \
$(LIBS)
COMPILE.c.flags = $(cc.flags) $(copt.flags) $(cpp.flags) $(c.flags)
COMPILE.cxx.flags = $(cc.flags) $(copt.flags) $(cxx.flags) $(cpp.flags)
COMPILE.c.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(c.flags)
COMPILE.cxx.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(cxx.flags)
COMPILE.f.flags = $(cc.flags) $(copt.flags) $(f.flags)
COMPILE.F.flags = $(cc.flags) $(cpp.flags) $(copt.flags) $(f.flags)
COMPILE.i.flags = $(cc.flags) $(copt.flags) $(c.flags)
COMPILE.ii.flags = $(cc.flags) $(copt.flags) $(cxx.flags)
LINK.flags = $(DEFAULT_LDFLAGS) $(CONFIG_LDFLAGS) $(LDFLAGS)
OBJECTIFY.c.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags) $(copt.flags) $(c.flags)
OBJECTIFY.cxx.flags = $(cc.flags) $(o.flags) $(S.flags) $(cxx.flags) $(cpp.flags) $(copt.flags)
OBJECTIFY.c.flags = $(OBJECTIFY.S.flags) $(copt.flags) $(c.flags)
OBJECTIFY.cxx.flags = $(OBJECTIFY.S.flags) $(copt.flags) $(cxx.flags)
OBJECTIFY.s.flags = $(ASONLYFLAGS) $(s.flags)
OBJECTIFY.S.flags = $(cc.flags) $(o.flags) $(S.flags) $(cpp.flags)
OBJECTIFY.S.flags = $(copt.flags) $(cc.flags) $(o.flags) $(cpp.flags) $(S.flags)
OBJECTIFY.f.flags = $(copt.flags) $(cc.flags) $(o.flags) $(copt.flags) $(S.flags) $(f.flags)
OBJECTIFY.F.flags = $(OBJECTIFY.f.flags) $(cpp.flags)
PREPROCESS.flags = -E $(copt.flags) $(cc.flags) $(cpp.flags)
PREPROCESS.lds.flags = -D__LINKER__ $(filter-out -g%,$(PREPROCESS.flags)) -P -xc
COMPILE.c = $(CC) -S $(COMPILE.c.flags)
COMPILE.cxx = $(CXX) -S $(COMPILE.cxx.flags)
COMPILE.i = $(CC) -S $(COMPILE.i.flags)
COMPILE.f = $(FC) -S $(COMPILE.f.flags)
COMPILE.F = $(FC) -S $(COMPILE.F.flags)
OBJECTIFY.s = $(AS) $(OBJECTIFY.s.flags)
OBJECTIFY.S = $(CC) $(OBJECTIFY.S.flags) -c
OBJECTIFY.f = $(FC) $(OBJECTIFY.f.flags) -c
OBJECTIFY.F = $(FC) $(OBJECTIFY.F.flags) -c
OBJECTIFY.c = $(CC) $(OBJECTIFY.c.flags) -c
OBJECTIFY.cxx = $(CXX) $(OBJECTIFY.cxx.flags) -c
PREPROCESS = $(CC) $(PREPROCESS.flags)
PREPROCESS.lds = $(CC) $(PREPROCESS.lds.flags)
LINK = $(LD) $(LINK.flags)
ELF = o/libc/elf/elf.lds
ELFLINK = $(COMPILE) -ALINK.elf $(LINK) $(LINKARGS) $(OUTPUT_OPTION) && $(COMPILE) -AFIXUP.ape -T$@ $(FIXUPOBJ) $@
ELFLINK = $(COMPILE) -ALINK.elf $(LINK) $(LINKARGS) $(OUTPUT_OPTION)
LINKARGS = $(patsubst %.lds,-T %.lds,$(call uniqr,$(LD.libs) $(filter-out %.pkg,$^)))
LOLSAN = build/lolsan -b $(IMAGE_BASE_VIRTUAL)
# The compiler won't generate %xmm code for sources extensioned .greg.c,
# which is needed for C modules wanting to run at the executive level or
@ -285,9 +327,74 @@ OBJECTIFY.greg.c = \
-fno-optimize-sibling-calls \
-fno-sanitize=all \
-ffreestanding \
-mno-fentry \
-fwrapv \
-c
OBJECTIFY.ansi.c = $(CC) $(OBJECTIFY.c.flags) -ansi -Wextra -Werror -pedantic-errors -c
OBJECTIFY.c99.c = $(CC) $(OBJECTIFY.c.flags) -std=c99 -Wextra -Werror -pedantic-errors -c
OBJECTIFY.c11.c = $(CC) $(OBJECTIFY.c.flags) -std=c11 -Wextra -Werror -pedantic-errors -c
OBJECTIFY.c2x.c = $(CC) $(OBJECTIFY.c.flags) -std=c2x -Wextra -Werror -pedantic-errors -c
OBJECTIFY.real.c = \
$(GCC) \
-x-no-pg \
$(OBJECTIFY.c.flags) \
-wrapper build/realify.sh \
-D__REAL_MODE__ \
-ffixed-r8 \
-ffixed-r9 \
-ffixed-r10 \
-ffixed-r11 \
-ffixed-r12 \
-ffixed-r13 \
-ffixed-r14 \
-ffixed-r15 \
-mno-red-zone \
-fcall-used-rbx \
-fno-jump-tables \
-fno-shrink-wrap \
-fno-schedule-insns2 \
-flive-range-shrinkage \
-fno-omit-frame-pointer \
-momit-leaf-frame-pointer \
-mpreferred-stack-boundary=3 \
-fno-delete-null-pointer-checks \
-c
OBJECTIFY.ncabi.c = \
$(GCC) \
$(OBJECTIFY.c.flags) \
-mno-sse \
-mfpmath=387 \
-mno-fentry \
-fno-stack-protector \
-fno-instrument-functions \
-fno-optimize-sibling-calls \
-fno-sanitize=all \
-fcall-saved-rcx \
-fcall-saved-rdx \
-fcall-saved-rdi \
-fcall-saved-rsi \
-fcall-saved-r8 \
-fcall-saved-r9 \
-fcall-saved-r10 \
-fcall-saved-r11 \
-c \
-xc
OBJECTIFY.initabi.c = \
$(GCC) \
$(OBJECTIFY.c.flags) \
-mno-fentry \
-fno-stack-protector \
-fno-instrument-functions \
-fno-optimize-sibling-calls \
-fno-sanitize=all \
-fcall-saved-rdi \
-fcall-saved-rsi \
-c
TAGSFLAGS = \
-e \
-a \

View file

@ -1,106 +0,0 @@
#!/bin/sh
# cosmocc downloader script
# https://justine.lol/cosmo3/#install
# https://github.com/jart/cosmopolitan/blob/master/tool/cosmocc/README.md
# collect arguments
OUTPUT_DIR=${1:?OUTPUT_DIR}
COSMOCC_VERSION=${2:?COSMOCC_VERSION}
COSMOCC_SHA256SUM=${3:?COSMOCC_SHA256SUM}
URL1="https://github.com/jart/cosmopolitan/releases/download/${COSMOCC_VERSION}/cosmocc-${COSMOCC_VERSION}.zip"
URL2="https://cosmo.zip/pub/cosmocc/cosmocc-${COSMOCC_VERSION}.zip"
# helper function
abort() {
printf '%s\n' "download terminated." >&2
exit 1
}
# exit if already downloaded
# we need it because directory timestamps work wierdly
OUTPUT_DIR=${OUTPUT_DIR%/}
if [ -d "${OUTPUT_DIR}" ]; then
exit 0
fi
# find commands we need to securely download cosmocc
if ! UNZIP=$(command -v unzip 2>/dev/null); then
printf '%s\n' "$0: fatal error: you need the unzip command" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/unzip and put it on the system path" >&2
abort
fi
if command -v sha256sum >/dev/null 2>&1; then
# can use system sha256sum
true
elif command -v shasum >/dev/null 2>&1; then
sha256sum() {
shasum -a 256 "$@"
}
else
if [ ! -f build/sha256sum.c ]; then
printf '%s\n' "$0: fatal error: you need to install sha256sum" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
abort
fi
if ! SHA256SUM=$(command -v "$PWD/o/build/sha256sum" 2>/dev/null); then
if ! CC=$(command -v "$CC" 2>/dev/null); then
if ! CC=$(command -v cc 2>/dev/null); then
if ! CC=$(command -v cosmocc 2>/dev/null); then
printf '%s\n' "$0: fatal error: you need to install either sha256sum, cc, or cosmocc" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/sha256sum and put it on the system path" >&2
abort
fi
fi
fi
mkdir -p o/build || abort
SHA256SUM="$PWD/o/build/sha256sum"
printf '%s\n' "${CC} -w -O2 -o ${SHA256SUM} build/sha256sum.c" >&2
"${CC}" -w -O2 -o "${SHA256SUM}.$$" build/sha256sum.c || abort
mv -f "${SHA256SUM}.$$" "${SHA256SUM}" || abort
fi
sha256sum() {
"${SHA256SUM}" "$@"
}
fi
if WGET=$(command -v wget 2>/dev/null); then
DOWNLOAD=$WGET
DOWNLOAD_ARGS=-O
elif CURL=$(command -v curl 2>/dev/null); then
DOWNLOAD=$CURL
DOWNLOAD_ARGS=-fLo
else
printf '%s\n' "$0: fatal error: you need to install either wget or curl" >&2
printf '%s\n' "please download https://cosmo.zip/pub/cosmos/bin/wget and put it on the system path" >&2
abort
fi
# create temporary output directory
OLDPWD=$PWD
OUTPUT_TMP="${OUTPUT_DIR}.tmp.$$/"
mkdir -p "${OUTPUT_TMP}" || abort
cd "${OUTPUT_TMP}"
die() {
cd "${OLDPWD}"
rm -rf "${OUTPUT_TMP}"
abort
}
# download cosmocc toolchain
# multiple urls avoids outages and national firewalls
if ! "${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL1}"; then
rm -f cosmocc.zip
"${DOWNLOAD}" ${DOWNLOAD_ARGS} cosmocc.zip "${URL2}" || die
fi
printf '%s\n' "${COSMOCC_SHA256SUM} *cosmocc.zip" >cosmocc.zip.sha256sum
sha256sum -c cosmocc.zip.sha256sum || die
"${UNZIP}" cosmocc.zip || die
rm -f cosmocc.zip cosmocc.zip.sha256sum
# commit output directory
cd "${OLDPWD}" || die
mv "${OUTPUT_TMP}" "${OUTPUT_DIR}" || die
# update current symlink
BASE=$(basename "${OUTPUT_DIR}")
DIR=$(dirname "${OUTPUT_DIR}")
ln -sfn "$BASE" "$DIR/current"

View file

@ -1,5 +1,5 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set et ft=make ts=8 sw=8 fenc=utf-8 :vi ──────────────────────┘
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
@ -12,9 +12,5 @@
tail = $(wordlist 2,$(words $1),$1)
reverse = $(if $1,$(call reverse,$(call tail,$1)) $(firstword $1))
uniqr = $(if $1,$(call uniqr,$(filter-out $(firstword $1),$1)) $(firstword $1))
# polyfill uniq native (landlock make 1.4)
ifneq ($(call uniq,c b c a),c b a)
uniq = $(if $1,$(firstword $1) $(call uniq,$(filter-out $(firstword $1),$1)))
endif
uniqr = $(if $1,$(call uniqr,$(filter-out $(firstword $1),$1)) $(firstword $1))

View file

@ -1,6 +1,6 @@
#!/bin/sh
#-*-mode:sh;indent-tabs-mode:nil;tab-width:2;coding:utf-8-*-┐
#── vi: set et ft=sh ts=2 sts=2 fenc=utf-8 :vi ─────────────┘
#───vi: set net ft=sh ts=2 sts=2 fenc=utf-8 :vi─────────────┘
#
# OVERVIEW
#
@ -43,9 +43,6 @@
# '(progn
# (add-hook 'c-mode-common-hook 'jart-c-mode-common-hook)))
TAGS="$1"
shift
# ctags doesn't understand atomics, e.g.
# extern char **environ;
set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@"
@ -55,7 +52,7 @@ set -- --regex-c='/_Atomic(\([^)]*\))/\1/b' "$@"
set -- --regex-c='/^\(\(hidden\|extern\|const\) \)*[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)/\4/b' "$@"
# ctags doesn't understand function prototypes, e.g.
# bool isheap(void *p) dontthrow dontcallback;
# bool isheap(void *p) dontthrow nocallback;
set -- --regex-c='/^[_[:alpha:]][_[:alnum:]]*[ *][ *]*\([_[:alpha:]][_[:alnum:]]*[ *][ *]*\)*\([_[:alpha:]][_$[:alnum:]]*\)(.*/\2/b' "$@"
# ctags doesn't understand function pointers, e.g.
@ -66,7 +63,7 @@ set -- --regex-c='/^extern [^(]*(\*const \([^)]*\))(/\1/b' "$@"
# struct WorstSoftwareEver;
set -- --regex-c='/^struct.*;$/uehocruehcroue/b' "$@"
build/run $TAGS \
exec ${TAGS:-ctags} \
-e \
--langmap=c:.c.h \
--exclude=libc/nt/struct/imagefileheader.internal.h \

View file

@ -1,29 +0,0 @@
#!/bin/sh
COSMO=${COSMO:-/opt/cosmo}
if [ -n "$OBJDUMP" ]; then
exec "$OBJDUMP" "$@"
fi
find_objdump() {
if [ -x .cosmocc/3.9.2/bin/$1-linux-cosmo-objdump ]; then
OBJDUMP=.cosmocc/3.9.2/bin/$1-linux-cosmo-objdump
elif [ -x .cosmocc/3.9.2/bin/$1-linux-musl-objdump ]; then
OBJDUMP=.cosmocc/3.9.2/bin/$1-linux-musl-objdump
elif [ -x "$COSMO/.cosmocc/3.9.2/bin/$1-linux-cosmo-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.9.2/bin/$1-linux-cosmo-objdump"
elif [ -x "$COSMO/.cosmocc/3.9.2/bin/$1-linux-musl-objdump" ]; then
OBJDUMP="$COSMO/.cosmocc/3.9.2/bin/$1-linux-musl-objdump"
else
echo "error: toolchain not found (try running 'cosmocc --update' or 'make' in the cosmo monorepo)" >&2
exit 1
fi
}
if printf '%s\n' "$*" | grep aarch64 >/dev/null 2>&1; then
find_objdump aarch64
exec "$OBJDUMP" "$@"
else
find_objdump x86_64
exec "$OBJDUMP" "$@"
fi

View file

@ -1,5 +1,5 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set et ft=make ts=8 sw=8 fenc=utf-8 :vi ──────────────────────┘
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
@ -22,14 +22,10 @@
# - tool/build/runit.c
# - tool/build/runitd.c
.PRECIOUS: o/$(MODE)/%.ok
o/$(MODE)/%.ok: private .PLEDGE = stdio rpath wpath cpath proc fattr inet dns
o/$(MODE)/%.ok: private .UNVEIL += r:/etc/resolv.conf
o/$(MODE)/%.ok: \
o/$(MODE)/tool/build/runit \
o/$(MODE)/tool/build/runitd \
o/$(MODE)/%
.PRECIOUS: o/$(MODE)/%.com.ok
o/$(MODE)/%.com.ok: .PLEDGE = stdio rpath wpath cpath proc fattr inet
o/$(MODE)/%.com.ok: \
o/$(MODE)/tool/build/runit.com \
o/$(MODE)/tool/build/runitd.com \
o/$(MODE)/%.com
@$(COMPILE) -wATEST -tT$@ $^ $(HOSTS)
.PHONY:
o/tiny/tool/build/runit:

View file

@ -1,5 +1,5 @@
#-*-mode:sed;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: et ft=sed ts=8 sw=8 fenc=utf-8 :vi ────────────────┘
#───vi: et ft=sed ts=8 tw=8 fenc=utf-8 :vi─────────────────┘
#
# SYNOPSIS
#

View file

@ -1,5 +1,5 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set et ft=make ts=8 sw=8 fenc=utf-8 :vi ──────────────────────┘
#───vi: set et ft=make ts=8 tw=8 fenc=utf-8 :vi───────────────────────┘
#
# SYNOPSIS
#
@ -16,15 +16,49 @@
MAKEFLAGS += --no-builtin-rules
MAKE_ZIPCOPY = $(COMPILE) -AZIPCOPY -wT$@ $(ZIPCOPY) $< $@
ifneq ($(ARCH), aarch64)
MAKE_OBJCOPY = $(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@ && $(MAKE_ZIPCOPY)
else
MAKE_OBJCOPY = $(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S $< $@ && $(MAKE_ZIPCOPY)
endif
o/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/%.o: o/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/%.s: %.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
o/%.s: o/%.S ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) $<
o/%.o: %.S ; @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
o/%.o: o/%.S ; @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
o/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
o/%.inc: %.h ; @$(COMPILE) -APREPROCESS $(PREPROCESS) $(OUTPUT_OPTION) -D__ASSEMBLER__ -P $<
o/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
o/%.zip.o: o/% ; @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%: o/$(MODE)/%.dbg
@$(MAKE_OBJCOPY)
o/$(MODE)/%: o/$(MODE)/%.dbg ; @$(COMPILE) -AOBJCOPY -T$@ $(OBJCOPY) -S -O binary $< $@
o/$(MODE)/%.o: %.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: o/$(MODE)/%.s ; @$(COMPILE) -AOBJECTIFY.s $(OBJECTIFY.s) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: %.f ; @$(COMPILE) -AOBJECTIFY.f $(OBJECTIFY.f) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: %.F ; @$(COMPILE) -AOBJECTIFY.F $(OBJECTIFY.F) $(OUTPUT_OPTION) $<
o/$(MODE)/%.h: %.c ; @$(COMPILE) -AAMALGAMATE $(PREPROCESS) $(OUTPUT_OPTION) -fdirectives-only -P $<
o/$(MODE)/%.h: o/$(MODE)/%.c ; @$(COMPILE) -AAMALGAMATE $(PREPROCESS) $(OUTPUT_OPTION) -fdirectives-only -P $<
o/$(MODE)/%.o: %.S ; @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: o/$(MODE)/%.S ; @$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: %.cc ; @$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
o/$(MODE)/%.lds: %.lds ; @$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.greg.o: %.greg.c ; @$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.initabi.o: %.initabi.c ; @$(COMPILE) -AOBJECTIFY.init $(OBJECTIFY.initabi.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.ncabi.o: %.ncabi.c ; @$(COMPILE) -AOBJECTIFY.nc $(OBJECTIFY.ncabi.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.real.o: %.c ; @$(COMPILE) -AOBJECTIFY.real $(OBJECTIFY.real.c) $(OUTPUT_OPTION) $<
o/$(MODE)/%.runs: o/$(MODE)/% ; @$(COMPILE) -ACHECK -wtT$@ $< $(TESTARGS)
o/$(MODE)/%.zip.o: % ; @$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: %.c ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: %.cc ; @$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/%.o: %.cc
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/%.o: o/%.cc
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/$(MODE)/%.o: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) $(OUTPUT_OPTION) $<
@ -34,144 +68,51 @@ o/$(MODE)/%.o: o/$(MODE)/%.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) $(OUTPUT_OPTION) $<
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/$(MODE)/%.h: %.c
@$(COMPILE) -AAMALGAMATE $(PREPROCESS) $(OUTPUT_OPTION) -fdirectives-only -P $<
o/$(MODE)/%.o: %.cc
o/$(MODE)/%.o: o/$(MODE)/%.cc
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/$(MODE)/%.o: %.cpp
@$(COMPILE) -AOBJECTIFY.cxx $(OBJECTIFY.cxx) $(OUTPUT_OPTION) $<
o/$(MODE)/%.lds: %.lds
@$(COMPILE) -APREPROCESS $(PREPROCESS.lds) $(OUTPUT_OPTION) $<
ifneq ($(ARCH), aarch64)
o/$(MODE)/%.o: %.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
o/$(MODE)/%.o: o/$(MODE)/%.S
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.S) $(OUTPUT_OPTION) $<
else
o/$(MODE)/%.o: %.S libc/empty.s
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.s) $(OUTPUT_OPTION) libc/empty.s
o/$(MODE)/%.o: o/$(MODE)/%.S libc/empty.s
@$(COMPILE) -AOBJECTIFY.S $(OBJECTIFY.s) $(OUTPUT_OPTION) libc/empty.s
endif
o/$(MODE)/%.o: %.greg.c
@$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/$(MODE)/%.greg.o: %.greg.c
@$(COMPILE) -AOBJECTIFY.greg $(OBJECTIFY.greg.c) $(OUTPUT_OPTION) $<
@$(COMPILE) -AFIXUPOBJ -wT$@ $(FIXUPOBJ) $@
o/%.a:
$(file >$(TMPDIR)/$(subst /,_,$@),$^)
@$(COMPILE) -AARCHIVE -wT$@ $(AR) $(ARFLAGS) $@ @$(TMPDIR)/$(subst /,_,$@)
o/%.pkg:
$(file >$(TMPSAFE).args,$(filter %.o,$^))
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPSAFE).args
$(file >$(TMPDIR)/$(subst /,_,$@).args,$(filter %.o,$^))
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPDIR)/$(subst /,_,$@)
o/$(MODE)/%.pkg:
$(file >$(TMPSAFE).args,$(filter %.o,$^))
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPSAFE).args
$(file >$(TMPDIR)/$(subst /,_,$@),$(filter %.o,$^))
@$(COMPILE) -APACKAGE -wT$@ $(PKG) $(OUTPUT_OPTION) $(addprefix -d,$(filter %.pkg,$^)) @$(TMPDIR)/$(subst /,_,$@)
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj $(PYFLAGS) -o $@ $<
o/$(MODE)/%.o: %.py o/$(MODE)/third_party/python/pyobj.com
@$(COMPILE) -wAPYOBJ o/$(MODE)/third_party/python/pyobj.com $(PYFLAGS) -o $@ $<
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp
@$(COMPILE) -wAPYCOMP o/$(MODE)/third_party/python/pycomp $(PYCFLAGS) -o $@ $<
o/$(MODE)/%.pyc: %.py o/$(MODE)/third_party/python/pycomp.com
@$(COMPILE) -wAPYCOMP o/$(MODE)/third_party/python/pycomp.com $(PYCFLAGS) -o $@ $<
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac
@$(COMPILE) -wALUAC o/$(MODE)/third_party/lua/luac -s -o $@ $<
o/$(MODE)/%.lua: %.lua o/$(MODE)/third_party/lua/luac.com
@$(COMPILE) -wALUAC o/$(MODE)/third_party/lua/luac.com -s -o $@ $<
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean
@$(COMPILE) -wALUA -tT$@ o/$(MODE)/tool/net/redbean $(LUAFLAGS) -i $<
o/$(MODE)/%.lua.runs: %.lua o/$(MODE)/tool/net/redbean.com
@$(COMPILE) -wALUA -tT$@ o/$(MODE)/tool/net/redbean.com $(LUAFLAGS) -i $<
o/$(MODE)/%: o/$(MODE)/%.com o/$(MODE)/tool/build/cp.com o/$(MODE)/tool/build/assimilate.com
@$(COMPILE) -wACP -T$@ o/$(MODE)/tool/build/cp.com $< $@
@$(COMPILE) -wAASSIMILATE -T$@ o/$(MODE)/tool/build/assimilate.com $@
################################################################################
# LOCAL UNIT TESTS
#
# We always run unit tests as part of the normal `make` invocation. you
# may override the $(TESTARGS) variable to do things such as enable the
# benchmarking feature. For example:
#
# TESTARGS = -b
#
# May be specified in your ~/.cosmo.mk file. You can also use this to
# enable things like function tracing. For example:
#
# TESTARGS = ----ftrace
# .PLEDGE += prot_exec
#
# You could then run a command like:
#
# make -j8 o//test/libc/calls/openbsd_test.runs
#
# You need PROT_EXEC permission since ftrace morphs the binary. It's
# also worth mentioning that the pledge command can simulate what
# Landlock Make does:
#
# o//tool/build/pledge \
# -v. -p 'stdio rpath wpath cpath tty prot_exec' \
# o//test/libc/calls/openbsd_test \
# ----ftrace
#
# This is useful in the event a test binary should run by itself, but
# fails to run beneath Landlock Make. It's also useful sometimes to
# override the verbosity when running tests:
#
# make V=5 TESTARGS=-b o//test/libc/calls/openbsd_test.runs
#
# This way, if for some reason a test should fail but calls exit(0),
# then the stdout/stderr output, which would normally be suppressed,
# will actually be displayed.
# strict header checking
# these rules are unsandboxed since they're kind of a sandboxing test themselves
o/$(MODE)/%.runs: o/$(MODE)/%
@$(COMPILE) -ACHECK -wtT$@ $< $(TESTARGS)
################################################################################
# ELF ZIP FILES
#
# zipobj lets us do fast incremental linking of compressed data.
# it's nice because if we link a hundred binaries that use the time zone
# database, then that database only needs to be DEFLATE'd once.
o/%.zip.o: o/%
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%.zip.o: %
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
o/$(MODE)/%.zip.o: %
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
# an issue with sandboxing arises when creating directory entries in the
# zip file. we need the trailing slash (e.g. o//foo/.zip.o) but Landlock
# Make avoids sandboxing directory names that have a trailing slash (so
# they can be used to watch for deleted files, without creating overly
# broad unveiling). such rules need to be written more explicitly.
o/$(MODE)%/.zip.o: %
@$(COMPILE) -wAZIPOBJ $(ZIPOBJ) $(ZIPOBJ_FLAGS) $(OUTPUT_OPTION) $<
################################################################################
# STRICT HEADER CHECKING
#
# these rules are unsandboxed since they're already a sandboxing test,
# and it would be too costly in terms of make latency to have every
# header file depend on $(HDRS) and $(INCS).
o/%.h.ok: private .UNSANDBOXED = 1
o/%.h.ok: .UNSANDBOXED = 1
o/%.h.ok: %.h
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.h.ok: private .UNSANDBOXED = 1
o/$(MODE)/%.h.ok: .UNSANDBOXED = 1
o/$(MODE)/%.h.ok: %.h
@$(COMPILE) -ACHECK.h $(COMPILE.c) -xc -g0 -o $@ $<
o/$(MODE)/%.hh.ok: private .UNSANDBOXED = 1
o/$(MODE)/%.hh.ok: .UNSANDBOXED = 1
o/$(MODE)/%.hh.ok: %.hh
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
@ -179,27 +120,6 @@ o/%.okk: .UNSANDBOXED = 1
o/%.okk: %
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
o/$(MODE)/%.okk: private .UNSANDBOXED = 1
o/$(MODE)/%.okk: .UNSANDBOXED = 1
o/$(MODE)/%.okk: %
@$(COMPILE) -ACHECK.h $(COMPILE.cxx) -xc++ -g0 -o $@ $<
################################################################################
# EMACS ASSEMBLY GENERATION
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-gcc.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-gcc.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: %.c
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.c) -S -g0 $(OUTPUT_OPTION) $<
# TODO(jart): Make intrinsics support Clang.
o/$(MODE)/%-clang.asm: CC = $(CLANG)
o/$(MODE)/%-clang.asm: private .UNSANDBOXED = 1
o/$(MODE)/%-clang.asm: %.cc
@$(COMPILE) -AOBJECTIFY.c $(OBJECTIFY.cxx) -S -g0 $(OUTPUT_OPTION) $<

View file

@ -1,8 +0,0 @@
#!/bin/sh
UNAMEM=$(uname -m)
UNAMES=$(uname -s)
if [ x"$UNAMES" = x"Darwin" ] && [ x"$UNAMEM" = x"arm64" ]; then
exec ape "$@"
else
exec rusage "$@"
fi

View file

@ -31,7 +31,7 @@ if [ ! -f /proc/sys/fs/binfmt_misc/status ]; then
exit 0
fi
if ! build/bootstrap/echo -n; then
if ! build/bootstrap/echo.com -n; then
cat <<'EOF' >&2
ERROR

View file

@ -1,455 +0,0 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set et ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 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 <errno.h>
#include <limits.h>
#include <stdarg.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
// this file should not have dependencies, because everything will be
// re-downloaded if the o/tool/sha256sum artifact becomes invalidated
#define PROG "sha256sum"
#define USAGE \
"\
Usage: " PROG " [-?hbctw] [PATH...]\n\
-h help\n\
-c check mode\n\
-b binary mode\n\
-t textual mode\n\
-w warning mode\n"
#define ROTR(a, b) (((a) >> (b)) | ((a) << (32 - (b))))
#define CH(x, y, z) (((x) & (y)) ^ (~(x) & (z)))
#define MAJ(x, y, z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z)))
#define EP0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
#define EP1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
#define SIG0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ ((x) >> 3))
#define SIG1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ ((x) >> 10))
struct Sha256Ctx {
uint8_t data[64];
uint32_t datalen;
uint64_t bitlen;
uint32_t state[8];
};
static const uint32_t kSha256Tab[64] = {
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, //
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, //
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, //
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, //
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, //
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, //
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, //
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, //
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, //
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, //
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, //
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, //
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, //
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, //
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, //
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, //
};
static bool g_warn;
static char g_mode;
static bool g_check;
static int g_mismatches;
static void Sha256Transform(uint32_t state[8], const uint8_t data[64]) {
unsigned i;
uint32_t a, b, c, d, e, f, g, h, t1, t2, m[64];
for (i = 0; i < 16; ++i, data += 4) {
m[i] = (uint32_t)data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3];
}
for (; i < 64; ++i) {
m[i] = SIG1(m[i - 2]) + m[i - 7] + SIG0(m[i - 15]) + m[i - 16];
}
a = state[0];
b = state[1];
c = state[2];
d = state[3];
e = state[4];
f = state[5];
g = state[6];
h = state[7];
for (i = 0; i < 64; ++i) {
t1 = h + EP1(e) + CH(e, f, g) + kSha256Tab[i] + m[i];
t2 = EP0(a) + MAJ(a, b, c);
h = g;
g = f;
f = e;
e = d + t1;
d = c;
c = b;
b = a;
a = t1 + t2;
}
state[0] += a;
state[1] += b;
state[2] += c;
state[3] += d;
state[4] += e;
state[5] += f;
state[6] += g;
state[7] += h;
}
static void Sha256Init(struct Sha256Ctx *ctx) {
ctx->datalen = 0;
ctx->bitlen = 0;
ctx->state[0] = 0x6a09e667;
ctx->state[1] = 0xbb67ae85;
ctx->state[2] = 0x3c6ef372;
ctx->state[3] = 0xa54ff53a;
ctx->state[4] = 0x510e527f;
ctx->state[5] = 0x9b05688c;
ctx->state[6] = 0x1f83d9ab;
ctx->state[7] = 0x5be0cd19;
}
static void Sha256Update(struct Sha256Ctx *ctx, const uint8_t *data,
long size) {
long i;
for (i = 0; i < size; ++i) {
ctx->data[ctx->datalen] = data[i];
ctx->datalen++;
if (ctx->datalen == 64) {
Sha256Transform(ctx->state, ctx->data);
ctx->bitlen += 512;
ctx->datalen = 0;
}
}
}
static void Sha256Final(struct Sha256Ctx *ctx, uint8_t *hash) {
long i;
i = ctx->datalen;
ctx->data[i++] = 0x80;
if (ctx->datalen < 56) {
memset(ctx->data + i, 0, 56 - i);
} else {
memset(ctx->data + i, 0, 64 - i);
Sha256Transform(ctx->state, ctx->data);
memset(ctx->data, 0, 56);
}
ctx->bitlen += ctx->datalen * 8;
ctx->data[63] = ctx->bitlen;
ctx->data[62] = ctx->bitlen >> 8;
ctx->data[61] = ctx->bitlen >> 16;
ctx->data[60] = ctx->bitlen >> 24;
ctx->data[59] = ctx->bitlen >> 32;
ctx->data[58] = ctx->bitlen >> 40;
ctx->data[57] = ctx->bitlen >> 48;
ctx->data[56] = ctx->bitlen >> 56;
Sha256Transform(ctx->state, ctx->data);
for (i = 0; i < 4; ++i) {
hash[i] = (ctx->state[0] >> (24 - i * 8)) & 0xff;
hash[i + 4] = (ctx->state[1] >> (24 - i * 8)) & 0xff;
hash[i + 8] = (ctx->state[2] >> (24 - i * 8)) & 0xff;
hash[i + 12] = (ctx->state[3] >> (24 - i * 8)) & 0xff;
hash[i + 16] = (ctx->state[4] >> (24 - i * 8)) & 0xff;
hash[i + 20] = (ctx->state[5] >> (24 - i * 8)) & 0xff;
hash[i + 24] = (ctx->state[6] >> (24 - i * 8)) & 0xff;
hash[i + 28] = (ctx->state[7] >> (24 - i * 8)) & 0xff;
}
}
static char *FormatUint32(char *p, uint32_t x) {
char t;
size_t i, a, b;
i = 0;
do {
p[i++] = x % 10 + '0';
x = x / 10;
} while (x > 0);
p[i] = '\0';
if (i) {
for (a = 0, b = i - 1; a < b; ++a, --b) {
t = p[a];
p[a] = p[b];
p[b] = t;
}
}
return p + i;
}
static char *FormatInt32(char *p, int32_t x) {
if (x < 0)
*p++ = '-', x = -(uint32_t)x;
return FormatUint32(p, x);
}
static size_t StrCat(char *dst, const char *src, size_t dsize) {
size_t m, n = dsize;
const char *p = dst;
const char *q = src;
while (n-- != 0 && *dst != '\0')
dst++;
m = dst - p;
n = dsize - m;
if (n-- == 0) {
return m + strlen(src);
}
while (*src != '\0') {
if (n != 0) {
*dst++ = *src;
n--;
}
src++;
}
*dst = '\0';
return m + (src - q);
}
static void GetOpts(int argc, char *argv[]) {
int opt;
g_mode = ' ';
while ((opt = getopt(argc, argv, "?hbctw")) != -1) {
switch (opt) {
case 'w':
g_warn = true;
break;
case 'c':
g_check = true;
break;
case 't':
g_mode = ' ';
break;
case 'b':
g_mode = '*';
break;
case 'h':
case '?':
(void)write(1, USAGE, sizeof(USAGE) - 1);
exit(0);
default:
(void)write(2, USAGE, sizeof(USAGE) - 1);
exit(64);
}
}
}
static void Write(int fd, const char *s, ...) {
va_list va;
char buf[512];
buf[0] = 0;
va_start(va, s);
do {
StrCat(buf, s, sizeof(buf));
} while ((s = va_arg(va, const char *)));
va_end(va);
(void)write(fd, buf, strlen(buf));
}
static bool IsModeCharacter(char c) {
switch (c) {
case ' ':
case '*':
return true;
default:
return false;
}
}
static bool IsSupportedPath(const char *path) {
size_t i;
for (i = 0;; ++i) {
switch (path[i]) {
case 0:
if (i)
return true;
// fallthrough
case '\r':
case '\n':
case '\\':
Write(2, PROG, ": ", path, ": unsupported path\n", NULL);
return false;
default:
break;
}
}
}
static bool GetDigest(const char *path, FILE *f, uint8_t digest[32]) {
size_t got;
uint8_t buf[512];
struct Sha256Ctx ctx;
Sha256Init(&ctx);
while ((got = fread(buf, 1, sizeof(buf), f))) {
Sha256Update(&ctx, buf, got);
}
if (ferror(f)) {
Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL);
return false;
}
Sha256Final(&ctx, digest);
return true;
}
static char *CopyHex(char *s, const void *p, size_t n) {
const char *d, *e;
for (d = (const char *)p, e = d + n; d < e; ++d) {
*s++ = "0123456789abcdef"[(*d >> 4) & 15];
*s++ = "0123456789abcdef"[(*d >> 0) & 15];
}
*s = 0;
return s;
}
static bool ProduceDigest(const char *path, FILE *f) {
char hexdigest[65];
char mode[2] = {g_mode};
unsigned char digest[32];
if (!IsSupportedPath(path))
return false;
if (!GetDigest(path, f, digest))
return false;
CopyHex(hexdigest, digest, 32);
Write(1, hexdigest, " ", mode, path, "\n", NULL);
return true;
}
static char *Chomp(char *line) {
size_t i;
if (line) {
for (i = strlen(line); i--;) {
if (line[i] == '\r' || line[i] == '\n') {
line[i] = '\0';
} else {
break;
}
}
}
return line;
}
static int HexToInt(int c) {
if ('0' <= c && c <= '9') {
return c - '0';
} else if ('a' <= c && c <= 'f') {
return c - 'a' + 10;
} else if ('A' <= c && c <= 'F') {
return c - 'A' + 10;
} else {
return -1;
}
}
static bool CheckDigests(const char *path, FILE *f) {
FILE *f2;
bool k = true;
int a, b, i, line;
const char *path2, *status;
uint8_t wantdigest[32], gotdigest[32];
char buf[64 + 2 + PATH_MAX + 1 + 1], *p;
for (line = 0; fgets(buf, sizeof(buf), f); ++line) {
if (!*Chomp(buf))
continue;
for (p = buf, i = 0; i < 32; ++i) {
if ((a = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
if ((b = HexToInt(*p++ & 255)) == -1)
goto InvalidLine;
wantdigest[i] = a << 4 | b;
}
if (*p++ != ' ')
goto InvalidLine;
if (!IsModeCharacter(*p++))
goto InvalidLine;
path2 = p;
if (!*path2)
goto InvalidLine;
if (!IsSupportedPath(path2))
continue;
if ((f2 = fopen(path2, "rb"))) {
if (GetDigest(path2, f2, gotdigest)) {
if (!memcmp(wantdigest, gotdigest, 32)) {
status = "OK";
} else {
status = "FAILED";
++g_mismatches;
k = false;
}
Write(1, path2, ": ", status, "\n", NULL);
} else {
k = false;
}
fclose(f2);
} else {
Write(2, PROG, ": ", path2, ": ", strerror(errno), "\n", NULL);
k = false;
}
continue;
InvalidLine:
if (g_warn) {
char linestr[12];
FormatInt32(linestr, line + 1);
Write(2, PROG, ": ", path, ":", linestr, ": ",
"improperly formatted checksum line", "\n", NULL);
}
}
if (ferror(f)) {
Write(2, PROG, ": ", path, ": ", strerror(errno), "\n", NULL);
k = false;
}
return k;
}
static bool Process(const char *path, FILE *f) {
if (g_check) {
return CheckDigests(path, f);
} else {
return ProduceDigest(path, f);
}
}
int main(int argc, char *argv[]) {
int i;
FILE *f;
bool k = true;
GetOpts(argc, argv);
if (optind == argc) {
f = stdin;
k &= Process("-", f);
} else {
for (i = optind; i < argc; ++i) {
if ((f = fopen(argv[i], "rb"))) {
k &= Process(argv[i], f);
fclose(f);
} else {
Write(2, PROG, ": ", argv[i], ": ", strerror(errno), "\n", NULL);
k = false;
}
}
}
if (g_mismatches) {
char ibuf[12];
FormatInt32(ibuf, g_mismatches);
Write(2, PROG, ": WARNING: ", ibuf, " computed checksum did NOT match\n",
NULL);
}
return !k;
}

View file

@ -1,13 +0,0 @@
---
BasedOnStyle: Mozilla
IndentWidth: 4
ColumnLimit: 80
---
Language: Cpp
AllowShortFunctionsOnASingleLine: false
AlignTrailingComments: false
AlignEscapedNewlines: DontAlign
AlwaysBreakTemplateDeclarations: true
ConstructorInitializerAllOnOneLineOrOnePerLine: true
FixNamespaceComments: true
---

View file

@ -1,55 +0,0 @@
#-*-mode:makefile-gmake;indent-tabs-mode:t;tab-width:8;coding:utf-8-*-┐
#── vi: set noet ft=make ts=8 sw=8 fenc=utf-8 :vi ────────────────────┘
PKGS += CTL
CTL_ARTIFACTS += CTL_A
CTL = $(CTL_A_DEPS) $(CTL_A)
CTL_A = o/$(MODE)/ctl/ctl.a
CTL_A_FILES := $(wildcard ctl/*)
CTL_A_HDRS = $(filter %.h,$(CTL_A_FILES))
CTL_A_SRCS = $(filter %.cc,$(CTL_A_FILES))
CTL_A_OBJS = $(CTL_A_SRCS:%.cc=o/$(MODE)/%.o)
CTL_A_CHECKS = \
$(CTL_A).pkg \
$(CTL_A_HDRS:%=o/$(MODE)/%.okk) \
CTL_A_DIRECTDEPS = \
LIBC_INTRIN \
LIBC_MEM \
LIBC_NEXGEN32E \
LIBC_STDIO \
LIBC_STR \
THIRD_PARTY_DOUBLECONVERSION \
THIRD_PARTY_GDTOA \
THIRD_PARTY_LIBCXXABI \
THIRD_PARTY_LIBUNWIND \
CTL_A_DEPS := $(call uniq,$(foreach x,$(CTL_A_DIRECTDEPS),$($(x))))
$(CTL_A): ctl/ \
$(CTL_A).pkg \
$(CTL_A_OBJS)
$(CTL_A).pkg: \
$(CTL_A_OBJS) \
$(foreach x,$(CTL_A_DIRECTDEPS),$($(x)_A).pkg)
$(CTL_A_OBJS): private \
OVERRIDE_CXXFLAGS += \
-Wframe-larger-than=4096 \
-Walloca-larger-than=4096 \
-ffunction-sections \
-fdata-sections \
-fexceptions \
CTL_LIBS = $(foreach x,$(CTL_ARTIFACTS),$($(x)))
CTL_SRCS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_SRCS))
CTL_HDRS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_HDRS))
CTL_CHECKS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_CHECKS))
CTL_OBJS = $(foreach x,$(CTL_ARTIFACTS),$($(x)_OBJS))
$(CTL_OBJS): $(BUILD_FILES) ctl/BUILD.mk
.PHONY: o/$(MODE)/ctl
o/$(MODE)/ctl: $(CTL_CHECKS)

File diff suppressed because it is too large Load diff

View file

@ -1,28 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ACCUMULATE_H_
#define CTL_ACCUMULATE_H_
namespace ctl {
template<class InputIt, class T>
constexpr T
accumulate(InputIt first, InputIt last, T init)
{
for (; first != last; ++first)
init = init + *first;
return init;
}
template<class InputIt, class T, class BinaryOperation>
constexpr T
accumulate(InputIt first, InputIt last, T init, BinaryOperation op)
{
for (; first != last; ++first)
init = op(init, *first);
return init;
}
} // namespace ctl
#endif // CTL_ACCUMULATE_H_

View file

@ -1,55 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ADD_LVALUE_REFERENCE_H_
#define CTL_ADD_LVALUE_REFERENCE_H_
namespace ctl {
template<typename T>
struct add_lvalue_reference
{
typedef T& type;
};
template<typename T>
struct add_lvalue_reference<T&>
{
typedef T& type;
};
template<typename T>
struct add_lvalue_reference<T&&>
{
typedef T& type;
};
template<>
struct add_lvalue_reference<void>
{
typedef void type;
};
template<>
struct add_lvalue_reference<const void>
{
typedef const void type;
};
template<>
struct add_lvalue_reference<volatile void>
{
typedef volatile void type;
};
template<>
struct add_lvalue_reference<const volatile void>
{
typedef const volatile void type;
};
template<typename T>
using add_lvalue_reference_t = typename add_lvalue_reference<T>::type;
} // namespace ctl
#endif // CTL_ADD_LVALUE_REFERENCE_H_

View file

@ -1,43 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ADD_POINTER_H_
#define CTL_ADD_POINTER_H_
#include "remove_reference.h"
namespace ctl {
// Primary template
template<typename T>
struct add_pointer
{
typedef typename remove_reference<T>::type* type;
};
// Specialization for functions
template<typename R, typename... Args>
struct add_pointer<R(Args...)>
{
typedef R (*type)(Args...);
};
// Specialization for function references
template<typename R, typename... Args>
struct add_pointer<R (&)(Args...)>
{
typedef R (*type)(Args...);
};
// Specialization for rvalue references to functions
template<typename R, typename... Args>
struct add_pointer<R (&&)(Args...)>
{
typedef R (*type)(Args...);
};
// Helper alias template (C++14 and later)
template<typename T>
using add_pointer_t = typename add_pointer<T>::type;
} // namespace ctl
#endif // CTL_ADD_POINTER_H_

View file

@ -1,29 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ADDRESSOF_H_
#define CTL_ADDRESSOF_H_
namespace ctl {
template<typename T>
T*
addressof(T& arg) noexcept
{
return reinterpret_cast<T*>(
&const_cast<char&>(reinterpret_cast<const volatile char&>(arg)));
}
template<typename R, typename... Args>
R (*addressof(R (*&arg)(Args...)) noexcept)
(Args...)
{
return arg;
}
template<typename T>
T*
addressof(T&&) = delete;
} // namespace ctl
#endif // CTL_ADDRESSOF_H_

View file

@ -1,24 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ADVANCE_H_
#define CTL_ADVANCE_H_
namespace ctl {
template<class InputIt, class Distance>
constexpr void
advance(InputIt& it, Distance n)
{
while (n > 0) {
--n;
++it;
}
while (n < 0) {
++n;
--it;
}
}
} // namespace ctl
#endif // CTL_ADVANCE_H_

View file

@ -1,20 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ALL_OF_H_
#define CTL_ALL_OF_H_
namespace ctl {
template<class InputIt, class UnaryPredicate>
constexpr bool
all_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first)
if (!p(*first))
return false;
return true;
}
} // namespace ctl
#endif // CTL_ALL_OF_H_

View file

@ -1,94 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ALLOCATOR_H_
#define CTL_ALLOCATOR_H_
#include "bad_alloc.h"
#include "integral_constant.h"
#include "new.h"
#include "utility.h"
namespace ctl {
template<typename T>
class allocator
{
public:
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using propagate_on_container_move_assignment = ctl::true_type;
using is_always_equal = ctl::true_type;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
constexpr allocator() noexcept = default;
constexpr allocator(const allocator&) noexcept = default;
template<class U>
constexpr allocator(const allocator<U>&) noexcept
{
}
constexpr ~allocator() = default;
[[nodiscard]] T* allocate(size_type n)
{
if (n > __SIZE_MAX__ / sizeof(T))
throw ctl::bad_alloc();
if (auto p = static_cast<T*>(::operator new(
n * sizeof(T), ctl::align_val_t(alignof(T)), ctl::nothrow)))
return p;
throw ctl::bad_alloc();
}
void deallocate(T* p, size_type n) noexcept
{
::operator delete(p, n * sizeof(T), ctl::align_val_t(alignof(T)));
}
template<typename U, typename... Args>
void construct(U* p, Args&&... args)
{
::new (static_cast<void*>(p)) U(ctl::forward<Args>(args)...);
}
template<typename U>
void destroy(U* p)
{
p->~U();
}
size_type max_size() const noexcept
{
return __SIZE_MAX__ / sizeof(T);
}
allocator& operator=(const allocator&) = default;
template<typename U>
struct rebind
{
using other = allocator<U>;
};
};
template<class T, class U>
bool
operator==(const allocator<T>&, const allocator<U>&) noexcept
{
return true;
}
template<class T, class U>
bool
operator!=(const allocator<T>&, const allocator<U>&) noexcept
{
return false;
}
} // namespace ctl
#endif // CTL_ALLOCATOR_H_

View file

@ -1,70 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ALLOCATOR_TRAITS_H_
#define CTL_ALLOCATOR_TRAITS_H_
#include "integral_constant.h"
namespace ctl {
template<typename Alloc>
struct allocator_traits
{
using allocator_type = Alloc;
using value_type = typename Alloc::value_type;
using pointer = typename Alloc::value_type*;
using const_pointer = const typename Alloc::value_type*;
using void_pointer = void*;
using const_void_pointer = const void*;
using difference_type = ptrdiff_t;
using size_type = size_t;
using propagate_on_container_copy_assignment = ctl::false_type;
using propagate_on_container_move_assignment = ctl::true_type;
using propagate_on_container_swap = ctl::false_type;
using is_always_equal = ctl::true_type;
template<typename T>
struct rebind_alloc
{
using other = typename Alloc::template rebind<T>::other;
};
template<typename T>
using rebind_traits = allocator_traits<typename rebind_alloc<T>::other>;
static pointer allocate(Alloc& a, size_type n)
{
return a.allocate(n);
}
static void deallocate(Alloc& a, pointer p, size_type n)
{
a.deallocate(p, n);
}
template<typename T, typename... Args>
static void construct(Alloc& a, T* p, Args&&... args)
{
::new ((void*)p) T(static_cast<Args&&>(args)...);
}
template<typename T>
static void destroy(Alloc& a, T* p)
{
p->~T();
}
static size_type max_size(const Alloc& a) noexcept
{
return a.max_size();
}
static Alloc select_on_container_copy_construction(const Alloc& a)
{
return a;
}
};
} // namespace ctl
#endif // CTL_ALLOCATOR_TRAITS_H_

View file

@ -1,20 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ANY_OF_H_
#define CTL_ANY_OF_H_
namespace ctl {
template<class InputIt, class UnaryPredicate>
constexpr bool
any_of(InputIt first, InputIt last, UnaryPredicate p)
{
for (; first != last; ++first)
if (p(*first))
return true;
return false;
}
} // namespace ctl
#endif // CTL_ANY_OF_H_

View file

@ -1,248 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_ARRAY_H_
#define CTL_ARRAY_H_
#include "initializer_list.h"
#include "out_of_range.h"
#include "reverse_iterator.h"
namespace ctl {
template<typename T, size_t N>
struct array
{
using value_type = T;
using size_type = size_t;
using difference_type = ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const value_type*;
using iterator = value_type*;
using const_iterator = const value_type*;
using reverse_iterator = ctl::reverse_iterator<iterator>;
using const_reverse_iterator = ctl::reverse_iterator<const_iterator>;
T elems[N];
constexpr array() = default;
constexpr array(std::initializer_list<T> init)
{
auto it = init.begin();
for (size_t i = 0; i < N && it != init.end(); ++i, ++it)
elems[i] = *it;
}
constexpr reference at(size_type pos)
{
if (pos >= N)
throw ctl::out_of_range();
return elems[pos];
}
constexpr const_reference at(size_type pos) const
{
if (pos >= N)
throw ctl::out_of_range();
return elems[pos];
}
constexpr reference operator[](size_type pos)
{
if (pos >= N)
__builtin_trap();
return elems[pos];
}
constexpr const_reference operator[](size_type pos) const
{
if (pos >= N)
__builtin_trap();
return elems[pos];
}
constexpr reference front()
{
return elems[0];
}
constexpr const_reference front() const
{
return elems[0];
}
constexpr reference back()
{
return elems[N - 1];
}
constexpr const_reference back() const
{
return elems[N - 1];
}
constexpr T* data() noexcept
{
return elems;
}
constexpr const T* data() const noexcept
{
return elems;
}
constexpr iterator begin() noexcept
{
return elems;
}
constexpr const_iterator begin() const noexcept
{
return elems;
}
constexpr iterator end() noexcept
{
return elems + N;
}
constexpr const_iterator end() const noexcept
{
return elems + N;
}
constexpr reverse_iterator rbegin() noexcept
{
return reverse_iterator(end());
}
constexpr const_reverse_iterator rbegin() const noexcept
{
return const_reverse_iterator(end());
}
constexpr reverse_iterator rend() noexcept
{
return reverse_iterator(begin());
}
constexpr const_reverse_iterator rend() const noexcept
{
return const_reverse_iterator(begin());
}
constexpr const_iterator cbegin() const noexcept
{
return begin();
}
constexpr const_iterator cend() const noexcept
{
return end();
}
constexpr const_reverse_iterator crbegin() const noexcept
{
return rbegin();
}
constexpr const_reverse_iterator crend() const noexcept
{
return rend();
}
constexpr bool empty() const noexcept
{
return N == 0;
}
constexpr size_type size() const noexcept
{
return N;
}
constexpr size_type max_size() const noexcept
{
return N;
}
void fill(const T& value)
{
for (size_type i = 0; i < N; ++i) {
elems[i] = value;
}
}
void swap(array& other) noexcept
{
for (size_type i = 0; i < N; ++i) {
T temp = elems[i];
elems[i] = other.elems[i];
other.elems[i] = temp;
}
}
};
template<typename T, size_t N>
bool
operator==(const array<T, N>& lhs, const array<T, N>& rhs)
{
for (size_t i = 0; i < N; ++i) {
if (!(lhs[i] == rhs[i]))
return false;
}
return true;
}
template<typename T, size_t N>
bool
operator!=(const array<T, N>& lhs, const array<T, N>& rhs)
{
return !(lhs == rhs);
}
template<typename T, size_t N>
bool
operator<(const array<T, N>& lhs, const array<T, N>& rhs)
{
for (size_t i = 0; i < N; ++i) {
if (lhs[i] < rhs[i])
return true;
if (rhs[i] < lhs[i])
return false;
}
return false;
}
template<typename T, size_t N>
bool
operator<=(const array<T, N>& lhs, const array<T, N>& rhs)
{
return !(rhs < lhs);
}
template<typename T, size_t N>
bool
operator>(const array<T, N>& lhs, const array<T, N>& rhs)
{
return rhs < lhs;
}
template<typename T, size_t N>
bool
operator>=(const array<T, N>& lhs, const array<T, N>& rhs)
{
return !(lhs < rhs);
}
template<typename T, size_t N>
void
swap(array<T, N>& lhs, array<T, N>& rhs) noexcept
{
lhs.swap(rhs);
}
} // namespace ctl
#endif // CTL_ARRAY_H_

View file

@ -1,64 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_BACK_INSERTER_H_
#define CTL_BACK_INSERTER_H_
#include "iterator.h"
#include "utility.h"
namespace ctl {
template<class Container>
class back_insert_iterator
{
protected:
Container* container;
public:
using iterator_category = ctl::output_iterator_tag;
using value_type = void;
using difference_type = void;
using pointer = void;
using reference = void;
explicit back_insert_iterator(Container& c) : container(&c)
{
}
back_insert_iterator& operator=(const typename Container::value_type& value)
{
container->push_back(value);
return *this;
}
back_insert_iterator& operator=(typename Container::value_type&& value)
{
container->push_back(ctl::move(value));
return *this;
}
back_insert_iterator& operator*()
{
return *this;
}
back_insert_iterator& operator++()
{
return *this;
}
back_insert_iterator operator++(int)
{
return *this;
}
};
template<class Container>
back_insert_iterator<Container>
back_inserter(Container& c)
{
return back_insert_iterator<Container>(c);
}
} // namespace ctl
#endif // CTL_BACK_INSERTER_H_

View file

@ -1,23 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_BAD_ALLOC_H_
#define CTL_BAD_ALLOC_H_
#include "exception.h"
namespace ctl {
class bad_alloc : public ctl::exception
{
public:
bad_alloc() noexcept = default;
~bad_alloc() override = default;
const char* what() const noexcept override
{
return "ctl::bad_alloc";
}
};
} // namespace ctl
#endif // CTL_BAD_ALLOC_H_

View file

@ -1,25 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_CONDITIONAL_H_
#define CTL_CONDITIONAL_H_
namespace ctl {
template<bool B, class T, class F>
struct conditional
{
typedef T type;
};
template<class T, class F>
struct conditional<false, T, F>
{
typedef F type;
};
template<bool B, typename T, typename F>
using conditional_t = typename conditional<B, T, F>::type;
} // namespace ctl
#endif // CTL_CONDITIONAL_H_

View file

@ -1,22 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_COPY_H_
#define CTL_COPY_H_
namespace ctl {
template<class InputIt, class OutputIt>
OutputIt
copy(InputIt first, InputIt last, OutputIt d_first)
{
while (first != last) {
*d_first = *first;
++d_first;
++first;
}
return d_first;
}
} // namespace ctl
#endif // CTL_COPY_H_

View file

@ -1,36 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_DECAY_H_
#define CTL_DECAY_H_
#include "add_pointer.h"
#include "conditional.h"
#include "is_array.h"
#include "is_function.h"
#include "remove_cv.h"
#include "remove_extent.h"
#include "remove_reference.h"
namespace ctl {
template<typename T>
struct decay
{
private:
typedef typename ctl::remove_reference<T>::type U;
public:
typedef typename ctl::conditional<
ctl::is_array<U>::value,
typename ctl::remove_extent<U>::type*,
typename ctl::conditional<ctl::is_function<U>::value,
typename ctl::add_pointer<U>::type,
typename ctl::remove_cv<U>::type>::type>::type
type;
};
template<typename T>
using decay_t = typename decay<T>::type;
} // namespace ctl
#endif // CTL_DECAY_H_

View file

@ -1,44 +0,0 @@
// -*-mode:c++;indent-tabs-mode:nil;c-basic-offset:4;tab-width:8;coding:utf-8-*-
// vi: set et ft=cpp ts=4 sts=4 sw=4 fenc=utf-8 :vi
#ifndef CTL_DEFAULT_DELETE_H_
#define CTL_DEFAULT_DELETE_H_
#include "enable_if.h"
#include "is_convertible.h"
namespace ctl {
template<typename T>
struct default_delete
{
constexpr default_delete() noexcept = default;
template<typename U,
typename = typename ctl::enable_if<
ctl::is_convertible<U*, T*>::value>::type>
constexpr default_delete(const default_delete<U>&) noexcept
{
}
constexpr void operator()(T* const p) const noexcept
{
delete p;
}
};
template<typename T>
struct default_delete<T[]>
{
constexpr default_delete() noexcept = default;
template<typename U,
typename = typename ctl::enable_if<
ctl::is_convertible<U (*)[], T (*)[]>::value>::type>
constexpr default_delete(const default_delete<U[]>&) noexcept
{
}
constexpr void operator()(T* const p) const noexcept
{
delete[] p;
}
};
} // namespace ctl
#endif // CTL_DEFAULT_DELETE_H_

Some files were not shown because too many files have changed in this diff Show more