arm: libc

This commit is contained in:
Steven Hugg 2023-12-29 23:46:57 -05:00
parent 8bdbae36e3
commit 63ee25741b
15 changed files with 226 additions and 37 deletions

View File

@ -1,9 +0,0 @@
int main();
void _start() {
asm("mov sp, #0x100000"); // stack pointer
main();
asm(".long 0xdeadc0d3");
}

View File

@ -1,6 +1,4 @@
//#link "crt0.c"
const char const str[] = "HELLO WORLD!";
int global = 0x1234;

View File

@ -1,4 +1,24 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
function getASCII(view: DataView, offset: number): string {
let s = '';

View File

@ -3555,6 +3555,11 @@ ARMCore.prototype.compileArm = function(instruction) {
var load = instruction & 0x00100000;
var b = instruction & 0x00400000;
var i = instruction & 0x02000000;
// test for UDF instruction
if ((instruction & 0xfff000f0) == (0xe7f000f0|0)) {
var immediate = instruction & 0x0000000f; // TODO: full range
throw new EmuHalt("Program exited (" + immediate + ")");
}
var address : AddressFunction = function() {
throw new EmuHalt("Unimplemented memory access: 0x" + instruction.toString(16));

View File

@ -1,3 +1,24 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
// https://dev.to/ndesmic/building-a-minimal-wasi-polyfill-for-browsers-4nel
// http://www.wasmtutor.com/webassembly-barebones-wasi
@ -154,7 +175,7 @@ export enum WASIErrors {
export class WASIFileDescriptor {
fdindex: number = -1;
data: Uint8Array = new Uint8Array(16);
protected data: Uint8Array = new Uint8Array(16);
flags: number = 0;
size: number = 0;
offset: number = 0;
@ -224,6 +245,8 @@ class WASIStreamingFileDescriptor extends WASIFileDescriptor {
export interface WASIFilesystem {
getFile(name: string) : WASIFileDescriptor;
getFiles() : WASIFileDescriptor[];
getDirectories() : WASIFileDescriptor[];
}
export class WASIMemoryFilesystem implements WASIFilesystem {
@ -239,6 +262,13 @@ export class WASIMemoryFilesystem implements WASIFilesystem {
}
putDirectory(name: string, rights?: number) {
if (!rights) rights = FDRights.PATH_OPEN | FDRights.PATH_CREATE_DIRECTORY | FDRights.PATH_CREATE_FILE;
if (name != '/' && name.endsWith('/')) name = name.substring(0, name.length - 1);
// add parent directory(s)
const parent = name.substring(0, name.lastIndexOf('/'));
if (parent && parent != name) {
this.putDirectory(parent, rights);
}
// add directory
const dir = new WASIFileDescriptor(name, FDType.DIRECTORY, rights);
this.dirs.set(name, dir);
return dir;
@ -261,6 +291,12 @@ export class WASIMemoryFilesystem implements WASIFilesystem {
}
return file;
}
getDirectories() {
return [...this.dirs.values()];
}
getFiles() {
return [...this.files.values()];
}
}
export class WASIRunner {

View File

@ -23,8 +23,8 @@ export class MemoryView implements ProjectView {
dumplines;
maindiv : HTMLElement;
recreateOnResize = true;
hibits = 0;
totalRows = 0x1400;
hibits = 0; // a hack to make it work with 32-bit addresses
totalRows = 0x1400; // a little more room in case we split lots of lines
createDiv(parent : HTMLElement) {
var div = document.createElement('div');
@ -45,7 +45,7 @@ export class MemoryView implements ProjectView {
var linediv = document.createElement("div");
if (this.dumplines) {
var dlr = this.dumplines[row];
if (dlr) linediv.classList.add('seg_' + this.getMemorySegment(this.dumplines[row].a));
if (dlr) linediv.classList.add('seg_' + this.getMemorySegment(this.dumplines[row].a | this.hibits));
}
linediv.appendChild(document.createTextNode(s));
return linediv;
@ -60,7 +60,8 @@ export class MemoryView implements ProjectView {
scrollToAddress(addr : number) {
if (this.dumplines) {
this.memorylist.scrollToItem(this.findMemoryWindowLine(addr));
this.hibits = addr & 0xffff0000;
this.memorylist.scrollToItem(this.findMemoryWindowLine(addr & 0xffff));
}
}
@ -131,7 +132,7 @@ export class MemoryView implements ProjectView {
var sym;
for (const _nextofs of Object.keys(addr2sym)) {
var nextofs = parseInt(_nextofs); // convert from string (stupid JS)
var nextsym = addr2sym[nextofs];
var nextsym = addr2sym[nextofs | this.hibits];
if (sym) {
// ignore certain symbols
if (ignoreSymbol(sym)) {
@ -280,8 +281,7 @@ export class MemoryMapView implements ProjectView {
segdiv.click(() => {
// TODO: what if memory browser does not exist?
var memview = projectWindows.createOrShow('#memory') as MemoryView;
memview.hibits = seg.start & 0xffff0000;
memview.scrollToAddress(seg.start & 0xffff);
memview.scrollToAddress(seg.start);
});
}

View File

@ -1,3 +1,24 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { ARM32CPU, ARMCoreState } from "../common/cpu/ARM";
import { BasicScanlineMachine, Bus32, HasSerialIO, SerialEvent, SerialIOInterface } from "../common/devices";

View File

@ -1,3 +1,24 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { Platform, DisasmLine, Machine, BaseMachinePlatform } from "../common/baseplatform";
import { PLATFORMS } from "../common/emu";

View File

@ -1,3 +1,25 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import assert from "assert";
import { DWARFParser, ELFParser } from "../common/binutils";

BIN
src/worker/fs/arm32-fs.zip Normal file

Binary file not shown.

Binary file not shown.

View File

@ -0,0 +1,15 @@
int entry();
__attribute__((weak, naked, noinline, noreturn)) void _start() {
asm(".global __bss_start__, __bss_end__");
asm("__bss_start__ = _edata");
asm("__bss_end__ = _end");
asm("mov sp, #0x100000"); // stack pointer
entry();
asm(".long 0xe7f000f0"); // udf #0
}
void _Exit(int ec) {
asm(".long 0xe7f000f0"); // udf #0
}

BIN
src/worker/lib/arm32/libc.a Normal file

Binary file not shown.

View File

@ -1,3 +1,24 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
export var PLATFORM_PARAMS = {
'vcs': {
@ -336,8 +357,11 @@ export var PLATFORM_PARAMS = {
},
'arm32': {
arch: 'arm32',
define: ['__ARM__'],
extra_link_files: ['arm-tcc.o', 'arm-libtcc1.a'],
define: ['__ARM__', 'DISABLE_UNIMPLEMENTED_LIBC_APIS', 'PRINTF_ALIAS_STANDARD_FUNCTION_NAMES_SOFT'],
extra_compile_args: ['-I./arch/arm/include', '-I./openlibm/include', '-I./openlibm/src', '-I./printf/src'],
extra_link_files: ['crt0.c', 'arm-libtcc1.a', 'libc.a'],
extra_link_args: ['arm-libtcc1.a', 'libc.a'],
crt0: 'crt0.c',
},
};

View File

@ -1,9 +1,32 @@
/*
* Copyright (c) 2024 Steven E. Hugg
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
import { ELFParser } from "../../common/binutils";
import { hex } from "../../common/util";
import { WASIFilesystem } from "../../common/wasi/wasishim";
import { CodeListingMap, SourceLine, WorkerError, WorkerResult } from "../../common/workertypes";
import { BuildStep, BuildStepResult, gatherFiles, staleFiles, populateFiles, putWorkFile, anyTargetChanged, getPrefix, getWorkFileAsString, populateExtraFiles } from "../builder";
import { makeErrorMatcher, re_crlf } from "../listingutils";
import { loadWASIFilesystemZip } from "../wasiutils";
import { loadNative, moduleInstFn, execMain, emglobal, EmscriptenModule } from "../wasmutils";
export function assembleARMIPS(step: BuildStep): WorkerResult {
@ -241,9 +264,11 @@ export function assembleVASMARM(step: BuildStep): BuildStepResult {
}
function tccErrorMatcher(errors: WorkerError[], mainpath: string) {
return makeErrorMatcher(errors, /(\w+|tcc):(\d+|\s*error): (.+)/, 2, 3, mainpath, 1);;
return makeErrorMatcher(errors, /([^:]+|tcc):(\d+|\s*error): (.+)/, 2, 3, mainpath, 1);;
}
let armtcc_fs: WASIFilesystem | null = null;
export async function compileARMTCC(step: BuildStep): Promise<BuildStepResult> {
loadNative("arm-tcc");
const params = step.params;
@ -252,6 +277,10 @@ export async function compileARMTCC(step: BuildStep): Promise<BuildStepResult> {
const objpath = step.prefix + ".o";
const error_fn = tccErrorMatcher(errors, step.path);
if (!armtcc_fs) {
armtcc_fs = await loadWASIFilesystemZip("arm32-fs.zip");
}
if (staleFiles(step, [objpath])) {
const armtcc: EmscriptenModule = await emglobal.armtcc({
instantiateWasm: moduleInstFn('arm-tcc'),
@ -260,7 +289,7 @@ export async function compileARMTCC(step: BuildStep): Promise<BuildStepResult> {
printErr: error_fn,
});
var args = ['-I.', '-c',
var args = ['-c', '-I.', '-I./include',
//'-std=c11',
'-funsigned-char',
'-Wwrite-strings',
@ -269,10 +298,21 @@ export async function compileARMTCC(step: BuildStep): Promise<BuildStepResult> {
if (params.define) {
params.define.forEach((x) => args.push('-D' + x));
}
if (params.extra_compile_args) {
args = args.concat(params.extra_compile_args);
}
args.push(step.path);
const FS = armtcc.FS;
// TODO: only should do once?
armtcc_fs.getDirectories().forEach((dir) => {
if (dir.name != '/') FS.mkdir(dir.name);
});
armtcc_fs.getFiles().forEach((file) => {
FS.writeFile(file.name, file.getBytes(), { encoding: 'binary' });
});
populateExtraFiles(step, FS, params.extra_compile_files);
populateFiles(step, FS);
execMain(step, armtcc, args);
if (errors.length)
@ -312,18 +352,14 @@ export async function linkARMTCC(step: BuildStep): Promise<WorkerResult> {
if (params.define) {
params.define.forEach((x) => args.push('-D' + x));
}
let objfiles = step.files;
// sort so that crtxxx files are first
objfiles.sort((a, b) => {
let a0 = a.startsWith('crt') ? 0 : 1;
let b0 = b.startsWith('crt') ? 0 : 1;
a = a0 + a;
b = b0 + b;
return a.localeCompare(b);
});
args = args.concat(objfiles);
args.push('arm-libtcc1.a');
if (params.crt0) {
args.push(params.crt0);
}
args = args.concat(step.files);
if (params.extra_link_args) {
args = args.concat(params.extra_link_args);
}
const FS = armtcc.FS;
populateExtraFiles(step, FS, params.extra_link_files);
populateFiles(step, FS);
@ -346,7 +382,7 @@ export async function linkARMTCC(step: BuildStep): Promise<WorkerResult> {
elfparser.sectionHeaders.forEach((section, index) => {
if (section.flags & 0x2) {
let data = objout.slice(section.offset, section.offset + section.size);
console.log(section.name, section.vmaddr.toString(16), data);
//console.log(section.name, section.vmaddr.toString(16), data);
rom.set(data, section.vmaddr);
}
});