summaryrefslogtreecommitdiff
path: root/tools/asm-processor
diff options
context:
space:
mode:
Diffstat (limited to 'tools/asm-processor')
-rw-r--r--tools/asm-processor/.gitignore2
-rw-r--r--tools/asm-processor/.gitrepo12
-rw-r--r--tools/asm-processor/LICENSE24
-rw-r--r--tools/asm-processor/README.md112
-rwxr-xr-xtools/asm-processor/add-test.sh5
-rw-r--r--tools/asm-processor/asm_processor.py1472
-rw-r--r--tools/asm-processor/build.py114
-rwxr-xr-xtools/asm-processor/compile-test.sh26
-rw-r--r--tools/asm-processor/prelude.inc43
-rwxr-xr-xtools/asm-processor/run-tests.sh6
-rw-r--r--tools/asm-processor/tests/ascii.c19
-rw-r--r--tools/asm-processor/tests/ascii.objdump29
-rw-r--r--tools/asm-processor/tests/comments.c6
-rw-r--r--tools/asm-processor/tests/comments.objdump21
-rw-r--r--tools/asm-processor/tests/force.c17
-rw-r--r--tools/asm-processor/tests/force.objdump47
-rw-r--r--tools/asm-processor/tests/kpic-o1.c93
-rw-r--r--tools/asm-processor/tests/kpic-o1.objdump46
-rw-r--r--tools/asm-processor/tests/kpic-o2.c92
-rw-r--r--tools/asm-processor/tests/kpic-o2.objdump46
-rw-r--r--tools/asm-processor/tests/label-sameline.c7
-rw-r--r--tools/asm-processor/tests/label-sameline.objdump25
-rw-r--r--tools/asm-processor/tests/large.c164
-rw-r--r--tools/asm-processor/tests/large.objdump58
-rw-r--r--tools/asm-processor/tests/late_rodata_align.c80
-rw-r--r--tools/asm-processor/tests/late_rodata_align.objdump51
-rw-r--r--tools/asm-processor/tests/late_rodata_doubles.c83
-rw-r--r--tools/asm-processor/tests/late_rodata_doubles.objdump55
-rw-r--r--tools/asm-processor/tests/late_rodata_doubles_mips1.c86
-rw-r--r--tools/asm-processor/tests/late_rodata_doubles_mips1.objdump52
-rw-r--r--tools/asm-processor/tests/late_rodata_jtbl.c153
-rw-r--r--tools/asm-processor/tests/late_rodata_jtbl.objdump110
-rw-r--r--tools/asm-processor/tests/late_rodata_jtbl_mips1.c155
-rw-r--r--tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump110
-rw-r--r--tools/asm-processor/tests/late_rodata_misaligned_doubles.c77
-rw-r--r--tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump56
-rw-r--r--tools/asm-processor/tests/line-continuation-separate-file.s4
-rw-r--r--tools/asm-processor/tests/line-continuation.asmproc.d3
-rw-r--r--tools/asm-processor/tests/line-continuation.c22
-rw-r--r--tools/asm-processor/tests/line-continuation.objdump30
-rw-r--r--tools/asm-processor/tests/o0.c28
-rw-r--r--tools/asm-processor/tests/o0.objdump44
-rw-r--r--tools/asm-processor/tests/o2.c26
-rw-r--r--tools/asm-processor/tests/o2.objdump40
-rw-r--r--tools/asm-processor/tests/pascal.objdump137
-rw-r--r--tools/asm-processor/tests/pascal.p95
-rw-r--r--tools/asm-processor/tests/static-global.c33
-rw-r--r--tools/asm-processor/tests/static-global.objdump58
-rw-r--r--tools/asm-processor/tests/static.c32
-rw-r--r--tools/asm-processor/tests/static.objdump58
-rw-r--r--tools/asm-processor/tests/test1.c71
-rw-r--r--tools/asm-processor/tests/test1.objdump54
-rw-r--r--tools/asm-processor/tests/test2.c69
-rw-r--r--tools/asm-processor/tests/test2.objdump76
-rw-r--r--tools/asm-processor/tests/test3.c70
-rw-r--r--tools/asm-processor/tests/test3.objdump64
56 files changed, 4568 insertions, 0 deletions
diff --git a/tools/asm-processor/.gitignore b/tools/asm-processor/.gitignore
new file mode 100644
index 0000000..cc5bba4
--- /dev/null
+++ b/tools/asm-processor/.gitignore
@@ -0,0 +1,2 @@
+*.o
+*.py[cod]
diff --git a/tools/asm-processor/.gitrepo b/tools/asm-processor/.gitrepo
new file mode 100644
index 0000000..ef2baa1
--- /dev/null
+++ b/tools/asm-processor/.gitrepo
@@ -0,0 +1,12 @@
+; DO NOT EDIT (unless you know what you are doing)
+;
+; This subdirectory is a git "subrepo", and this file is maintained by the
+; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme
+;
+[subrepo]
+ remote = git@github.com:simonlindholm/asm-processor.git
+ branch = main
+ commit = bbd86ea1faf84e6a7a0e101ab8068a00a3dfb2fc
+ parent = 75437386de04179489f4fd5fb345d122ff8a2dc0
+ method = merge
+ cmdver = 0.4.3
diff --git a/tools/asm-processor/LICENSE b/tools/asm-processor/LICENSE
new file mode 100644
index 0000000..cf1ab25
--- /dev/null
+++ b/tools/asm-processor/LICENSE
@@ -0,0 +1,24 @@
+This is free and unencumbered software released into the public domain.
+
+Anyone is free to copy, modify, publish, use, compile, sell, or
+distribute this software, either in source code form or as a compiled
+binary, for any purpose, commercial or non-commercial, and by any
+means.
+
+In jurisdictions that recognize copyright laws, the author or authors
+of this software dedicate any and all copyright interest in the
+software to the public domain. We make this dedication for the benefit
+of the public at large and to the detriment of our heirs and
+successors. We intend this dedication to be an overt act of
+relinquishment in perpetuity of all present and future rights to this
+software under copyright law.
+
+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 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.
+
+For more information, please refer to <http://unlicense.org>
diff --git a/tools/asm-processor/README.md b/tools/asm-processor/README.md
new file mode 100644
index 0000000..009147c
--- /dev/null
+++ b/tools/asm-processor/README.md
@@ -0,0 +1,112 @@
+# asm-processor
+
+Pre-process .c files and post-process .o files to enable embedding MIPS assembly into IDO-compiled C.
+
+## Usage
+
+Let's say you have a file compiled with `-g` on the IDO compiler, that looks like this:
+```c
+float func4(void) {
+ "func4";
+ return 0.2f;
+}
+```
+
+This script enables replacing it by:
+```asm
+GLOBAL_ASM(
+.rdata
+.word 0x66756e63 # func
+.word 0x34000000 # 4\0\0\0
+
+.late_rodata
+glabel rv
+.word 0x3e4ccccd # 0.2f
+
+.text
+glabel func4
+lui $at, %hi(rv)
+jr $ra
+lwc1 $f0, %lo(rv)($at)
+jr $ra
+nop
+jr $ra
+nop
+)
+```
+
+To compile the file, run `python3 build.py $CC -- $AS $ASFLAGS -- $CFLAGS -o out.o in.c`, where $CC points to an IDO binary (5.3/7.1 and recomp/qemu all supported), $AS is e.g. `mips-linux-gnu-as`, $ASFLAGS e.g. `-march=vr4300 -mabi=32` and $CFLAGS e.g. `-Wab,-r4300_mul -non_shared -G 0 -Xcpluscomm -g`. build.py may be customized as needed.
+
+In addition to an .o file, build.py also generates a .d file with Makefile dependencies for .s files referenced by the input .c file.
+This functionality may be removed if not needed.
+
+Reading assembly from file is also supported, by either `GLOBAL_ASM("file.s")` or `#pragma GLOBAL_ASM("file.s")`.
+
+### What is supported?
+
+`.text`, `.data`, `.bss` and `.rodata` sections, `.word`/`.incbin`, `.ascii`/`.asciz`, and `-g`, `-g3`, `-O1`, `-O2`, `-framepointer` and `-mips1`/`-mips2` flags to the IDO compiler.
+
+### What is not supported?
+
+* complicated assembly (.ifdef, macro declarations/calls other than `glabel`, pseudo-instructions that expand to several real instructions)
+* non-IDO compilers
+* `-O3` (due to function reordering)
+
+C `#ifdef`s only work outside of `GLOBAL_ASM` calls, but is otherwise able to replace `.ifdef`.
+
+### What's up with "late rodata"?
+
+The IDO compiler emits rodata in two passes: first array/string contents, then large literals/switch jump tables.
+
+Data declared within `.rdata`/`.section .rodata` will end up in the first half, and `.late_rodata`/`.section .late_rodata` in the second half.
+
+### How does it work?
+
+It's a bit of a hack!
+The basic idea is replace `GLOBAL_ASM` blocks with dummy C functions/global vars of the same sections sizes as the assembly.
+Then the C file gets compiled, and the dummy contents overwritten with the injected assembly.
+
+To accomplish this, asm-processor has logic for guessing the size of assembly contents
+(which assumes the assembly isn't too complicated, e.g. no macros),
+and for emitting C code of exact sizes for a bunch of different IDO compiler flags.
+
+The assembler code is padded with nops to line it up with its correct position in the C;
+this allows C and asm ELF files to be merged easily without having to fix up e.g. symbol addresses.
+
+The most difficult part is `late_rodata`, which is hard to create programmatically.
+asm-processor does that by emitting code that uses dummy float literals/double literals/jump tables,
+assembles the late_rodata at another location of the .rodata section, then overwrites the dummy rodata.
+This does require some movement of symbols and relocations, and quite a bit of care in what code to
+emit and how to preserve .double alignment.
+
+It's worth noting some alternative ways in which asm-processor would have been implemented:
+- One idea to get rid of the C/asm size estimations is to emit arbitrary code, and then move code,
+symbols and relocations to the correct place after the sizes are known.
+Given the machinery for `late_rodata` this wouldn't have been too difficult, and it would have the upside of improved portability.
+There is a big downside, however: using dummy code of incorrect size throws off alignment and can introduce unintended padding.
+Fixing this would require running multiple passes of asm-processor, with one compile per `ASM_GLOBAL`.
+- Another idea is to run the compiler with -S to emit assembly, modify the emitted assembly, then run the assembler
+(which in IDO's case may perform additional instruction reordering etc.).
+This option has not been investigated in much detail, and would perhaps be superior to the current implementation.
+It does have a few unknowns to it, e.g. instruction encoding differences between GNU `as` and IDO's assembler,
+how to avoid reordering the injected assembly, and how .rodata/.late_rodata are implemented.
+
+### Testing
+
+There are a few tests to ensure you don't break anything when hacking on asm-processor: `./run-tests.sh` should exit without output if they pass, or else output a diff from previous to new version.
+
+Tests need the environment variable `MIPS_CC` set to point to the IDO 7.1 compiler, with Pascal support enabled.
+
+For example if asm-processor is cloned in the same directory as [ido static recomp](https://github.com/decompals/ido-static-recomp) and the working directory is asm-processor, tests can be run using:
+
+```sh
+MIPS_CC=../ido-static-recomp/build/7.1/out/cc ./run-tests.sh
+```
+
+Or using [qemu-irix](https://github.com/zeldaret/oot/releases/tag/0.1q) (don't forget `chmod u+x qemu-irix`) to emulate IDO:
+
+```sh
+MIPS_CC='./qemu-irix -silent -L ../ido-static-recomp/ido/7.1/ ../ido-static-recomp/ido/7.1/usr/bin/cc' ./run-tests.sh
+```
+
+To skip running Pascal tests, remove the `tests/*.p` glob from `run-tests.sh`.
diff --git a/tools/asm-processor/add-test.sh b/tools/asm-processor/add-test.sh
new file mode 100755
index 0000000..708548e
--- /dev/null
+++ b/tools/asm-processor/add-test.sh
@@ -0,0 +1,5 @@
+#!/usr/bin/env bash
+for A in "$@"; do
+ OBJDUMPFLAGS="-srt"
+ ./compile-test.sh "$A" && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" > "${A%.*}.objdump"
+done
diff --git a/tools/asm-processor/asm_processor.py b/tools/asm-processor/asm_processor.py
new file mode 100644
index 0000000..0d62bc3
--- /dev/null
+++ b/tools/asm-processor/asm_processor.py
@@ -0,0 +1,1472 @@
+#!/usr/bin/env python3
+import argparse
+import tempfile
+import struct
+import copy
+import sys
+import re
+import os
+from collections import namedtuple
+from io import StringIO
+
+MAX_FN_SIZE = 100
+SLOW_CHECKS = False
+
+EI_NIDENT = 16
+EI_CLASS = 4
+EI_DATA = 5
+EI_VERSION = 6
+EI_OSABI = 7
+EI_ABIVERSION = 8
+STN_UNDEF = 0
+
+SHN_UNDEF = 0
+SHN_ABS = 0xfff1
+SHN_COMMON = 0xfff2
+SHN_XINDEX = 0xffff
+SHN_LORESERVE = 0xff00
+
+STT_NOTYPE = 0
+STT_OBJECT = 1
+STT_FUNC = 2
+STT_SECTION = 3
+STT_FILE = 4
+STT_COMMON = 5
+STT_TLS = 6
+
+STB_LOCAL = 0
+STB_GLOBAL = 1
+STB_WEAK = 2
+
+STV_DEFAULT = 0
+STV_INTERNAL = 1
+STV_HIDDEN = 2
+STV_PROTECTED = 3
+
+SHT_NULL = 0
+SHT_PROGBITS = 1
+SHT_SYMTAB = 2
+SHT_STRTAB = 3
+SHT_RELA = 4
+SHT_HASH = 5
+SHT_DYNAMIC = 6
+SHT_NOTE = 7
+SHT_NOBITS = 8
+SHT_REL = 9
+SHT_SHLIB = 10
+SHT_DYNSYM = 11
+SHT_INIT_ARRAY = 14
+SHT_FINI_ARRAY = 15
+SHT_PREINIT_ARRAY = 16
+SHT_GROUP = 17
+SHT_SYMTAB_SHNDX = 18
+SHT_MIPS_GPTAB = 0x70000003
+SHT_MIPS_DEBUG = 0x70000005
+SHT_MIPS_REGINFO = 0x70000006
+SHT_MIPS_OPTIONS = 0x7000000d
+
+SHF_WRITE = 0x1
+SHF_ALLOC = 0x2
+SHF_EXECINSTR = 0x4
+SHF_MERGE = 0x10
+SHF_STRINGS = 0x20
+SHF_INFO_LINK = 0x40
+SHF_LINK_ORDER = 0x80
+SHF_OS_NONCONFORMING = 0x100
+SHF_GROUP = 0x200
+SHF_TLS = 0x400
+
+R_MIPS_32 = 2
+R_MIPS_26 = 4
+R_MIPS_HI16 = 5
+R_MIPS_LO16 = 6
+
+MIPS_DEBUG_ST_STATIC = 2
+MIPS_DEBUG_ST_STATIC_PROC = 14
+
+
+class ElfFormat:
+ def __init__(self, is_big_endian):
+ self.is_big_endian = is_big_endian
+ self.struct_char = ">" if is_big_endian else "<"
+
+ def pack(self, fmt, *args):
+ return struct.pack(self.struct_char + fmt, *args)
+
+ def unpack(self, fmt, data):
+ return struct.unpack(self.struct_char + fmt, data)
+
+
+class ElfHeader:
+ """
+ typedef struct {
+ unsigned char e_ident[EI_NIDENT];
+ Elf32_Half e_type;
+ Elf32_Half e_machine;
+ Elf32_Word e_version;
+ Elf32_Addr e_entry;
+ Elf32_Off e_phoff;
+ Elf32_Off e_shoff;
+ Elf32_Word e_flags;
+ Elf32_Half e_ehsize;
+ Elf32_Half e_phentsize;
+ Elf32_Half e_phnum;
+ Elf32_Half e_shentsize;
+ Elf32_Half e_shnum;
+ Elf32_Half e_shstrndx;
+ } Elf32_Ehdr;
+ """
+
+ def __init__(self, data):
+ self.e_ident = data[:EI_NIDENT]
+ assert self.e_ident[EI_CLASS] == 1 # 32-bit
+ self.fmt = ElfFormat(is_big_endian=(self.e_ident[EI_DATA] == 2))
+ self.e_type, self.e_machine, self.e_version, self.e_entry, self.e_phoff, self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize, self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx = self.fmt.unpack('HHIIIIIHHHHHH', data[EI_NIDENT:])
+ assert self.e_type == 1 # relocatable
+ assert self.e_machine == 8 # MIPS I Architecture
+ assert self.e_phoff == 0 # no program header
+ assert self.e_shoff != 0 # section header
+ assert self.e_shstrndx != SHN_UNDEF
+
+ def to_bin(self):
+ return self.e_ident + self.fmt.pack('HHIIIIIHHHHHH', self.e_type,
+ self.e_machine, self.e_version, self.e_entry, self.e_phoff,
+ self.e_shoff, self.e_flags, self.e_ehsize, self.e_phentsize,
+ self.e_phnum, self.e_shentsize, self.e_shnum, self.e_shstrndx)
+
+
+class Symbol:
+ """
+ typedef struct {
+ Elf32_Word st_name;
+ Elf32_Addr st_value;
+ Elf32_Word st_size;
+ unsigned char st_info;
+ unsigned char st_other;
+ Elf32_Half st_shndx;
+ } Elf32_Sym;
+ """
+
+ def __init__(self, fmt, data, strtab, name=None):
+ self.fmt = fmt
+ self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx = fmt.unpack('IIIBBH', data)
+ assert self.st_shndx != SHN_XINDEX, "too many sections (SHN_XINDEX not supported)"
+ self.bind = st_info >> 4
+ self.type = st_info & 15
+ self.name = name if name is not None else strtab.lookup_str(self.st_name)
+ self.visibility = self.st_other & 3
+
+ @staticmethod
+ def from_parts(fmt, st_name, st_value, st_size, st_info, st_other, st_shndx, strtab, name):
+ header = fmt.pack('IIIBBH', st_name, st_value, st_size, st_info, st_other, st_shndx)
+ return Symbol(fmt, header, strtab, name)
+
+ def to_bin(self):
+ st_info = (self.bind << 4) | self.type
+ return self.fmt.pack('IIIBBH', self.st_name, self.st_value, self.st_size, st_info, self.st_other, self.st_shndx)
+
+
+class Relocation:
+ def __init__(self, fmt, data, sh_type):
+ self.fmt = fmt
+ self.sh_type = sh_type
+ if sh_type == SHT_REL:
+ self.r_offset, self.r_info = fmt.unpack('II', data)
+ else:
+ self.r_offset, self.r_info, self.r_addend = fmt.unpack('III', data)
+ self.sym_index = self.r_info >> 8
+ self.rel_type = self.r_info & 0xff
+
+ def to_bin(self):
+ self.r_info = (self.sym_index << 8) | self.rel_type
+ if self.sh_type == SHT_REL:
+ return self.fmt.pack('II', self.r_offset, self.r_info)
+ else:
+ return self.fmt.pack('III', self.r_offset, self.r_info, self.r_addend)
+
+
+class Section:
+ """
+ typedef struct {
+ Elf32_Word sh_name;
+ Elf32_Word sh_type;
+ Elf32_Word sh_flags;
+ Elf32_Addr sh_addr;
+ Elf32_Off sh_offset;
+ Elf32_Word sh_size;
+ Elf32_Word sh_link;
+ Elf32_Word sh_info;
+ Elf32_Word sh_addralign;
+ Elf32_Word sh_entsize;
+ } Elf32_Shdr;
+ """
+
+ def __init__(self, fmt, header, data, index):
+ self.fmt = fmt
+ self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize = fmt.unpack('IIIIIIIIII', header)
+ assert not self.sh_flags & SHF_LINK_ORDER
+ if self.sh_entsize != 0:
+ assert self.sh_size % self.sh_entsize == 0
+ if self.sh_type == SHT_NOBITS:
+ self.data = b''
+ else:
+ self.data = data[self.sh_offset:self.sh_offset + self.sh_size]
+ self.index = index
+ self.relocated_by = []
+
+ @staticmethod
+ def from_parts(fmt, sh_name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data, index):
+ header = fmt.pack('IIIIIIIIII', sh_name, sh_type, sh_flags, 0, 0, len(data), sh_link, sh_info, sh_addralign, sh_entsize)
+ return Section(fmt, header, data, index)
+
+ def lookup_str(self, index):
+ assert self.sh_type == SHT_STRTAB
+ to = self.data.find(b'\0', index)
+ assert to != -1
+ return self.data[index:to].decode('latin1')
+
+ def add_str(self, string):
+ assert self.sh_type == SHT_STRTAB
+ ret = len(self.data)
+ self.data += string.encode('latin1') + b'\0'
+ return ret
+
+ def is_rel(self):
+ return self.sh_type == SHT_REL or self.sh_type == SHT_RELA
+
+ def header_to_bin(self):
+ if self.sh_type != SHT_NOBITS:
+ self.sh_size = len(self.data)
+ return self.fmt.pack('IIIIIIIIII', self.sh_name, self.sh_type, self.sh_flags, self.sh_addr, self.sh_offset, self.sh_size, self.sh_link, self.sh_info, self.sh_addralign, self.sh_entsize)
+
+ def late_init(self, sections):
+ if self.sh_type == SHT_SYMTAB:
+ self.init_symbols(sections)
+ elif self.is_rel():
+ self.rel_target = sections[self.sh_info]
+ self.rel_target.relocated_by.append(self)
+ self.init_relocs()
+
+ def find_symbol(self, name):
+ assert self.sh_type == SHT_SYMTAB
+ for s in self.symbol_entries:
+ if s.name == name:
+ return (s.st_shndx, s.st_value)
+ return None
+
+ def find_symbol_in_section(self, name, section):
+ pos = self.find_symbol(name)
+ assert pos is not None
+ assert pos[0] == section.index
+ return pos[1]
+
+ def init_symbols(self, sections):
+ assert self.sh_type == SHT_SYMTAB
+ assert self.sh_entsize == 16
+ self.strtab = sections[self.sh_link]
+ entries = []
+ for i in range(0, self.sh_size, self.sh_entsize):
+ entries.append(Symbol(self.fmt, self.data[i:i+self.sh_entsize], self.strtab))
+ self.symbol_entries = entries
+
+ def init_relocs(self):
+ assert self.is_rel()
+ entries = []
+ for i in range(0, self.sh_size, self.sh_entsize):
+ entries.append(Relocation(self.fmt, self.data[i:i+self.sh_entsize], self.sh_type))
+ self.relocations = entries
+
+ def local_symbols(self):
+ assert self.sh_type == SHT_SYMTAB
+ return self.symbol_entries[:self.sh_info]
+
+ def global_symbols(self):
+ assert self.sh_type == SHT_SYMTAB
+ return self.symbol_entries[self.sh_info:]
+
+ def relocate_mdebug(self, original_offset):
+ assert self.sh_type == SHT_MIPS_DEBUG
+ new_data = bytearray(self.data)
+ shift_by = self.sh_offset - original_offset
+
+ # Update the file-relative offsets in the Symbolic HDRR
+ hdrr_magic, hdrr_vstamp, hdrr_ilineMax, hdrr_cbLine, \
+ hdrr_cbLineOffset, hdrr_idnMax, hdrr_cbDnOffset, hdrr_ipdMax, \
+ hdrr_cbPdOffset, hdrr_isymMax, hdrr_cbSymOffset, hdrr_ioptMax, \
+ hdrr_cbOptOffset, hdrr_iauxMax, hdrr_cbAuxOffset, hdrr_issMax, \
+ hdrr_cbSsOffset, hdrr_issExtMax, hdrr_cbSsExtOffset, hdrr_ifdMax, \
+ hdrr_cbFdOffset, hdrr_crfd, hdrr_cbRfdOffset, hdrr_iextMax, \
+ hdrr_cbExtOffset = self.fmt.unpack("HHIIIIIIIIIIIIIIIIIIIIIII", self.data[0:0x60])
+
+ assert hdrr_magic == 0x7009, "Invalid magic value for .mdebug symbolic header"
+
+ hdrr_cbLineOffset += shift_by
+ hdrr_cbDnOffset += shift_by
+ hdrr_cbPdOffset += shift_by
+ hdrr_cbSymOffset += shift_by
+ hdrr_cbOptOffset += shift_by
+ hdrr_cbAuxOffset += shift_by
+ hdrr_cbSsOffset += shift_by
+ hdrr_cbSsExtOffset += shift_by
+ hdrr_cbFdOffset += shift_by
+ hdrr_cbRfdOffset += shift_by
+ hdrr_cbExtOffset += shift_by
+
+ new_data[0:0x60] = self.fmt.pack("HHIIIIIIIIIIIIIIIIIIIIIII", hdrr_magic, hdrr_vstamp, hdrr_ilineMax, hdrr_cbLine, \
+ hdrr_cbLineOffset, hdrr_idnMax, hdrr_cbDnOffset, hdrr_ipdMax, \
+ hdrr_cbPdOffset, hdrr_isymMax, hdrr_cbSymOffset, hdrr_ioptMax, \
+ hdrr_cbOptOffset, hdrr_iauxMax, hdrr_cbAuxOffset, hdrr_issMax, \
+ hdrr_cbSsOffset, hdrr_issExtMax, hdrr_cbSsExtOffset, hdrr_ifdMax, \
+ hdrr_cbFdOffset, hdrr_crfd, hdrr_cbRfdOffset, hdrr_iextMax, \
+ hdrr_cbExtOffset)
+
+ self.data = bytes(new_data)
+
+class ElfFile:
+ def __init__(self, data):
+ self.data = data
+ assert data[:4] == b'\x7fELF', "not an ELF file"
+
+ self.elf_header = ElfHeader(data[0:52])
+ self.fmt = self.elf_header.fmt
+
+ offset, size = self.elf_header.e_shoff, self.elf_header.e_shentsize
+ null_section = Section(self.fmt, data[offset:offset + size], data, 0)
+ num_sections = self.elf_header.e_shnum or null_section.sh_size
+
+ self.sections = [null_section]
+ for i in range(1, num_sections):
+ ind = offset + i * size
+ self.sections.append(Section(self.fmt, data[ind:ind + size], data, i))
+
+ symtab = None
+ for s in self.sections:
+ if s.sh_type == SHT_SYMTAB:
+ assert not symtab
+ symtab = s
+ assert symtab is not None
+ self.symtab = symtab
+
+ shstr = self.sections[self.elf_header.e_shstrndx]
+ for s in self.sections:
+ s.name = shstr.lookup_str(s.sh_name)
+ s.late_init(self.sections)
+
+ def find_section(self, name):
+ for s in self.sections:
+ if s.name == name:
+ return s
+ return None
+
+ def add_section(self, name, sh_type, sh_flags, sh_link, sh_info, sh_addralign, sh_entsize, data):
+ shstr = self.sections[self.elf_header.e_shstrndx]
+ sh_name = shstr.add_str(name)
+ s = Section.from_parts(self.fmt, sh_name=sh_name, sh_type=sh_type,
+ sh_flags=sh_flags, sh_link=sh_link, sh_info=sh_info,
+ sh_addralign=sh_addralign, sh_entsize=sh_entsize, data=data,
+ index=len(self.sections))
+ self.sections.append(s)
+ s.name = name
+ s.late_init(self.sections)
+ return s
+
+ def drop_mdebug_gptab(self):
+ # We can only drop sections at the end, since otherwise section
+ # references might be wrong. Luckily, these sections typically are.
+ while self.sections[-1].sh_type in [SHT_MIPS_DEBUG, SHT_MIPS_GPTAB]:
+ self.sections.pop()
+
+ def write(self, filename):
+ outfile = open(filename, 'wb')
+ outidx = 0
+ def write_out(data):
+ nonlocal outidx
+ outfile.write(data)
+ outidx += len(data)
+ def pad_out(align):
+ if align and outidx % align:
+ write_out(b'\0' * (align - outidx % align))
+
+ self.elf_header.e_shnum = len(self.sections)
+ write_out(self.elf_header.to_bin())
+
+ for s in self.sections:
+ if s.sh_type != SHT_NOBITS and s.sh_type != SHT_NULL:
+ pad_out(s.sh_addralign)
+ old_offset = s.sh_offset
+ s.sh_offset = outidx
+ if s.sh_type == SHT_MIPS_DEBUG and s.sh_offset != old_offset:
+ # The .mdebug section has moved, relocate offsets
+ s.relocate_mdebug(old_offset)
+ write_out(s.data)
+
+ pad_out(4)
+ self.elf_header.e_shoff = outidx
+ for s in self.sections:
+ write_out(s.header_to_bin())
+
+ outfile.seek(0)
+ outfile.write(self.elf_header.to_bin())
+ outfile.close()
+
+
+def is_temp_name(name):
+ return name.startswith('_asmpp_')
+
+
+# https://stackoverflow.com/a/241506
+def re_comment_replacer(match):
+ s = match.group(0)
+ if s[0] in "/#":
+ return " "
+ else:
+ return s
+
+
+re_comment_or_string = re.compile(
+ r'#.*|/\*.*?\*/|"(?:\\.|[^\\"])*"'
+)
+
+
+class Failure(Exception):
+ def __init__(self, message):
+ self.message = message
+
+ def __str__(self):
+ return self.message
+
+
+class GlobalState:
+ def __init__(self, min_instr_count, skip_instr_count, use_jtbl_for_rodata, prelude_if_late_rodata, mips1, pascal):
+ # A value that hopefully never appears as a 32-bit rodata constant (or we
+ # miscompile late rodata). Increases by 1 in each step.
+ self.late_rodata_hex = 0xE0123456
+ self.valuectr = 0
+ self.namectr = 0
+ self.min_instr_count = min_instr_count
+ self.skip_instr_count = skip_instr_count
+ self.use_jtbl_for_rodata = use_jtbl_for_rodata
+ self.prelude_if_late_rodata = prelude_if_late_rodata
+ self.mips1 = mips1
+ self.pascal = pascal
+
+ def next_late_rodata_hex(self):
+ dummy_bytes = struct.pack('>I', self.late_rodata_hex)
+ if (self.late_rodata_hex & 0xffff) == 0:
+ # Avoid lui
+ self.late_rodata_hex += 1
+ self.late_rodata_hex += 1
+ return dummy_bytes
+
+ def make_name(self, cat):
+ self.namectr += 1
+ return '_asmpp_{}{}'.format(cat, self.namectr)
+
+ def func_prologue(self, name):
+ if self.pascal:
+ return " ".join([
+ "procedure {}();".format(name),
+ "type",
+ " pi = ^integer;",
+ " pf = ^single;",
+ " pd = ^double;",
+ "var",
+ " vi: pi;",
+ " vf: pf;",
+ " vd: pd;",
+ "begin",
+ " vi := vi;",
+ " vf := vf;",
+ " vd := vd;",
+ ])
+ else:
+ return 'void {}(void) {{'.format(name)
+
+ def func_epilogue(self):
+ if self.pascal:
+ return "end;"
+ else:
+ return "}"
+
+ def pascal_assignment(self, tp, val):
+ self.valuectr += 1
+ address = (8 * self.valuectr) & 0x7FFF
+ return 'v{} := p{}({}); v{}^ := {};'.format(tp, tp, address, tp, val)
+
+Function = namedtuple('Function', ['text_glabels', 'asm_conts', 'late_rodata_dummy_bytes', 'jtbl_rodata_size', 'late_rodata_asm_conts', 'fn_desc', 'data'])
+
+
+class GlobalAsmBlock:
+ def __init__(self, fn_desc):
+ self.fn_desc = fn_desc
+ self.cur_section = '.text'
+ self.asm_conts = []
+ self.late_rodata_asm_conts = []
+ self.late_rodata_alignment = 0
+ self.late_rodata_alignment_from_content = False
+ self.text_glabels = []
+ self.fn_section_sizes = {
+ '.text': 0,
+ '.data': 0,
+ '.bss': 0,
+ '.rodata': 0,
+ '.late_rodata': 0,
+ }
+ self.fn_ins_inds = []
+ self.glued_line = ''
+ self.num_lines = 0
+
+ def fail(self, message, line=None):
+ context = self.fn_desc
+ if line:
+ context += ", at line \"" + line + "\""
+ raise Failure(message + "\nwithin " + context)
+
+ def count_quoted_size(self, line, z, real_line, output_enc):
+ line = line.encode(output_enc).decode('latin1')
+ in_quote = False
+ has_comma = True
+ num_parts = 0
+ ret = 0
+ i = 0
+ digits = "0123456789" # 0-7 would be more sane, but this matches GNU as
+ while i < len(line):
+ c = line[i]
+ i += 1
+ if not in_quote:
+ if c == '"':
+ in_quote = True
+ if z and not has_comma:
+ self.fail(".asciiz with glued strings is not supported due to GNU as version diffs")
+ num_parts += 1
+ elif c == ',':
+ has_comma = True
+ else:
+ if c == '"':
+ in_quote = False
+ has_comma = False
+ continue
+ ret += 1
+ if c != '\\':
+ continue
+ if i == len(line):
+ self.fail("backslash at end of line not supported", real_line)
+ c = line[i]
+ i += 1
+ # (if c is in "bfnrtv", we have a real escaped literal)
+ if c == 'x':
+ # hex literal, consume any number of hex chars, possibly none
+ while i < len(line) and line[i] in digits + "abcdefABCDEF":
+ i += 1
+ elif c in digits:
+ # octal literal, consume up to two more digits
+ it = 0
+ while i < len(line) and line[i] in digits and it < 2:
+ i += 1
+ it += 1
+
+ if in_quote:
+ self.fail("unterminated string literal", real_line)
+ if num_parts == 0:
+ self.fail(".ascii with no string", real_line)
+ return ret + num_parts if z else ret
+
+ def align2(self):
+ while self.fn_section_sizes[self.cur_section] % 2 != 0:
+ self.fn_section_sizes[self.cur_section] += 1
+
+ def align4(self):
+ while self.fn_section_sizes[self.cur_section] % 4 != 0:
+ self.fn_section_sizes[self.cur_section] += 1
+
+ def add_sized(self, size, line):
+ if self.cur_section in ['.text', '.late_rodata']:
+ if size % 4 != 0:
+ self.fail("size must be a multiple of 4", line)
+ if size < 0:
+ self.fail("size cannot be negative", line)
+ self.fn_section_sizes[self.cur_section] += size
+ if self.cur_section == '.text':
+ if not self.text_glabels:
+ self.fail(".text block without an initial glabel", line)
+ self.fn_ins_inds.append((self.num_lines - 1, size // 4))
+
+ def process_line(self, line, output_enc):
+ self.num_lines += 1
+ if line.endswith('\\'):
+ self.glued_line += line[:-1]
+ return
+ line = self.glued_line + line
+ self.glued_line = ''
+
+ real_line = line
+ line = re.sub(re_comment_or_string, re_comment_replacer, line)
+ line = line.strip()
+ line = re.sub(r'^[a-zA-Z0-9_]+:\s*', '', line)
+ changed_section = False
+ emitting_double = False
+ if line.startswith('glabel ') and self.cur_section == '.text':
+ self.text_glabels.append(line.split()[1])
+ if not line:
+ pass # empty line
+ elif line.startswith('glabel ') or line.startswith('dlabel ') or line.startswith('endlabel ') or (' ' not in line and line.endswith(':')):
+ pass # label
+ elif line.startswith('.section') or line in ['.text', '.data', '.rdata', '.rodata', '.bss', '.late_rodata']:
+ # section change
+ self.cur_section = '.rodata' if line == '.rdata' else line.split(',')[0].split()[-1]
+ if self.cur_section not in ['.data', '.text', '.rodata', '.late_rodata', '.bss']:
+ self.fail("unrecognized .section directive", real_line)
+ changed_section = True
+ elif line.startswith('.late_rodata_alignment'):
+ if self.cur_section != '.late_rodata':
+ self.fail(".late_rodata_alignment must occur within .late_rodata section", real_line)
+ value = int(line.split()[1])
+ if value not in [4, 8]:
+ self.fail(".late_rodata_alignment argument must be 4 or 8", real_line)
+ if self.late_rodata_alignment and self.late_rodata_alignment != value:
+ self.fail(".late_rodata_alignment alignment assumption conflicts with earlier .double directive. Make sure to provide explicit alignment padding.")
+ self.late_rodata_alignment = value
+ changed_section = True
+ elif line.startswith('.incbin'):
+ self.add_sized(int(line.split(',')[-1].strip(), 0), real_line)
+ elif line.startswith('.word') or line.startswith('.gpword') or line.startswith('.float'):
+ self.align4()
+ self.add_sized(4 * len(line.split(',')), real_line)
+ elif line.startswith('.double'):
+ self.align4()
+ if self.cur_section == '.late_rodata':
+ align8 = self.fn_section_sizes[self.cur_section] % 8
+ # Automatically set late_rodata_alignment, so the generated C code uses doubles.
+ # This gives us correct alignment for the transferred doubles even when the
+ # late_rodata_alignment is wrong, e.g. for non-matching compilation.
+ if not self.late_rodata_alignment:
+ self.late_rodata_alignment = 8 - align8
+ self.late_rodata_alignment_from_content = True
+ elif self.late_rodata_alignment != 8 - align8:
+ if self.late_rodata_alignment_from_content:
+ self.fail("found two .double directives with different start addresses mod 8. Make sure to provide explicit alignment padding.", real_line)
+ else:
+ self.fail(".double at address that is not 0 mod 8 (based on .late_rodata_alignment assumption). Make sure to provide explicit alignment padding.", real_line)
+ self.add_sized(8 * len(line.split(',')), real_line)
+ emitting_double = True
+ elif line.startswith('.space'):
+ self.add_sized(int(line.split()[1], 0), real_line)
+ elif line.startswith('.balign') or line.startswith('.align'):
+ align = int(line.split()[1])
+ if align != 4:
+ self.fail("only .balign 4 is supported", real_line)
+ self.align4()
+ elif line.startswith('.asci'):
+ z = (line.startswith('.asciz') or line.startswith('.asciiz'))
+ self.add_sized(self.count_quoted_size(line, z, real_line, output_enc), real_line)
+ elif line.startswith('.byte'):
+ self.add_sized(len(line.split(',')), real_line)
+ elif line.startswith('.half'):
+ self.align2()
+ self.add_sized(2*len(line.split(',')), real_line)
+ elif line.startswith('.'):
+ # .macro, ...
+ self.fail("asm directive not supported", real_line)
+ else:
+ # Unfortunately, macros are hard to support for .rodata --
+ # we don't know how how space they will expand to before
+ # running the assembler, but we need that information to
+ # construct the C code. So if we need that we'll either
+ # need to run the assembler twice (at least in some rare
+ # cases), or change how this program is invoked.
+ # Similarly, we can't currently deal with pseudo-instructions
+ # that expand to several real instructions.
+ if self.cur_section != '.text':
+ self.fail("instruction or macro call in non-.text section? not supported", real_line)
+ self.add_sized(4, real_line)
+ if self.cur_section == '.late_rodata':
+ if not changed_section:
+ if emitting_double:
+ self.late_rodata_asm_conts.append(".align 0")
+ self.late_rodata_asm_conts.append(real_line)
+ if emitting_double:
+ self.late_rodata_asm_conts.append(".align 2")
+ else:
+ self.asm_conts.append(real_line)
+
+ def finish(self, state):
+ src = [''] * (self.num_lines + 1)
+ late_rodata_dummy_bytes = []
+ jtbl_rodata_size = 0
+ late_rodata_fn_output = []
+
+ num_instr = self.fn_section_sizes['.text'] // 4
+
+ if self.fn_section_sizes['.late_rodata'] > 0:
+ # Generate late rodata by emitting unique float constants.
+ # This requires 3 instructions for each 4 bytes of rodata.
+ # If we know alignment, we can use doubles, which give 3
+ # instructions for 8 bytes of rodata.
+ size = self.fn_section_sizes['.late_rodata'] // 4
+ skip_next = False
+ needs_double = (self.late_rodata_alignment != 0)
+ extra_mips1_nop = False
+ if state.pascal:
+ jtbl_size = 9 if state.mips1 else 8
+ jtbl_min_rodata_size = 2
+ else:
+ jtbl_size = 11 if state.mips1 else 9
+ jtbl_min_rodata_size = 5
+ for i in range(size):
+ if skip_next:
+ skip_next = False
+ continue
+ # Jump tables give 9 instructions (11 with -mips1) for >= 5 words of rodata,
+ # and should be emitted when:
+ # - -O2 or -O2 -g3 are used, which give the right codegen
+ # - we have emitted our first .float/.double (to ensure that we find the
+ # created rodata in the binary)
+ # - we have emitted our first .double, if any (to ensure alignment of doubles
+ # in shifted rodata sections)
+ # - we have at least 5 words of rodata left to emit (otherwise IDO does not
+ # generate a jump table)
+ # - we have at least 10 more instructions to go in this function (otherwise our
+ # function size computation will be wrong since the delay slot goes unused)
+ if (not needs_double and state.use_jtbl_for_rodata and i >= 1 and
+ size - i >= jtbl_min_rodata_size and
+ num_instr - len(late_rodata_fn_output) >= jtbl_size + 1):
+ if state.pascal:
+ cases = " ".join("{}: ;".format(case) for case in range(size - i))
+ line = "case 0 of " + cases + " otherwise end;"
+ else:
+ cases = " ".join("case {}:".format(case) for case in range(size - i))
+ line = "switch (*(volatile int*)0) { " + cases + " ; }"
+ late_rodata_fn_output.append(line)
+ late_rodata_fn_output.extend([""] * (jtbl_size - 1))
+ jtbl_rodata_size = (size - i) * 4
+ extra_mips1_nop = i != 2
+ break
+ dummy_bytes = state.next_late_rodata_hex()
+ late_rodata_dummy_bytes.append(dummy_bytes)
+ if self.late_rodata_alignment == 4 * ((i + 1) % 2 + 1) and i + 1 < size:
+ dummy_bytes2 = state.next_late_rodata_hex()
+ late_rodata_dummy_bytes.append(dummy_bytes2)
+ fval, = struct.unpack('>d', dummy_bytes + dummy_bytes2)
+ if state.pascal:
+ line = state.pascal_assignment('d', fval)
+ else:
+ line = '*(volatile double*)0 = {};'.format(fval)
+ late_rodata_fn_output.append(line)
+ skip_next = True
+ needs_double = False
+ if state.mips1:
+ # mips1 does not have ldc1/sdc1
+ late_rodata_fn_output.append('')
+ late_rodata_fn_output.append('')
+ extra_mips1_nop = False
+ else:
+ fval, = struct.unpack('>f', dummy_bytes)
+ if state.pascal:
+ line = state.pascal_assignment('f', fval)
+ else:
+ line = '*(volatile float*)0 = {}f;'.format(fval)
+ late_rodata_fn_output.append(line)
+ extra_mips1_nop = True
+ late_rodata_fn_output.append('')
+ late_rodata_fn_output.append('')
+ if state.mips1 and extra_mips1_nop:
+ late_rodata_fn_output.append('')
+
+ text_name = None
+ if self.fn_section_sizes['.text'] > 0 or late_rodata_fn_output:
+ text_name = state.make_name('func')
+ src[0] = state.func_prologue(text_name)
+ src[self.num_lines] = state.func_epilogue()
+ instr_count = self.fn_section_sizes['.text'] // 4
+ if instr_count < state.min_instr_count:
+ self.fail("too short .text block")
+ tot_emitted = 0
+ tot_skipped = 0
+ fn_emitted = 0
+ fn_skipped = 0
+ skipping = True
+ rodata_stack = late_rodata_fn_output[::-1]
+ for (line, count) in self.fn_ins_inds:
+ for _ in range(count):
+ if (fn_emitted > MAX_FN_SIZE and instr_count - tot_emitted > state.min_instr_count and
+ (not rodata_stack or rodata_stack[-1])):
+ # Don't let functions become too large. When a function reaches 284
+ # instructions, and -O2 -framepointer flags are passed, the IRIX
+ # compiler decides it is a great idea to start optimizing more.
+ # Also, Pascal cannot handle too large functions before it runs out
+ # of unique statements to write.
+ fn_emitted = 0
+ fn_skipped = 0
+ skipping = True
+ src[line] += (' ' + state.func_epilogue() + ' ' +
+ state.func_prologue(state.make_name('large_func')) + ' ')
+ if (
+ skipping and
+ fn_skipped < state.skip_instr_count +
+ (state.prelude_if_late_rodata if rodata_stack else 0)
+ ):
+ fn_skipped += 1
+ tot_skipped += 1
+ else:
+ skipping = False
+ if rodata_stack:
+ src[line] += rodata_stack.pop()
+ elif state.pascal:
+ src[line] += state.pascal_assignment('i', '0')
+ else:
+ src[line] += '*(volatile int*)0 = 0;'
+ tot_emitted += 1
+ fn_emitted += 1
+ if rodata_stack:
+ size = len(late_rodata_fn_output) // 3
+ available = instr_count - tot_skipped
+ self.fail(
+ "late rodata to text ratio is too high: {} / {} must be <= 1/3\n"
+ "add .late_rodata_alignment (4|8) to the .late_rodata "
+ "block to double the allowed ratio."
+ .format(size, available))
+
+ rodata_name = None
+ if self.fn_section_sizes['.rodata'] > 0:
+ if state.pascal:
+ self.fail(".rodata isn't supported with Pascal for now")
+ rodata_name = state.make_name('rodata')
+ src[self.num_lines] += ' const char {}[{}] = {{1}};'.format(rodata_name, self.fn_section_sizes['.rodata'])
+
+ data_name = None
+ if self.fn_section_sizes['.data'] > 0:
+ data_name = state.make_name('data')
+ if state.pascal:
+ line = ' var {}: packed array[1..{}] of char := [otherwise: 0];'.format(data_name, self.fn_section_sizes['.data'])
+ else:
+ line = ' char {}[{}] = {{1}};'.format(data_name, self.fn_section_sizes['.data'])
+ src[self.num_lines] += line
+
+ bss_name = None
+ if self.fn_section_sizes['.bss'] > 0:
+ if state.pascal:
+ self.fail(".bss isn't supported with Pascal")
+ bss_name = state.make_name('bss')
+ src[self.num_lines] += ' char {}[{}];'.format(bss_name, self.fn_section_sizes['.bss'])
+
+ fn = Function(
+ text_glabels=self.text_glabels,
+ asm_conts=self.asm_conts,
+ late_rodata_dummy_bytes=late_rodata_dummy_bytes,
+ jtbl_rodata_size=jtbl_rodata_size,
+ late_rodata_asm_conts=self.late_rodata_asm_conts,
+ fn_desc=self.fn_desc,
+ data={
+ '.text': (text_name, self.fn_section_sizes['.text']),
+ '.data': (data_name, self.fn_section_sizes['.data']),
+ '.rodata': (rodata_name, self.fn_section_sizes['.rodata']),
+ '.bss': (bss_name, self.fn_section_sizes['.bss']),
+ })
+ return src, fn
+
+cutscene_data_regexpr = re.compile(r"CutsceneData (.|\n)*\[\] = {")
+float_regexpr = re.compile(r"[-+]?[0-9]*\.?[0-9]+([eE][-+]?[0-9]+)?f")
+
+def repl_float_hex(m):
+ return str(struct.unpack(">I", struct.pack(">f", float(m.group(0).strip().rstrip("f"))))[0])
+
+Opts = namedtuple('Opts', ['opt', 'framepointer', 'mips1', 'kpic', 'pascal', 'input_enc', 'output_enc'])
+
+def parse_source(f, opts, out_dependencies, print_source=None):
+ if opts.opt in ['O1', 'O2']:
+ if opts.framepointer:
+ min_instr_count = 6
+ skip_instr_count = 5
+ else:
+ min_instr_count = 2
+ skip_instr_count = 1
+ elif opts.opt == 'O0':
+ if opts.framepointer:
+ min_instr_count = 8
+ skip_instr_count = 8
+ else:
+ min_instr_count = 4
+ skip_instr_count = 4
+ elif opts.opt == 'g':
+ if opts.framepointer:
+ min_instr_count = 7
+ skip_instr_count = 7
+ else:
+ min_instr_count = 4
+ skip_instr_count = 4
+ elif opts.opt == 'g3':
+ if opts.framepointer:
+ min_instr_count = 4
+ skip_instr_count = 4
+ else:
+ min_instr_count = 2
+ skip_instr_count = 2
+ else:
+ raise Failure("must pass one of -g, -O0, -O1, -O2, -O2 -g3")
+ prelude_if_late_rodata = 0
+ if opts.kpic:
+ # Without optimizations, the PIC prelude always takes up 3 instructions.
+ # With optimizations, the prelude is optimized out if there's no late rodata.
+ if opts.opt in ('g3', 'O2'):
+ prelude_if_late_rodata = 3
+ else:
+ min_instr_count += 3
+ skip_instr_count += 3
+
+ use_jtbl_for_rodata = False
+ if opts.opt in ['O2', 'g3'] and not opts.framepointer and not opts.kpic:
+ use_jtbl_for_rodata = True
+
+ state = GlobalState(min_instr_count, skip_instr_count, use_jtbl_for_rodata, prelude_if_late_rodata, opts.mips1, opts.pascal)
+ output_enc = opts.output_enc
+
+ global_asm = None
+ asm_functions = []
+ output_lines = [
+ '#line 1 "' + f.name + '"'
+ ]
+
+ is_cutscene_data = False
+ is_early_include = False
+
+ for line_no, raw_line in enumerate(f, 1):
+ raw_line = raw_line.rstrip()
+ line = raw_line.lstrip()
+
+ # Print exactly one output line per source line, to make compiler
+ # errors have correct line numbers. These will be overridden with
+ # reasonable content further down.
+ output_lines.append('')
+
+ if global_asm is not None:
+ if line.startswith(')'):
+ src, fn = global_asm.finish(state)
+ for i, line2 in enumerate(src):
+ output_lines[start_index + i] = line2
+ asm_functions.append(fn)
+ global_asm = None
+ else:
+ global_asm.process_line(raw_line, output_enc)
+ elif line in ['GLOBAL_ASM(', '#pragma GLOBAL_ASM(']:
+ global_asm = GlobalAsmBlock("GLOBAL_ASM block at line " + str(line_no))
+ start_index = len(output_lines)
+ elif ((line.startswith('GLOBAL_ASM("') or line.startswith('#pragma GLOBAL_ASM("'))
+ and line.endswith('")')):
+ fname = line[line.index('(') + 2 : -2]
+ out_dependencies.append(fname)
+ global_asm = GlobalAsmBlock(fname)
+ with open(fname, encoding=opts.input_enc) as f:
+ for line2 in f:
+ global_asm.process_line(line2.rstrip(), output_enc)
+ src, fn = global_asm.finish(state)
+ output_lines[-1] = ''.join(src)
+ asm_functions.append(fn)
+ global_asm = None
+ elif line == '#pragma asmproc recurse':
+ # C includes qualified as
+ # #pragma asmproc recurse
+ # #include "file.c"
+ # will be processed recursively when encountered
+ is_early_include = True
+ elif is_early_include:
+ # Previous line was a #pragma asmproc recurse
+ is_early_include = False
+ if not line.startswith("#include "):
+ raise Failure("#pragma asmproc recurse must be followed by an #include ")
+ fpath = os.path.dirname(f.name)
+ fname = os.path.join(fpath, line[line.index(' ') + 2 : -1])
+ out_dependencies.append(fname)
+ include_src = StringIO()
+ with open(fname, encoding=opts.input_enc) as include_file:
+ parse_source(include_file, opts, out_dependencies, include_src)
+ include_src.write('#line ' + str(line_no + 1) + ' "' + f.name + '"')
+ output_lines[-1] = include_src.getvalue()
+ include_src.close()
+ else:
+ # This is a hack to replace all floating-point numbers in an array of a particular type
+ # (in this case CutsceneData) with their corresponding IEEE-754 hexadecimal representation
+ if cutscene_data_regexpr.search(line) is not None:
+ is_cutscene_data = True
+ elif line.endswith("};"):
+ is_cutscene_data = False
+ if is_cutscene_data:
+ raw_line = re.sub(float_regexpr, repl_float_hex, raw_line)
+ output_lines[-1] = raw_line
+
+ if print_source:
+ if isinstance(print_source, StringIO):
+ for line in output_lines:
+ print_source.write(line + '\n')
+ else:
+ newline_encoded = "\n".encode(output_enc)
+ for line in output_lines:
+ try:
+ line_encoded = line.encode(output_enc)
+ except UnicodeEncodeError:
+ print("Failed to encode a line to", output_enc)
+ print("The line:", line)
+ print("The line, utf-8-encoded:", line.encode("utf-8"))
+ raise
+ print_source.write(line_encoded)
+ print_source.write(newline_encoded)
+ print_source.flush()
+
+ return asm_functions
+
+def fixup_objfile(objfile_name, functions, asm_prelude, assembler, output_enc, drop_mdebug_gptab, convert_statics):
+ SECTIONS = ['.data', '.text', '.rodata', '.bss']
+
+ with open(objfile_name, 'rb') as f:
+ objfile = ElfFile(f.read())
+ fmt = objfile.fmt
+
+ prev_locs = {
+ '.text': 0,
+ '.data': 0,
+ '.rodata': 0,
+ '.bss': 0,
+ }
+ to_copy = {
+ '.text': [],
+ '.data': [],
+ '.rodata': [],
+ '.bss': [],
+ }
+ asm = []
+ all_late_rodata_dummy_bytes = []
+ all_jtbl_rodata_size = []
+ late_rodata_asm = []
+ late_rodata_source_name_start = None
+ late_rodata_source_name_end = None
+
+ # Generate an assembly file with all the assembly we need to fill in. For
+ # simplicity we pad with nops/.space so that addresses match exactly, so we
+ # don't have to fix up relocations/symbol references.
+ all_text_glabels = set()
+ func_sizes = {}
+ for function in functions:
+ ifdefed = False
+ for sectype, (temp_name, size) in function.data.items():
+ if temp_name is None:
+ continue
+ assert size > 0
+ loc = objfile.symtab.find_symbol(temp_name)
+ if loc is None:
+ ifdefed = True
+ break
+ loc = loc[1]
+ prev_loc = prev_locs[sectype]
+ if loc < prev_loc:
+ # If the dummy C generates too little asm, and we have two
+ # consecutive GLOBAL_ASM blocks, we detect that error here.
+ # On the other hand, if it generates too much, we don't have
+ # a good way of discovering that error: it's indistinguishable
+ # from a static symbol occurring after the GLOBAL_ASM block.
+ raise Failure("Wrongly computed size for section {} (diff {}). This is an asm-processor bug!".format(sectype, prev_loc- loc))
+ if loc != prev_loc:
+ asm.append('.section ' + sectype)
+ if sectype == '.text':
+ for i in range((loc - prev_loc) // 4):
+ asm.append('nop')
+ else:
+ asm.append('.space {}'.format(loc - prev_loc))
+ to_copy[sectype].append((loc, size, temp_name, function.fn_desc))
+ if function.text_glabels and sectype == '.text':
+ func_sizes[function.text_glabels[0]] = size
+ prev_locs[sectype] = loc + size
+ if not ifdefed:
+ all_text_glabels.update(function.text_glabels)
+ all_late_rodata_dummy_bytes.append(function.late_rodata_dummy_bytes)
+ all_jtbl_rodata_size.append(function.jtbl_rodata_size)
+ late_rodata_asm.append(function.late_rodata_asm_conts)
+ for sectype, (temp_name, size) in function.data.items():
+ if temp_name is not None:
+ asm.append('.section ' + sectype)
+ asm.append('glabel ' + temp_name + '_asm_start')
+ asm.append('.text')
+ for line in function.asm_conts:
+ asm.append(line)
+ for sectype, (temp_name, size) in function.data.items():
+ if temp_name is not None:
+ asm.append('.section ' + sectype)
+ asm.append('glabel ' + temp_name + '_asm_end')
+ if any(late_rodata_asm):
+ late_rodata_source_name_start = '_asmpp_late_rodata_start'
+ late_rodata_source_name_end = '_asmpp_late_rodata_end'
+ asm.append('.section .late_rodata')
+ # Put some padding at the start to avoid conflating symbols with
+ # references to the whole section.
+ asm.append('.word 0, 0')
+ asm.append('glabel {}'.format(late_rodata_source_name_start))
+ for conts in late_rodata_asm:
+ asm.extend(conts)
+ asm.append('glabel {}'.format(late_rodata_source_name_end))
+
+ o_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.o', delete=False)
+ o_name = o_file.name
+ o_file.close()
+ s_file = tempfile.NamedTemporaryFile(prefix='asm-processor', suffix='.s', delete=False)
+ s_name = s_file.name
+ try:
+ s_file.write(asm_prelude + b'\n')
+ for line in asm:
+ s_file.write(line.encode(output_enc) + b'\n')
+ s_file.close()
+ ret = os.system(assembler + " " + s_name + " -o " + o_name)
+ if ret != 0:
+ raise Failure("failed to assemble")
+ with open(o_name, 'rb') as f:
+ asm_objfile = ElfFile(f.read())
+
+ # Remove clutter from objdump output for tests, and make the tests
+ # portable by avoiding absolute paths. Outside of tests .mdebug is
+ # useful for showing source together with asm, though.
+ mdebug_section = objfile.find_section('.mdebug')
+ if drop_mdebug_gptab:
+ objfile.drop_mdebug_gptab()
+
+ # Unify reginfo sections
+ target_reginfo = objfile.find_section('.reginfo')
+ if target_reginfo is not None:
+ source_reginfo_data = list(asm_objfile.find_section('.reginfo').data)
+ data = list(target_reginfo.data)
+ for i in range(20):
+ data[i] |= source_reginfo_data[i]
+ target_reginfo.data = bytes(data)
+
+ # Move over section contents
+ modified_text_positions = set()
+ jtbl_rodata_positions = set()
+ last_rodata_pos = 0
+ for sectype in SECTIONS:
+ if not to_copy[sectype]:
+ continue
+ source = asm_objfile.find_section(sectype)
+ assert source is not None, "didn't find source section: " + sectype
+ for (pos, count, temp_name, fn_desc) in to_copy[sectype]:
+ loc1 = asm_objfile.symtab.find_symbol_in_section(temp_name + '_asm_start', source)
+ loc2 = asm_objfile.symtab.find_symbol_in_section(temp_name + '_asm_end', source)
+ assert loc1 == pos, "assembly and C files don't line up for section " + sectype + ", " + fn_desc
+ if loc2 - loc1 != count:
+ raise Failure("incorrectly computed size for section " + sectype + ", " + fn_desc + ". If using .double, make sure to provide explicit alignment padding.")
+ if sectype == '.bss':
+ continue
+ target = objfile.find_section(sectype)
+ assert target is not None, "missing target section of type " + sectype
+ data = list(target.data)
+ for (pos, count, _, _) in to_copy[sectype]:
+ data[pos:pos + count] = source.data[pos:pos + count]
+ if sectype == '.text':
+ assert count % 4 == 0
+ assert pos % 4 == 0
+ for i in range(count // 4):
+ modified_text_positions.add(pos + 4 * i)
+ elif sectype == '.rodata':
+ last_rodata_pos = pos + count
+ target.data = bytes(data)
+
+ # Move over late rodata. This is heuristic, sadly, since I can't think
+ # of another way of doing it.
+ moved_late_rodata = {}
+ if any(all_late_rodata_dummy_bytes) or any(all_jtbl_rodata_size):
+ source = asm_objfile.find_section('.late_rodata')
+ target = objfile.find_section('.rodata')
+ source_pos = asm_objfile.symtab.find_symbol_in_section(late_rodata_source_name_start, source)
+ source_end = asm_objfile.symtab.find_symbol_in_section(late_rodata_source_name_end, source)
+ if source_end - source_pos != sum(map(len, all_late_rodata_dummy_bytes)) * 4 + sum(all_jtbl_rodata_size):
+ raise Failure("computed wrong size of .late_rodata")
+ new_data = list(target.data)
+ for dummy_bytes_list, jtbl_rodata_size in zip(all_late_rodata_dummy_bytes, all_jtbl_rodata_size):
+ for index, dummy_bytes in enumerate(dummy_bytes_list):
+ if not fmt.is_big_endian:
+ dummy_bytes = dummy_bytes[::-1]
+ pos = target.data.index(dummy_bytes, last_rodata_pos)
+ # This check is nice, but makes time complexity worse for large files:
+ if SLOW_CHECKS and target.data.find(dummy_bytes, pos + 4) != -1:
+ raise Failure("multiple occurrences of late_rodata hex magic. Change asm-processor to use something better than 0xE0123456!")
+ if index == 0 and len(dummy_bytes_list) > 1 and target.data[pos+4:pos+8] == b'\0\0\0\0':
+ # Ugly hack to handle double alignment for non-matching builds.
+ # We were told by .late_rodata_alignment (or deduced from a .double)
+ # that a function's late_rodata started out 4 (mod 8), and emitted
+ # a float and then a double. But it was actually 0 (mod 8), so our
+ # double was moved by 4 bytes. To make them adjacent to keep jump
+ # tables correct, move the float by 4 bytes as well.
+ new_data[pos:pos+4] = b'\0\0\0\0'
+ pos += 4
+ new_data[pos:pos+4] = source.data[source_pos:source_pos+4]
+ moved_late_rodata[source_pos] = pos
+ last_rodata_pos = pos + 4
+ source_pos += 4
+ if jtbl_rodata_size > 0:
+ assert dummy_bytes_list, "should always have dummy bytes before jtbl data"
+ pos = last_rodata_pos
+ new_data[pos : pos + jtbl_rodata_size] = \
+ source.data[source_pos : source_pos + jtbl_rodata_size]
+ for i in range(0, jtbl_rodata_size, 4):
+ moved_late_rodata[source_pos + i] = pos + i
+ jtbl_rodata_positions.add(pos + i)
+ last_rodata_pos += jtbl_rodata_size
+ source_pos += jtbl_rodata_size
+ target.data = bytes(new_data)
+
+ # Merge strtab data.
+ strtab_adj = len(objfile.symtab.strtab.data)
+ objfile.symtab.strtab.data += asm_objfile.symtab.strtab.data
+
+ # Find relocated symbols
+ relocated_symbols = set()
+ for sectype in SECTIONS + ['.late_rodata']:
+ for obj in [asm_objfile, objfile]:
+ sec = obj.find_section(sectype)
+ if sec is None:
+ continue
+ for reltab in sec.relocated_by:
+ for rel in reltab.relocations:
+ relocated_symbols.add(obj.symtab.symbol_entries[rel.sym_index])
+
+ # Move over symbols, deleting the temporary function labels.
+ # Skip over new local symbols that aren't relocated against, to
+ # avoid conflicts.
+ empty_symbol = objfile.symtab.symbol_entries[0]
+ new_syms = [s for s in objfile.symtab.symbol_entries[1:] if not is_temp_name(s.name)]
+
+ for i, s in enumerate(asm_objfile.symtab.symbol_entries):
+ is_local = (i < asm_objfile.symtab.sh_info)
+ if is_local and s not in relocated_symbols:
+ continue
+ if is_temp_name(s.name):
+ assert s not in relocated_symbols
+ continue
+ if s.st_shndx not in [SHN_UNDEF, SHN_ABS]:
+ section_name = asm_objfile.sections[s.st_shndx].name
+ target_section_name = section_name
+ if section_name == ".late_rodata":
+ target_section_name = ".rodata"
+ elif section_name not in SECTIONS:
+ raise Failure("generated assembly .o must only have symbols for .text, .data, .rodata, .late_rodata, ABS and UNDEF, but found " + section_name)
+ objfile_section = objfile.find_section(target_section_name)
+ if objfile_section is None:
+ raise Failure("generated assembly .o has section that real objfile lacks: " + target_section_name)
+ s.st_shndx = objfile_section.index
+ # glabel's aren't marked as functions, making objdump output confusing. Fix that.
+ if s.name in all_text_glabels:
+ s.type = STT_FUNC
+ if s.name in func_sizes:
+ s.st_size = func_sizes[s.name]
+ if section_name == '.late_rodata':
+ if s.st_value == 0:
+ # This must be a symbol corresponding to the whole .late_rodata
+ # section, being referred to from a relocation.
+ # Moving local symbols is tricky, because it requires fixing up
+ # lo16/hi16 relocation references to .late_rodata+<offset>.
+ # Just disallow it for now.
+ raise Failure("local symbols in .late_rodata are not allowed")
+ s.st_value = moved_late_rodata[s.st_value]
+ s.st_name += strtab_adj
+ new_syms.append(s)
+ make_statics_global = convert_statics in ("global", "global-with-filename")
+
+ # Add static symbols from .mdebug, so they can be referred to from GLOBAL_ASM
+ if mdebug_section and convert_statics != "no":
+ strtab_index = len(objfile.symtab.strtab.data)
+ new_strtab_data = []
+ ifd_max, cb_fd_offset = fmt.unpack('II', mdebug_section.data[18*4 : 20*4])
+ cb_sym_offset, = fmt.unpack('I', mdebug_section.data[9*4 : 10*4])
+ cb_ss_offset, = fmt.unpack('I', mdebug_section.data[15*4 : 16*4])
+ for i in range(ifd_max):
+ offset = cb_fd_offset + 18*4*i
+ iss_base, _, isym_base, csym = fmt.unpack('IIII', objfile.data[offset + 2*4 : offset + 6*4])
+ for j in range(csym):
+ offset2 = cb_sym_offset + 12 * (isym_base + j)
+ iss, value, st_sc_index = fmt.unpack('III', objfile.data[offset2 : offset2 + 12])
+ st = (st_sc_index >> 26)
+ sc = (st_sc_index >> 21) & 0x1f
+ if st in [MIPS_DEBUG_ST_STATIC, MIPS_DEBUG_ST_STATIC_PROC]:
+ symbol_name_offset = cb_ss_offset + iss_base + iss
+ symbol_name_offset_end = objfile.data.find(b'\0', symbol_name_offset)
+ assert symbol_name_offset_end != -1
+ symbol_name = objfile.data[symbol_name_offset : symbol_name_offset_end + 1]
+ emitted_symbol_name = symbol_name
+ if convert_statics == "global-with-filename":
+ # Change the emitted symbol name to include the filename,
+ # but don't let that affect deduplication logic.
+ emitted_symbol_name = objfile_name.encode("utf-8") + b":" + symbol_name
+ section_name = {1: '.text', 2: '.data', 3: '.bss', 15: '.rodata'}[sc]
+ section = objfile.find_section(section_name)
+ symtype = STT_FUNC if sc == 1 else STT_OBJECT
+ binding = STB_GLOBAL if make_statics_global else STB_LOCAL
+ sym = Symbol.from_parts(
+ fmt,
+ st_name=strtab_index,
+ st_value=value,
+ st_size=0,
+ st_info=(binding << 4 | symtype),
+ st_other=STV_DEFAULT,
+ st_shndx=section.index,
+ strtab=objfile.symtab.strtab,
+ name=symbol_name[:-1].decode('latin1'))
+ strtab_index += len(emitted_symbol_name)
+ new_strtab_data.append(emitted_symbol_name)
+ new_syms.append(sym)
+ objfile.symtab.strtab.data += b''.join(new_strtab_data)
+
+ # Get rid of duplicate symbols, favoring ones that are not UNDEF.
+ # Skip this for unnamed local symbols though.
+ new_syms.sort(key=lambda s: 0 if s.st_shndx != SHN_UNDEF else 1)
+ old_syms = []
+ newer_syms = []
+ name_to_sym = {}
+ for s in new_syms:
+ if s.name == "_gp_disp":
+ s.type = STT_OBJECT
+ if s.bind == STB_LOCAL and s.st_shndx == SHN_UNDEF:
+ raise Failure("local symbol \"" + s.name + "\" is undefined")
+ if not s.name:
+ if s.bind != STB_LOCAL:
+ raise Failure("global symbol with no name")
+ newer_syms.append(s)
+ else:
+ existing = name_to_sym.get(s.name)
+ if not existing:
+ name_to_sym[s.name] = s
+ newer_syms.append(s)
+ elif s.st_shndx != SHN_UNDEF:
+ raise Failure("symbol \"" + s.name + "\" defined twice")
+ else:
+ s.replace_by = existing
+ old_syms.append(s)
+ new_syms = newer_syms
+
+ # Put local symbols in front, with the initial dummy entry first, and
+ # _gp_disp at the end if it exists.
+ new_syms.insert(0, empty_symbol)
+ new_syms.sort(key=lambda s: (s.bind != STB_LOCAL, s.name == "_gp_disp"))
+ num_local_syms = sum(1 for s in new_syms if s.bind == STB_LOCAL)
+
+ for i, s in enumerate(new_syms):
+ s.new_index = i
+ for s in old_syms:
+ s.new_index = s.replace_by.new_index
+ objfile.symtab.data = b''.join(s.to_bin() for s in new_syms)
+ objfile.symtab.sh_info = num_local_syms
+
+ # Fix up relocation symbol references
+ for sectype in SECTIONS:
+ target = objfile.find_section(sectype)
+
+ if target is not None:
+ # fixup relocation symbol indices, since we butchered them above
+ for reltab in target.relocated_by:
+ nrels = []
+ for rel in reltab.relocations:
+ if (sectype == '.text' and rel.r_offset in modified_text_positions or
+ sectype == '.rodata' and rel.r_offset in jtbl_rodata_positions):
+ # don't include relocations for late_rodata dummy code
+ continue
+ rel.sym_index = objfile.symtab.symbol_entries[rel.sym_index].new_index
+ nrels.append(rel)
+ reltab.relocations = nrels
+ reltab.data = b''.join(rel.to_bin() for rel in nrels)
+
+ # Move over relocations
+ for sectype in SECTIONS + ['.late_rodata']:
+ source = asm_objfile.find_section(sectype)
+ if source is None or not source.data:
+ continue
+
+ target_sectype = '.rodata' if sectype == '.late_rodata' else sectype
+ target = objfile.find_section(target_sectype)
+ assert target is not None, target_sectype
+ target_reltab = objfile.find_section('.rel' + target_sectype)
+ target_reltaba = objfile.find_section('.rela' + target_sectype)
+ for reltab in source.relocated_by:
+ for rel in reltab.relocations:
+ rel.sym_index = asm_objfile.symtab.symbol_entries[rel.sym_index].new_index
+ if sectype == '.late_rodata':
+ rel.r_offset = moved_late_rodata[rel.r_offset]
+ new_data = b''.join(rel.to_bin() for rel in reltab.relocations)
+ if reltab.sh_type == SHT_REL:
+ if not target_reltab:
+ target_reltab = objfile.add_section('.rel' + target_sectype,
+ sh_type=SHT_REL, sh_flags=0,
+ sh_link=objfile.symtab.index, sh_info=target.index,
+ sh_addralign=4, sh_entsize=8, data=b'')
+ target_reltab.data += new_data
+ else:
+ if not target_reltaba:
+ target_reltaba = objfile.add_section('.rela' + target_sectype,
+ sh_type=SHT_RELA, sh_flags=0,
+ sh_link=objfile.symtab.index, sh_info=target.index,
+ sh_addralign=4, sh_entsize=12, data=b'')
+ target_reltaba.data += new_data
+
+ objfile.write(objfile_name)
+ finally:
+ s_file.close()
+ os.remove(s_name)
+ try:
+ os.remove(o_name)
+ except:
+ pass
+
+def run_wrapped(argv, outfile, functions):
+ parser = argparse.ArgumentParser(description="Pre-process .c files and post-process .o files to enable embedding assembly into C.")
+ parser.add_argument('filename', help="path to .c code")
+ parser.add_argument('--post-process', dest='objfile', help="path to .o file to post-process")
+ parser.add_argument('--assembler', dest='assembler', help="assembler command (e.g. \"mips-linux-gnu-as -march=vr4300 -mabi=32\")")
+ parser.add_argument('--asm-prelude', dest='asm_prelude', help="path to a file containing a prelude to the assembly file (with .set and .macro directives, e.g.)")
+ parser.add_argument('--input-enc', default='latin1', help="input encoding (default: %(default)s)")
+ parser.add_argument('--output-enc', default='latin1', help="output encoding (default: %(default)s)")
+ parser.add_argument('--drop-mdebug-gptab', dest='drop_mdebug_gptab', action='store_true', help="drop mdebug and gptab sections")
+ parser.add_argument('--convert-statics', dest='convert_statics', choices=["no", "local", "global", "global-with-filename"], default="local", help="change static symbol visibility (default: %(default)s)")
+ parser.add_argument('--force', dest='force', action='store_true', help="force processing of files without GLOBAL_ASM blocks")
+ parser.add_argument('-framepointer', dest='framepointer', action='store_true')
+ parser.add_argument('-mips1', dest='mips1', action='store_true')
+ parser.add_argument('-g3', dest='g3', action='store_true')
+ parser.add_argument('-KPIC', dest='kpic', action='store_true')
+ group = parser.add_mutually_exclusive_group(required=True)
+ group.add_argument('-O0', dest='opt', action='store_const', const='O0')
+ group.add_argument('-O1', dest='opt', action='store_const', const='O1')
+ group.add_argument('-O2', dest='opt', action='store_const', const='O2')
+ group.add_argument('-g', dest='opt', action='store_const', const='g')
+ args = parser.parse_args(argv)
+ opt = args.opt
+ pascal = any(args.filename.endswith(ext) for ext in (".p", ".pas", ".pp"))
+ if args.g3:
+ if opt != 'O2':
+ raise Failure("-g3 is only supported together with -O2")
+ opt = 'g3'
+ if args.mips1 and (opt not in ('O1', 'O2') or args.framepointer):
+ raise Failure("-mips1 is only supported together with -O1 or -O2")
+ if pascal and opt not in ('O1', 'O2', 'g3'):
+ raise Failure("Pascal is only supported together with -O1, -O2 or -O2 -g3")
+ opts = Opts(opt, args.framepointer, args.mips1, args.kpic, pascal, args.input_enc, args.output_enc)
+
+ if args.objfile is None:
+ with open(args.filename, encoding=args.input_enc) as f:
+ deps = []
+ functions = parse_source(f, opts, out_dependencies=deps, print_source=outfile)
+ return functions, deps
+ else:
+ if args.assembler is None:
+ raise Failure("must pass assembler command")
+ if functions is None:
+ with open(args.filename, encoding=args.input_enc) as f:
+ functions = parse_source(f, opts, out_dependencies=[])
+ if not functions and not args.force:
+ return
+ asm_prelude = b''
+ if args.asm_prelude:
+ with open(args.asm_prelude, 'rb') as f:
+ asm_prelude = f.read()
+ fixup_objfile(args.objfile, functions, asm_prelude, args.assembler, args.output_enc, args.drop_mdebug_gptab, args.convert_statics)
+
+def run(argv, outfile=sys.stdout.buffer, functions=None):
+ try:
+ return run_wrapped(argv, outfile, functions)
+ except Failure as e:
+ print("Error:", e, file=sys.stderr)
+ sys.exit(1)
+
+if __name__ == "__main__":
+ run(sys.argv[1:])
diff --git a/tools/asm-processor/build.py b/tools/asm-processor/build.py
new file mode 100644
index 0000000..efbaade
--- /dev/null
+++ b/tools/asm-processor/build.py
@@ -0,0 +1,114 @@
+#!/usr/bin/env python3
+import sys
+from pathlib import Path
+import shlex
+import subprocess
+import tempfile
+import uuid
+import asm_processor
+
+# Boolean for debugging purposes
+# Preprocessed files are temporary, set to True to keep a copy
+keep_preprocessed_files = False
+
+dir_path = Path(__file__).resolve().parent
+asm_prelude_path = dir_path / "prelude.inc"
+
+all_args = sys.argv[1:]
+sep0 = next(index for index, arg in enumerate(all_args) if not arg.startswith("-"))
+sep1 = all_args.index("--")
+sep2 = all_args.index("--", sep1 + 1)
+
+asmproc_flags = all_args[:sep0]
+compiler = all_args[sep0:sep1]
+
+assembler_args = all_args[sep1 + 1 : sep2]
+assembler_sh = " ".join(shlex.quote(x) for x in assembler_args)
+
+
+compile_args = all_args[sep2 + 1 :]
+
+in_file = Path(compile_args[-1])
+del compile_args[-1]
+
+out_ind = compile_args.index("-o")
+out_file = Path(compile_args[out_ind + 1])
+del compile_args[out_ind + 1]
+del compile_args[out_ind]
+
+
+in_dir = in_file.resolve().parent
+opt_flags = [
+ x for x in compile_args if x in {"-g3", "-g", "-O0", "-O1", "-O2", "-framepointer", "-KPIC"}
+]
+if "-mips2" not in compile_args:
+ opt_flags.append("-mips1")
+
+asmproc_flags += opt_flags + [str(in_file)]
+
+# Drop .mdebug and .gptab sections from resulting binaries. This makes
+# resulting .o files much smaller and speeds up builds, but loses line
+# number debug data.
+# asmproc_flags += ["--drop-mdebug-gptab"]
+
+# Convert encoding before compiling.
+# asmproc_flags += ["--input-enc", "utf-8", "--output-enc", "euc-jp"]
+
+with tempfile.TemporaryDirectory(prefix="asm_processor") as tmpdirname:
+ tmpdir_path = Path(tmpdirname)
+ preprocessed_filename = "preprocessed_" + uuid.uuid4().hex + in_file.suffix
+ preprocessed_path = tmpdir_path / preprocessed_filename
+
+ with preprocessed_path.open("wb") as f:
+ functions, deps = asm_processor.run(asmproc_flags, outfile=f)
+
+ if keep_preprocessed_files:
+ import shutil
+
+ keep_output_dir = Path("./asm_processor_preprocessed")
+ keep_output_dir.mkdir(parents=True, exist_ok=True)
+
+ shutil.copy(
+ preprocessed_path,
+ keep_output_dir / (in_file.stem + "_" + preprocessed_filename),
+ )
+
+ compile_cmdline = (
+ compiler
+ + compile_args
+ + ["-I", str(in_dir), "-o", str(out_file), str(preprocessed_path)]
+ )
+
+ try:
+ subprocess.check_call(compile_cmdline)
+ except subprocess.CalledProcessError as e:
+ print("Failed to compile file " + str(in_file) + ". Command line:")
+ print()
+ print(" ".join(shlex.quote(x) for x in compile_cmdline))
+ print()
+ sys.exit(55)
+
+ asm_processor.run(
+ asmproc_flags
+ + [
+ "--post-process",
+ str(out_file),
+ "--assembler",
+ assembler_sh,
+ "--asm-prelude",
+ str(asm_prelude_path),
+ ],
+ functions=functions,
+ )
+
+ deps_file = out_file.with_suffix(".asmproc.d")
+ if deps:
+ with deps_file.open("w") as f:
+ f.write(str(out_file) + ": " + " \\\n ".join(deps) + "\n")
+ for dep in deps:
+ f.write("\n" + dep + ":\n")
+ else:
+ try:
+ deps_file.unlink()
+ except OSError:
+ pass
diff --git a/tools/asm-processor/compile-test.sh b/tools/asm-processor/compile-test.sh
new file mode 100755
index 0000000..6551662
--- /dev/null
+++ b/tools/asm-processor/compile-test.sh
@@ -0,0 +1,26 @@
+#!/bin/bash
+set -o pipefail
+INPUT="$1"
+OUTPUT="${INPUT%.*}.o"
+
+rm -f "$OUTPUT"
+
+CC="$MIPS_CC" # ido 7.1 via recomp or qemu-irix
+AS="mips-linux-gnu-as"
+ASFLAGS="-march=vr4300 -mabi=32"
+OPTFLAGS=$(grep 'COMPILE-FLAGS: ' $INPUT | sed 's#^.*COMPILE-FLAGS: ##' | sed 's#}$##')
+ASMPFLAGS=$(grep 'ASMP-FLAGS: ' $INPUT | sed 's#^.*ASMP-FLAGS: ##' | sed 's#}$##')
+ISET=$(grep 'COMPILE-ISET: ' $INPUT | sed 's#^.*COMPILE-ISET: ##' | sed 's#}$##')
+if [[ -z "$OPTFLAGS" ]]; then
+ OPTFLAGS="-g"
+fi
+CFLAGS="-Wab,-r4300_mul -G 0 -Xcpluscomm -fullwarn -wlint -woff 819,820,852,821 -signed -c"
+if [[ -z "$ISET" ]]; then
+ CFLAGS="$CFLAGS -mips2"
+fi
+if [[ "$OPTFLAGS" != *-KPIC* ]]; then
+ CFLAGS="$CFLAGS -non_shared"
+fi
+
+set -e
+python3 build.py --drop-mdebug-gptab $ASMPFLAGS $CC -- $AS $ASFLAGS -- $CFLAGS $OPTFLAGS $ISET -o "$OUTPUT" "$INPUT"
diff --git a/tools/asm-processor/prelude.inc b/tools/asm-processor/prelude.inc
new file mode 100644
index 0000000..3e58ff1
--- /dev/null
+++ b/tools/asm-processor/prelude.inc
@@ -0,0 +1,43 @@
+.set noat
+.set noreorder
+.set gp=64
+.macro glabel label
+ .global \label
+ \label:
+.endm
+
+
+# Float register aliases (o32 ABI, odd ones are rarely used)
+
+.set $fv0, $f0
+.set $fv0f, $f1
+.set $fv1, $f2
+.set $fv1f, $f3
+.set $ft0, $f4
+.set $ft0f, $f5
+.set $ft1, $f6
+.set $ft1f, $f7
+.set $ft2, $f8
+.set $ft2f, $f9
+.set $ft3, $f10
+.set $ft3f, $f11
+.set $fa0, $f12
+.set $fa0f, $f13
+.set $fa1, $f14
+.set $fa1f, $f15
+.set $ft4, $f16
+.set $ft4f, $f17
+.set $ft5, $f18
+.set $ft5f, $f19
+.set $fs0, $f20
+.set $fs0f, $f21
+.set $fs1, $f22
+.set $fs1f, $f23
+.set $fs2, $f24
+.set $fs2f, $f25
+.set $fs3, $f26
+.set $fs3f, $f27
+.set $fs4, $f28
+.set $fs4f, $f29
+.set $fs5, $f30
+.set $fs5f, $f31
diff --git a/tools/asm-processor/run-tests.sh b/tools/asm-processor/run-tests.sh
new file mode 100755
index 0000000..5cae0a7
--- /dev/null
+++ b/tools/asm-processor/run-tests.sh
@@ -0,0 +1,6 @@
+#!/usr/bin/env bash
+for A in tests/*.c tests/*.p; do
+ OBJDUMPFLAGS=-srt
+ echo $A
+ ./compile-test.sh "$A" && mips-linux-gnu-objdump $OBJDUMPFLAGS "${A%.*}.o" | diff - "${A%.*}.objdump" || echo FAIL "$A"
+done
diff --git a/tools/asm-processor/tests/ascii.c b/tools/asm-processor/tests/ascii.c
new file mode 100644
index 0000000..bb27d25
--- /dev/null
+++ b/tools/asm-processor/tests/ascii.c
@@ -0,0 +1,19 @@
+void foo(void) { "abcdef"; }
+
+GLOBAL_ASM(
+.rdata
+ .ascii "AB"
+ .ascii "CD", "EF"
+ .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK"
+)
+
+void bar(void) { "hello"; }
+
+GLOBAL_ASM(
+.rdata
+ .asciiz "12"
+ .asciiz "34", "56"
+ .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A"
+)
+
+void baz(void) { "ghijkl"; }
diff --git a/tools/asm-processor/tests/ascii.objdump b/tools/asm-processor/tests/ascii.objdump
new file mode 100644
index 0000000..bf42638
--- /dev/null
+++ b/tools/asm-processor/tests/ascii.objdump
@@ -0,0 +1,29 @@
+
+tests/ascii.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000030 .text
+00000000 l d .rodata 00000050 .rodata
+00000000 g F .text 00000010 foo
+00000010 g F .text 00000010 bar
+00000020 g F .text 00000010 baz
+
+
+Contents of section .text:
+ 0000 03e00008 00000000 03e00008 00000000 ................
+ 0010 03e00008 00000000 03e00008 00000000 ................
+ 0020 03e00008 00000000 03e00008 00000000 ................
+Contents of section .rodata:
+ 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH
+ 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ
+ 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3
+ 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$
+ 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl..
+Contents of section .options:
+ 0000 01200000 00000000 80000000 00000000 . ..............
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000000 00000000 00000000 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/comments.c b/tools/asm-processor/tests/comments.c
new file mode 100644
index 0000000..4c93669
--- /dev/null
+++ b/tools/asm-processor/tests/comments.c
@@ -0,0 +1,6 @@
+const char before[] = "^";
+GLOBAL_ASM(
+.rdata
+.asciz "aaaa /* bbbb */ # cccc", /**//**//**//**/ /*/ "xxxx" /*/ /* dddd " eeee */ "# ffff" # gggg "hhhh" /* iiii */
+)
+const char after[] = "$";
diff --git a/tools/asm-processor/tests/comments.objdump b/tools/asm-processor/tests/comments.objdump
new file mode 100644
index 0000000..246df20
--- /dev/null
+++ b/tools/asm-processor/tests/comments.objdump
@@ -0,0 +1,21 @@
+
+tests/comments.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .rodata 00000030 .rodata
+00000000 g O .rodata 00000002 before
+00000024 g O .rodata 00000002 after
+
+
+Contents of section .rodata:
+ 0000 5e000000 61616161 202f2a20 62626262 ^...aaaa /* bbbb
+ 0010 202a2f20 23206363 63630023 20666666 */ # cccc.# fff
+ 0020 66000000 24000000 00000000 00000000 f...$...........
+Contents of section .options:
+ 0000 01200000 00000000 00000000 00000000 . ..............
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/force.c b/tools/asm-processor/tests/force.c
new file mode 100644
index 0000000..03b630c
--- /dev/null
+++ b/tools/asm-processor/tests/force.c
@@ -0,0 +1,17 @@
+// COMPILE-FLAGS: -O2
+// ASMP-FLAGS: --convert-statics=global-with-filename --force
+static int xtext(int a, int b, int c);
+const int rodata1[] = {1};
+static const int rodata2[] = {2};
+int data1[] = {3};
+static int data2[] = {4};
+int bss1;
+static int bss2;
+
+static int xtext(int a, int b, int c) {
+ return 1;
+}
+
+void baz(void) {
+ xtext(bss2, rodata2[0], data2[0]);
+}
diff --git a/tools/asm-processor/tests/force.objdump b/tools/asm-processor/tests/force.objdump
new file mode 100644
index 0000000..7ef7024
--- /dev/null
+++ b/tools/asm-processor/tests/force.objdump
@@ -0,0 +1,47 @@
+
+tests/force.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000050 .text
+00000000 l d .rodata 00000010 .rodata
+00000000 l d .data 00000010 .data
+00000000 l d .bss 00000010 .bss
+00000000 g O .rodata 00000004 rodata1
+00000000 g O .data 00000004 data1
+00000000 g O .bss 00000004 bss1
+00000014 g F .text 00000034 baz
+00000004 g O .rodata 00000000 tests/force.o:rodata2
+00000004 g O .data 00000000 tests/force.o:data2
+00000004 g O .bss 00000000 tests/force.o:bss2
+00000000 g F .text 00000000 tests/force.o:xtext
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+0000001c R_MIPS_HI16 .bss
+00000034 R_MIPS_LO16 .bss
+00000020 R_MIPS_HI16 .rodata
+0000002c R_MIPS_LO16 .rodata
+00000024 R_MIPS_HI16 .data
+00000028 R_MIPS_LO16 .data
+00000030 R_MIPS_26 .text
+
+
+Contents of section .text:
+ 0000 afa40000 afa50004 afa60008 03e00008 ................
+ 0010 24020001 27bdffe8 afbf0014 3c040000 $...'.......<...
+ 0020 3c050000 3c060000 8cc60004 8ca50004 <...<...........
+ 0030 0c000000 8c840004 8fbf0014 27bd0018 ............'...
+ 0040 03e00008 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 00000001 00000002 00000000 00000000 ................
+Contents of section .data:
+ 0000 00000003 00000004 00000000 00000000 ................
+Contents of section .options:
+ 0000 01200000 00000000 a0000074 00000000 . .........t....
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a0000074 00000000 00000000 00000000 ...t............
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/kpic-o1.c b/tools/asm-processor/tests/kpic-o1.c
new file mode 100644
index 0000000..4d3346d
--- /dev/null
+++ b/tools/asm-processor/tests/kpic-o1.c
@@ -0,0 +1,93 @@
+// COMPILE-FLAGS: -O1 -KPIC
+GLOBAL_ASM(
+glabel foo
+addiu $a0, $a0, 1
+addiu $a0, $a0, 2
+addiu $a0, $a0, 3
+addiu $a0, $a0, 4
+addiu $a0, $a0, 5
+addiu $a0, $a0, 6
+addiu $a0, $a0, 7
+addiu $a0, $a0, 8
+addiu $a0, $a0, 9
+addiu $a0, $a0, 10
+addiu $a0, $a0, 11
+addiu $a0, $a0, 12
+)
+GLOBAL_ASM(
+.late_rodata
+.float 1
+.text
+glabel float_fn
+addiu $a0, $a0, 13
+addiu $a0, $a0, 14
+addiu $a0, $a0, 15
+addiu $a0, $a0, 16
+addiu $a0, $a0, 17
+addiu $a0, $a0, 18
+addiu $a0, $a0, 19
+addiu $a0, $a0, 20
+addiu $a0, $a0, 21
+addiu $a0, $a0, 22
+addiu $a0, $a0, 23
+addiu $a0, $a0, 24
+addiu $a0, $a0, 25
+addiu $a0, $a0, 26
+addiu $a0, $a0, 27
+addiu $a0, $a0, 28
+addiu $a0, $a0, 29
+addiu $a0, $a0, 30
+)
+GLOBAL_ASM(
+.late_rodata
+.late_rodata_alignment 4
+.float 2
+.double 1
+.double 2
+.double 3
+.double 4
+.double 5
+.double 6
+.double 7
+.double 8
+.text
+glabel doubles
+addiu $a0, $a0, 31
+addiu $a0, $a0, 32
+addiu $a0, $a0, 33
+addiu $a0, $a0, 34
+addiu $a0, $a0, 35
+addiu $a0, $a0, 36
+addiu $a0, $a0, 37
+addiu $a0, $a0, 38
+addiu $a0, $a0, 39
+addiu $a0, $a0, 40
+addiu $a0, $a0, 41
+addiu $a0, $a0, 42
+addiu $a0, $a0, 43
+addiu $a0, $a0, 44
+addiu $a0, $a0, 45
+addiu $a0, $a0, 46
+addiu $a0, $a0, 47
+addiu $a0, $a0, 48
+addiu $a0, $a0, 49
+addiu $a0, $a0, 50
+addiu $a0, $a0, 51
+addiu $a0, $a0, 52
+addiu $a0, $a0, 53
+addiu $a0, $a0, 54
+addiu $a0, $a0, 55
+addiu $a0, $a0, 56
+addiu $a0, $a0, 57
+addiu $a0, $a0, 58
+addiu $a0, $a0, 59
+addiu $a0, $a0, 60
+addiu $a0, $a0, 61
+addiu $a0, $a0, 62
+addiu $a0, $a0, 63
+addiu $a0, $a0, 64
+addiu $a0, $a0, 65
+addiu $a0, $a0, 66
+addiu $a0, $a0, 67
+addiu $a0, $a0, 68
+)
diff --git a/tools/asm-processor/tests/kpic-o1.objdump b/tools/asm-processor/tests/kpic-o1.objdump
new file mode 100644
index 0000000..6e33675
--- /dev/null
+++ b/tools/asm-processor/tests/kpic-o1.objdump
@@ -0,0 +1,46 @@
+
+tests/kpic-o1.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000110 .text
+00000000 l d .rodata 00000050 .rodata
+00000000 g F .text 00000030 foo
+00000030 g F .text 00000048 float_fn
+00000078 g F .text 00000098 doubles
+00000000 O *UND* 00000000 _gp_disp
+
+
+RELOCATION RECORDS FOR [.text]: (none)
+
+Contents of section .text:
+ 0000 24840001 24840002 24840003 24840004 $...$...$...$...
+ 0010 24840005 24840006 24840007 24840008 $...$...$...$...
+ 0020 24840009 2484000a 2484000b 2484000c $...$...$...$...
+ 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$...
+ 0040 24840011 24840012 24840013 24840014 $...$...$...$...
+ 0050 24840015 24840016 24840017 24840018 $...$...$...$...
+ 0060 24840019 2484001a 2484001b 2484001c $...$...$...$...
+ 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$..
+ 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$
+ 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..(
+ 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$..,
+ 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0
+ 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4
+ 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8
+ 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..<
+ 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@
+ 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D
+Contents of section .rodata:
+ 0000 3f800000 40000000 3ff00000 00000000 ?...@...?.......
+ 0010 40000000 00000000 40080000 00000000 @.......@.......
+ 0020 40100000 00000000 40140000 00000000 @.......@.......
+ 0030 40180000 00000000 401c0000 00000000 @.......@.......
+ 0040 40200000 00000000 00000000 00000000 @ ..............
+Contents of section .options:
+ 0000 01200000 00000000 92000002 00000000 . ..............
+ 0010 000f0ff0 00000000 00000000 00000000 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 92000012 00000000 000f0ff0 00000000 ................
+ 0010 00000000 00000000 ........
diff --git a/tools/asm-processor/tests/kpic-o2.c b/tools/asm-processor/tests/kpic-o2.c
new file mode 100644
index 0000000..f037341
--- /dev/null
+++ b/tools/asm-processor/tests/kpic-o2.c
@@ -0,0 +1,92 @@
+// COMPILE-FLAGS: -O2 -KPIC
+GLOBAL_ASM(
+glabel foo
+addiu $a0, $a0, 1
+addiu $a0, $a0, 2
+addiu $a0, $a0, 3
+addiu $a0, $a0, 4
+addiu $a0, $a0, 5
+addiu $a0, $a0, 6
+addiu $a0, $a0, 7
+addiu $a0, $a0, 8
+addiu $a0, $a0, 9
+addiu $a0, $a0, 10
+addiu $a0, $a0, 11
+addiu $a0, $a0, 12
+)
+GLOBAL_ASM(
+.late_rodata
+.float 1
+.text
+glabel float_fn
+addiu $a0, $a0, 13
+addiu $a0, $a0, 14
+addiu $a0, $a0, 15
+addiu $a0, $a0, 16
+addiu $a0, $a0, 17
+addiu $a0, $a0, 18
+addiu $a0, $a0, 19
+addiu $a0, $a0, 20
+addiu $a0, $a0, 21
+addiu $a0, $a0, 22
+addiu $a0, $a0, 23
+addiu $a0, $a0, 24
+addiu $a0, $a0, 25
+addiu $a0, $a0, 26
+addiu $a0, $a0, 27
+addiu $a0, $a0, 28
+addiu $a0, $a0, 29
+addiu $a0, $a0, 30
+)
+GLOBAL_ASM(
+.late_rodata
+.float 2
+.double 1
+.double 2
+.double 3
+.double 4
+.double 5
+.double 6
+.double 7
+.double 8
+.text
+glabel doubles
+addiu $a0, $a0, 31
+addiu $a0, $a0, 32
+addiu $a0, $a0, 33
+addiu $a0, $a0, 34
+addiu $a0, $a0, 35
+addiu $a0, $a0, 36
+addiu $a0, $a0, 37
+addiu $a0, $a0, 38
+addiu $a0, $a0, 39
+addiu $a0, $a0, 40
+addiu $a0, $a0, 41
+addiu $a0, $a0, 42
+addiu $a0, $a0, 43
+addiu $a0, $a0, 44
+addiu $a0, $a0, 45
+addiu $a0, $a0, 46
+addiu $a0, $a0, 47
+addiu $a0, $a0, 48
+addiu $a0, $a0, 49
+addiu $a0, $a0, 50
+addiu $a0, $a0, 51
+addiu $a0, $a0, 52
+addiu $a0, $a0, 53
+addiu $a0, $a0, 54
+addiu $a0, $a0, 55
+addiu $a0, $a0, 56
+addiu $a0, $a0, 57
+addiu $a0, $a0, 58
+addiu $a0, $a0, 59
+addiu $a0, $a0, 60
+addiu $a0, $a0, 61
+addiu $a0, $a0, 62
+addiu $a0, $a0, 63
+addiu $a0, $a0, 64
+addiu $a0, $a0, 65
+addiu $a0, $a0, 66
+addiu $a0, $a0, 67
+addiu $a0, $a0, 68
+)
diff --git a/tools/asm-processor/tests/kpic-o2.objdump b/tools/asm-processor/tests/kpic-o2.objdump
new file mode 100644
index 0000000..abf87ae
--- /dev/null
+++ b/tools/asm-processor/tests/kpic-o2.objdump
@@ -0,0 +1,46 @@
+
+tests/kpic-o2.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000110 .text
+00000000 l d .rodata 00000050 .rodata
+00000000 g F .text 00000030 foo
+00000030 g F .text 00000048 float_fn
+00000078 g F .text 00000098 doubles
+00000000 O *UND* 00000000 _gp_disp
+
+
+RELOCATION RECORDS FOR [.text]: (none)
+
+Contents of section .text:
+ 0000 24840001 24840002 24840003 24840004 $...$...$...$...
+ 0010 24840005 24840006 24840007 24840008 $...$...$...$...
+ 0020 24840009 2484000a 2484000b 2484000c $...$...$...$...
+ 0030 2484000d 2484000e 2484000f 24840010 $...$...$...$...
+ 0040 24840011 24840012 24840013 24840014 $...$...$...$...
+ 0050 24840015 24840016 24840017 24840018 $...$...$...$...
+ 0060 24840019 2484001a 2484001b 2484001c $...$...$...$...
+ 0070 2484001d 2484001e 2484001f 24840020 $...$...$...$..
+ 0080 24840021 24840022 24840023 24840024 $..!$.."$..#$..$
+ 0090 24840025 24840026 24840027 24840028 $..%$..&$..'$..(
+ 00a0 24840029 2484002a 2484002b 2484002c $..)$..*$..+$..,
+ 00b0 2484002d 2484002e 2484002f 24840030 $..-$...$../$..0
+ 00c0 24840031 24840032 24840033 24840034 $..1$..2$..3$..4
+ 00d0 24840035 24840036 24840037 24840038 $..5$..6$..7$..8
+ 00e0 24840039 2484003a 2484003b 2484003c $..9$..:$..;$..<
+ 00f0 2484003d 2484003e 2484003f 24840040 $..=$..>$..?$..@
+ 0100 24840041 24840042 24840043 24840044 $..A$..B$..C$..D
+Contents of section .rodata:
+ 0000 3f800000 40000000 3ff00000 00000000 ?...@...?.......
+ 0010 40000000 00000000 40080000 00000000 @.......@.......
+ 0020 40100000 00000000 40140000 00000000 @.......@.......
+ 0030 40180000 00000000 401c0000 00000000 @.......@.......
+ 0040 40200000 00000000 00000000 00000000 @ ..............
+Contents of section .options:
+ 0000 01200000 00000000 92000002 00000000 . ..............
+ 0010 000f0ff0 00000000 00000000 00000000 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 92000012 00000000 000f0ff0 00000000 ................
+ 0010 00000000 00000000 ........
diff --git a/tools/asm-processor/tests/label-sameline.c b/tools/asm-processor/tests/label-sameline.c
new file mode 100644
index 0000000..a35b43d
--- /dev/null
+++ b/tools/asm-processor/tests/label-sameline.c
@@ -0,0 +1,7 @@
+GLOBAL_ASM(
+.rdata
+.word 0x12345678
+glabel blah
+.word blah2
+ /*a*/ blah2: /*b*/ .word blah /*c*/
+)
diff --git a/tools/asm-processor/tests/label-sameline.objdump b/tools/asm-processor/tests/label-sameline.objdump
new file mode 100644
index 0000000..1f1aacf
--- /dev/null
+++ b/tools/asm-processor/tests/label-sameline.objdump
@@ -0,0 +1,25 @@
+
+tests/label-sameline.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .rodata 00000010 .rodata
+00000000 l d .rodata 00000000
+00000004 g .rodata 00000000 blah
+
+
+RELOCATION RECORDS FOR [.rodata]:
+OFFSET TYPE VALUE
+00000004 R_MIPS_32
+00000008 R_MIPS_32 blah
+
+
+Contents of section .rodata:
+ 0000 12345678 00000008 00000000 00000000 .4Vx............
+Contents of section .options:
+ 0000 01200000 00000000 00000000 00000000 . ..............
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/large.c b/tools/asm-processor/tests/large.c
new file mode 100644
index 0000000..4ffb4ac
--- /dev/null
+++ b/tools/asm-processor/tests/large.c
@@ -0,0 +1,164 @@
+
+GLOBAL_ASM(
+glabel test
+
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+addiu $sp, $sp, -24
+ sw $zero, 4($sp)
+lw $t6, 4($sp)
+addu $t7, $a0, $t6
+sb $zero, ($t7)
+lw $t8, 4($sp)
+addiu $t9, $t8, 1
+slt $at, $t9, $a1
+ sw $t9, 4($sp)
+ nop
+jr $ra
+ addiu $sp, $sp, 24
+
+)
+
+void foo(void) {}
diff --git a/tools/asm-processor/tests/large.objdump b/tools/asm-processor/tests/large.objdump
new file mode 100644
index 0000000..17409a7
--- /dev/null
+++ b/tools/asm-processor/tests/large.objdump
@@ -0,0 +1,58 @@
+
+tests/large.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000280 .text
+00000270 g F .text 00000010 foo
+00000000 g F .text 00000270 test
+
+
+Contents of section .text:
+ 0000 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0010 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0020 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0030 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0040 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0050 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0060 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0070 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0080 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0090 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 00a0 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 00b0 afb90004 00000000 03e00008 27bd0018 ............'...
+ 00c0 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 00d0 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 00e0 afb90004 00000000 03e00008 27bd0018 ............'...
+ 00f0 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0100 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0110 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0120 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0130 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0140 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0150 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0160 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0170 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0180 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0190 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 01a0 afb90004 00000000 03e00008 27bd0018 ............'...
+ 01b0 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 01c0 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 01d0 afb90004 00000000 03e00008 27bd0018 ............'...
+ 01e0 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 01f0 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0200 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0210 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0220 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0230 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0240 27bdffe8 afa00004 8fae0004 008e7821 '.............x!
+ 0250 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0260 afb90004 00000000 03e00008 27bd0018 ............'...
+ 0270 03e00008 00000000 03e00008 00000000 ................
+Contents of section .options:
+ 0000 01200000 00000000 80000000 00000000 . ..............
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a300c032 00000000 00000000 00000000 ...2............
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/late_rodata_align.c b/tools/asm-processor/tests/late_rodata_align.c
new file mode 100644
index 0000000..7367c79
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_align.c
@@ -0,0 +1,80 @@
+GLOBAL_ASM(
+.late_rodata
+ .float 4.1
+ .float 4.2
+ .float 4.3
+ .float 4.4
+.text
+glabel a
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float foo(void) { "foo"; return 1.1f; }
+
+GLOBAL_ASM(
+.late_rodata
+.late_rodata_alignment 4
+ .float 5.1
+ .float 5.2
+ .float 5.3
+ .float 5.4
+.text
+glabel b
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float bar(void) { "bar"; return 1.2f; }
+
+GLOBAL_ASM(
+.late_rodata
+.late_rodata_alignment 8
+ .float 6.1
+ .float 6.2
+ .float 6.3
+ .float 6.4
+ .float 6.5
+.text
+glabel c
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
diff --git a/tools/asm-processor/tests/late_rodata_align.objdump b/tools/asm-processor/tests/late_rodata_align.objdump
new file mode 100644
index 0000000..87c05e8
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_align.objdump
@@ -0,0 +1,51 @@
+
+tests/late_rodata_align.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000000f0 .text
+00000000 l d .rodata 00000050 .rodata
+00000040 g F .text 0000001c foo
+00000090 g F .text 0000001c bar
+00000000 g F .text 00000040 a
+0000005c g F .text 00000034 b
+000000ac g F .text 00000038 c
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000040 R_MIPS_HI16 .rodata
+00000048 R_MIPS_LO16 .rodata
+00000090 R_MIPS_HI16 .rodata
+00000098 R_MIPS_LO16 .rodata
+
+
+Contents of section .text:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00000000 00000000 00000000 ................
+ 0020 00000000 00000000 00000000 00000000 ................
+ 0030 00000000 00000000 00000000 00000000 ................
+ 0040 3c010000 03e00008 c4200018 03e00008 <........ ......
+ 0050 00000000 03e00008 00000000 00000000 ................
+ 0060 00000000 00000000 00000000 00000000 ................
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 3c010000 03e00008 c420002c 03e00008 <........ .,....
+ 00a0 00000000 03e00008 00000000 00000000 ................
+ 00b0 00000000 00000000 00000000 00000000 ................
+ 00c0 00000000 00000000 00000000 00000000 ................
+ 00d0 00000000 00000000 00000000 00000000 ................
+ 00e0 00000000 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 666f6f00 62617200 40833333 40866666 foo.bar.@.33@.ff
+ 0010 4089999a 408ccccd 3f8ccccd 40a33333 @...@...?...@.33
+ 0020 40a66666 40a9999a 40accccd 3f99999a @.ff@...@...?...
+ 0030 40c33333 40c66666 40c9999a 40cccccd @.33@.ff@...@...
+ 0040 40d00000 00000000 00000000 00000000 @...............
+Contents of section .options:
+ 0000 01200000 00000000 80000002 00000000 . ..............
+ 0010 000005f1 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000002 00000000 000005f1 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/late_rodata_doubles.c b/tools/asm-processor/tests/late_rodata_doubles.c
new file mode 100644
index 0000000..0a27b41
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_doubles.c
@@ -0,0 +1,83 @@
+GLOBAL_ASM(
+.late_rodata
+ .float 4.1
+.text
+glabel a
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float foo(void) {
+ return 4.15f;
+}
+
+GLOBAL_ASM(
+.late_rodata
+ .float 4.2
+ .word 0
+ .double 4.3
+.text
+glabel b
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float bar(void) {
+ return 4.4f;
+}
+
+GLOBAL_ASM(
+.late_rodata
+ .float 4.55
+ .double 4.6
+.text
+glabel c
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float baz(void) {
+ return 4.6f;
+}
diff --git a/tools/asm-processor/tests/late_rodata_doubles.objdump b/tools/asm-processor/tests/late_rodata_doubles.objdump
new file mode 100644
index 0000000..84d7e67
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_doubles.objdump
@@ -0,0 +1,55 @@
+
+tests/late_rodata_doubles.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000120 .text
+00000000 l d .rodata 00000030 .rodata
+00000040 g F .text 0000001c foo
+0000009c g F .text 0000001c bar
+000000f8 g F .text 0000001c baz
+00000000 g F .text 00000040 a
+0000005c g F .text 00000040 b
+000000b8 g F .text 00000040 c
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000040 R_MIPS_HI16 .rodata
+00000048 R_MIPS_LO16 .rodata
+0000009c R_MIPS_HI16 .rodata
+000000a4 R_MIPS_LO16 .rodata
+000000f8 R_MIPS_HI16 .rodata
+00000100 R_MIPS_LO16 .rodata
+
+
+Contents of section .text:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00000000 00000000 00000000 ................
+ 0020 00000000 00000000 00000000 00000000 ................
+ 0030 00000000 00000000 00000000 00000000 ................
+ 0040 3c010000 03e00008 c4200004 03e00008 <........ ......
+ 0050 00000000 03e00008 00000000 00000000 ................
+ 0060 00000000 00000000 00000000 00000000 ................
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 00000000 00000000 00000000 3c010000 ............<...
+ 00a0 03e00008 c4200018 03e00008 00000000 ..... ..........
+ 00b0 03e00008 00000000 00000000 00000000 ................
+ 00c0 00000000 00000000 00000000 00000000 ................
+ 00d0 00000000 00000000 00000000 00000000 ................
+ 00e0 00000000 00000000 00000000 00000000 ................
+ 00f0 00000000 00000000 3c010000 03e00008 ........<.......
+ 0100 c4200028 03e00008 00000000 03e00008 . .(............
+ 0110 00000000 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff....
+ 0010 40113333 33333333 408ccccd 4091999a @.333333@...@...
+ 0020 40126666 66666666 40933333 00000000 @.ffffff@.33....
+Contents of section .options:
+ 0000 01200000 00000000 80000002 00000000 . ..............
+ 0010 000000f1 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000002 00000000 000000f1 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/late_rodata_doubles_mips1.c b/tools/asm-processor/tests/late_rodata_doubles_mips1.c
new file mode 100644
index 0000000..b97261f
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_doubles_mips1.c
@@ -0,0 +1,86 @@
+// COMPILE-FLAGS: -O2
+// COMPILE-ISET: -mips1
+// exact copy of late_rodata_doubles.c except for the -mips1 -O2 additions
+GLOBAL_ASM(
+.late_rodata
+ .float 4.1
+.text
+glabel a
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float foo(void) {
+ return 4.15f;
+}
+
+GLOBAL_ASM(
+.late_rodata
+ .float 4.2
+ .word 0
+ .double 4.3
+.text
+glabel b
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float bar(void) {
+ return 4.4f;
+}
+
+GLOBAL_ASM(
+.late_rodata
+ .float 4.55
+ .double 4.6
+.text
+glabel c
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+float baz(void) {
+ return 4.6f;
+}
diff --git a/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump b/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump
new file mode 100644
index 0000000..8fac85f
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_doubles_mips1.objdump
@@ -0,0 +1,52 @@
+
+tests/late_rodata_doubles_mips1.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000000f0 .text
+00000000 l d .rodata 00000030 .rodata
+00000040 g F .text 00000010 foo
+00000090 g F .text 00000010 bar
+000000e0 g F .text 00000010 baz
+00000000 g F .text 00000040 a
+00000050 g F .text 00000040 b
+000000a0 g F .text 00000040 c
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000040 R_MIPS_HI16 .rodata
+00000044 R_MIPS_LO16 .rodata
+00000090 R_MIPS_HI16 .rodata
+00000094 R_MIPS_LO16 .rodata
+000000e0 R_MIPS_HI16 .rodata
+000000e4 R_MIPS_LO16 .rodata
+
+
+Contents of section .text:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00000000 00000000 00000000 ................
+ 0020 00000000 00000000 00000000 00000000 ................
+ 0030 00000000 00000000 00000000 00000000 ................
+ 0040 3c010000 c4200004 03e00008 00000000 <.... ..........
+ 0050 00000000 00000000 00000000 00000000 ................
+ 0060 00000000 00000000 00000000 00000000 ................
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 3c010000 c4200018 03e00008 00000000 <.... ..........
+ 00a0 00000000 00000000 00000000 00000000 ................
+ 00b0 00000000 00000000 00000000 00000000 ................
+ 00c0 00000000 00000000 00000000 00000000 ................
+ 00d0 00000000 00000000 00000000 00000000 ................
+ 00e0 3c010000 c4200028 03e00008 00000000 <.... .(........
+Contents of section .rodata:
+ 0000 40833333 4084cccd 40866666 00000000 @.33@...@.ff....
+ 0010 40113333 33333333 408ccccd 4091999a @.333333@...@...
+ 0020 40126666 66666666 40933333 00000000 @.ffffff@.33....
+Contents of section .options:
+ 0000 01200000 00000000 80000002 00000000 . ..............
+ 0010 000c0011 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000002 00000000 000c0011 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/late_rodata_jtbl.c b/tools/asm-processor/tests/late_rodata_jtbl.c
new file mode 100644
index 0000000..3c2a5bb
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_jtbl.c
@@ -0,0 +1,153 @@
+// COMPILE-FLAGS: -O2
+GLOBAL_ASM(
+.late_rodata
+.double 1
+.double 2
+.double 3
+.double 4
+.double 5
+.double 6
+.double 7
+.double 8
+.text
+glabel doubles1
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+)
+
+float a(void) { return 1.1f; }
+
+GLOBAL_ASM(
+.late_rodata
+.float 1
+.double 2
+.double 3
+.double 4
+.double 5
+.double 6
+.double 7
+.double 8
+.double 9
+.float 10
+.text
+glabel doubles2
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+)
+
+GLOBAL_ASM(
+glabel a2
+move $a0, $a0
+nop
+nop
+nop
+jr $ra
+move $a0, $a0
+)
+
+GLOBAL_ASM(
+.late_rodata
+
+glabel jtbl
+.word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10
+.word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20
+.word case21, case22, case23, case24, case25, case26
+
+.text
+glabel foo
+sltiu $at, $a0, 0xa
+beqz $at, .L756E659B
+ sll $t7, $a0, 2
+lui $at, %hi(jtbl)
+addu $at, $at, $t7
+lw $t7, %lo(jtbl)($at)
+jr $t7
+ nop
+case0: addiu $a0, $a0, 1
+case1: addiu $a0, $a0, 1
+case2: addiu $a0, $a0, 1
+case3: addiu $a0, $a0, 1
+case4: addiu $a0, $a0, 1
+case5: addiu $a0, $a0, 1
+case6: addiu $a0, $a0, 1
+case7: addiu $a0, $a0, 1
+case8: addiu $a0, $a0, 1
+case9: addiu $a0, $a0, 1
+case10: addiu $a0, $a0, 1
+case11: addiu $a0, $a0, 1
+case12: addiu $a0, $a0, 1
+case13: addiu $a0, $a0, 1
+case14: addiu $a0, $a0, 1
+case15: addiu $a0, $a0, 1
+case16: addiu $a0, $a0, 1
+case17: addiu $a0, $a0, 1
+case18: addiu $a0, $a0, 1
+case19: addiu $a0, $a0, 1
+case20: addiu $a0, $a0, 1
+case21: addiu $a0, $a0, 1
+case22: addiu $a0, $a0, 1
+case23: addiu $a0, $a0, 1
+case24: addiu $a0, $a0, 1
+case25: addiu $a0, $a0, 1
+case26:
+jr $ra
+ addiu $v0, $a0, 1
+
+.L756E659B:
+addiu $v0, $zero, 2
+jr $ra
+ nop
+)
+
+GLOBAL_ASM(
+glabel b2
+move $a0, $a0
+nop
+nop
+jr $ra
+move $a0, $a0
+)
+
+float b(void) { return 1.2f; }
diff --git a/tools/asm-processor/tests/late_rodata_jtbl.objdump b/tools/asm-processor/tests/late_rodata_jtbl.objdump
new file mode 100644
index 0000000..44bb6e8
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_jtbl.objdump
@@ -0,0 +1,110 @@
+
+tests/late_rodata_jtbl.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000001a0 .text
+00000000 l d .rodata 00000100 .rodata
+00000000 l d .text 00000000
+0000005c g F .text 0000000c a
+0000018c g F .text 0000000c b
+00000000 g F .text 0000005c doubles1
+00000068 g F .text 0000005c doubles2
+000000c4 g F .text 00000018 a2
+000000dc g F .text 0000009c foo
+0000008c g .rodata 00000000 jtbl
+00000178 g F .text 00000014 b2
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+0000005c R_MIPS_HI16 .rodata
+00000064 R_MIPS_LO16 .rodata
+0000018c R_MIPS_HI16 .rodata
+00000194 R_MIPS_LO16 .rodata
+000000e8 R_MIPS_HI16 jtbl
+000000f0 R_MIPS_LO16 jtbl
+
+
+RELOCATION RECORDS FOR [.rodata]:
+OFFSET TYPE VALUE
+0000008c R_MIPS_32
+00000090 R_MIPS_32
+00000094 R_MIPS_32
+00000098 R_MIPS_32
+0000009c R_MIPS_32
+000000a0 R_MIPS_32
+000000a4 R_MIPS_32
+000000a8 R_MIPS_32
+000000ac R_MIPS_32
+000000b0 R_MIPS_32
+000000b4 R_MIPS_32
+000000b8 R_MIPS_32
+000000bc R_MIPS_32
+000000c0 R_MIPS_32
+000000c4 R_MIPS_32
+000000c8 R_MIPS_32
+000000cc R_MIPS_32
+000000d0 R_MIPS_32
+000000d4 R_MIPS_32
+000000d8 R_MIPS_32
+000000dc R_MIPS_32
+000000e0 R_MIPS_32
+000000e4 R_MIPS_32
+000000e8 R_MIPS_32
+000000ec R_MIPS_32
+000000f0 R_MIPS_32
+000000f4 R_MIPS_32
+
+
+Contents of section .text:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00000000 00000000 00000000 ................
+ 0020 00000000 00000000 00000000 00000000 ................
+ 0030 00000000 00000000 00000000 00000000 ................
+ 0040 00000000 00000000 00000000 00000000 ................
+ 0050 00000000 00000000 00000000 3c010000 ............<...
+ 0060 03e00008 c4200040 00000000 00000000 ..... .@........
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 00000000 00000000 00000000 00000000 ................
+ 00a0 00000000 00000000 00000000 00000000 ................
+ 00b0 00000000 00000000 00000000 00000000 ................
+ 00c0 00000000 00802025 00000000 00000000 ...... %........
+ 00d0 00000000 03e00008 00802025 2c81000a .......... %,...
+ 00e0 10200022 00047880 3c010000 002f0821 . ."..x.<..../.!
+ 00f0 8c2f0000 01e00008 00000000 24840001 ./..........$...
+ 0100 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0110 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0120 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0130 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0140 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0150 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0160 24840001 03e00008 24820001 24020002 $.......$...$...
+ 0170 03e00008 00000000 00802025 00000000 .......... %....
+ 0180 00000000 03e00008 00802025 3c010000 .......... %<...
+ 0190 03e00008 c42000f8 00000000 00000000 ..... ..........
+Contents of section .rodata:
+ 0000 3ff00000 00000000 40000000 00000000 ?.......@.......
+ 0010 40080000 00000000 40100000 00000000 @.......@.......
+ 0020 40140000 00000000 40180000 00000000 @.......@.......
+ 0030 401c0000 00000000 40200000 00000000 @.......@ ......
+ 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@.......
+ 0050 40080000 00000000 40100000 00000000 @.......@.......
+ 0060 40140000 00000000 40180000 00000000 @.......@.......
+ 0070 401c0000 00000000 40200000 00000000 @.......@ ......
+ 0080 40220000 00000000 41200000 000000fc @"......A ......
+ 0090 00000100 00000104 00000108 0000010c ................
+ 00a0 00000110 00000114 00000118 0000011c ................
+ 00b0 00000120 00000124 00000128 0000012c ... ...$...(...,
+ 00c0 00000130 00000134 00000138 0000013c ...0...4...8...<
+ 00d0 00000140 00000144 00000148 0000014c ...@...D...H...L
+ 00e0 00000150 00000154 00000158 0000015c ...P...T...X...\
+ 00f0 00000160 00000164 3f99999a 00000000 ...`...d?.......
+Contents of section .options:
+ 0000 01200000 00000000 80004002 00000000 . ........@.....
+ 0010 000000f1 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 8000c016 00000000 000000f1 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/late_rodata_jtbl_mips1.c b/tools/asm-processor/tests/late_rodata_jtbl_mips1.c
new file mode 100644
index 0000000..505f4c1
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_jtbl_mips1.c
@@ -0,0 +1,155 @@
+// COMPILE-FLAGS: -O2
+// COMPILE-ISET: -mips1
+// exact copy of late_rodata_jtbl.c except for the -mips1 addition
+GLOBAL_ASM(
+.late_rodata
+.double 1
+.double 2
+.double 3
+.double 4
+.double 5
+.double 6
+.double 7
+.double 8
+.text
+glabel doubles1
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+)
+
+float a(void) { return 1.1f; }
+
+GLOBAL_ASM(
+.late_rodata
+.float 1
+.double 2
+.double 3
+.double 4
+.double 5
+.double 6
+.double 7
+.double 8
+.double 9
+.float 10
+.text
+glabel doubles2
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+)
+
+GLOBAL_ASM(
+glabel a2
+move $a0, $a0
+nop
+nop
+nop
+jr $ra
+move $a0, $a0
+)
+
+GLOBAL_ASM(
+.late_rodata
+
+glabel jtbl
+.word case0, case1, case2, case3, case4, case5, case6, case7, case8, case9, case10
+.word case11, case12, case13, case14, case15, case16, case17, case18, case19, case20
+.word case21, case22, case23, case24, case25, case26
+
+.text
+glabel foo
+sltiu $at, $a0, 0xa
+beqz $at, .L756E659B
+ sll $t7, $a0, 2
+lui $at, %hi(jtbl)
+addu $at, $at, $t7
+lw $t7, %lo(jtbl)($at)
+jr $t7
+ nop
+case0: addiu $a0, $a0, 1
+case1: addiu $a0, $a0, 1
+case2: addiu $a0, $a0, 1
+case3: addiu $a0, $a0, 1
+case4: addiu $a0, $a0, 1
+case5: addiu $a0, $a0, 1
+case6: addiu $a0, $a0, 1
+case7: addiu $a0, $a0, 1
+case8: addiu $a0, $a0, 1
+case9: addiu $a0, $a0, 1
+case10: addiu $a0, $a0, 1
+case11: addiu $a0, $a0, 1
+case12: addiu $a0, $a0, 1
+case13: addiu $a0, $a0, 1
+case14: addiu $a0, $a0, 1
+case15: addiu $a0, $a0, 1
+case16: addiu $a0, $a0, 1
+case17: addiu $a0, $a0, 1
+case18: addiu $a0, $a0, 1
+case19: addiu $a0, $a0, 1
+case20: addiu $a0, $a0, 1
+case21: addiu $a0, $a0, 1
+case22: addiu $a0, $a0, 1
+case23: addiu $a0, $a0, 1
+case24: addiu $a0, $a0, 1
+case25: addiu $a0, $a0, 1
+case26:
+jr $ra
+ addiu $v0, $a0, 1
+
+.L756E659B:
+addiu $v0, $zero, 2
+jr $ra
+ nop
+)
+
+GLOBAL_ASM(
+glabel b2
+move $a0, $a0
+nop
+nop
+jr $ra
+move $a0, $a0
+)
+
+float b(void) { return 1.2f; }
diff --git a/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump b/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump
new file mode 100644
index 0000000..d37c8bb
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_jtbl_mips1.objdump
@@ -0,0 +1,110 @@
+
+tests/late_rodata_jtbl_mips1.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000001a0 .text
+00000000 l d .rodata 00000100 .rodata
+00000000 l d .text 00000000
+0000005c g F .text 00000010 a
+00000190 g F .text 00000010 b
+00000000 g F .text 0000005c doubles1
+0000006c g F .text 0000005c doubles2
+000000c8 g F .text 00000018 a2
+000000e0 g F .text 0000009c foo
+0000008c g .rodata 00000000 jtbl
+0000017c g F .text 00000014 b2
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+0000005c R_MIPS_HI16 .rodata
+00000060 R_MIPS_LO16 .rodata
+00000190 R_MIPS_HI16 .rodata
+00000194 R_MIPS_LO16 .rodata
+000000ec R_MIPS_HI16 jtbl
+000000f4 R_MIPS_LO16 jtbl
+
+
+RELOCATION RECORDS FOR [.rodata]:
+OFFSET TYPE VALUE
+0000008c R_MIPS_32
+00000090 R_MIPS_32
+00000094 R_MIPS_32
+00000098 R_MIPS_32
+0000009c R_MIPS_32
+000000a0 R_MIPS_32
+000000a4 R_MIPS_32
+000000a8 R_MIPS_32
+000000ac R_MIPS_32
+000000b0 R_MIPS_32
+000000b4 R_MIPS_32
+000000b8 R_MIPS_32
+000000bc R_MIPS_32
+000000c0 R_MIPS_32
+000000c4 R_MIPS_32
+000000c8 R_MIPS_32
+000000cc R_MIPS_32
+000000d0 R_MIPS_32
+000000d4 R_MIPS_32
+000000d8 R_MIPS_32
+000000dc R_MIPS_32
+000000e0 R_MIPS_32
+000000e4 R_MIPS_32
+000000e8 R_MIPS_32
+000000ec R_MIPS_32
+000000f0 R_MIPS_32
+000000f4 R_MIPS_32
+
+
+Contents of section .text:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00000000 00000000 00000000 ................
+ 0020 00000000 00000000 00000000 00000000 ................
+ 0030 00000000 00000000 00000000 00000000 ................
+ 0040 00000000 00000000 00000000 00000000 ................
+ 0050 00000000 00000000 00000000 3c010000 ............<...
+ 0060 c4200040 03e00008 00000000 00000000 . .@............
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 00000000 00000000 00000000 00000000 ................
+ 00a0 00000000 00000000 00000000 00000000 ................
+ 00b0 00000000 00000000 00000000 00000000 ................
+ 00c0 00000000 00000000 00802025 00000000 .......... %....
+ 00d0 00000000 00000000 03e00008 00802025 .............. %
+ 00e0 2c81000a 10200022 00047880 3c010000 ,.... ."..x.<...
+ 00f0 002f0821 8c2f0000 01e00008 00000000 ./.!./..........
+ 0100 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0110 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0120 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0130 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0140 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0150 24840001 24840001 24840001 24840001 $...$...$...$...
+ 0160 24840001 24840001 03e00008 24820001 $...$.......$...
+ 0170 24020002 03e00008 00000000 00802025 $............. %
+ 0180 00000000 00000000 03e00008 00802025 .............. %
+ 0190 3c010000 c42000f8 03e00008 00000000 <.... ..........
+Contents of section .rodata:
+ 0000 3ff00000 00000000 40000000 00000000 ?.......@.......
+ 0010 40080000 00000000 40100000 00000000 @.......@.......
+ 0020 40140000 00000000 40180000 00000000 @.......@.......
+ 0030 401c0000 00000000 40200000 00000000 @.......@ ......
+ 0040 3f8ccccd 3f800000 40000000 00000000 ?...?...@.......
+ 0050 40080000 00000000 40100000 00000000 @.......@.......
+ 0060 40140000 00000000 40180000 00000000 @.......@.......
+ 0070 401c0000 00000000 40200000 00000000 @.......@ ......
+ 0080 40220000 00000000 41200000 00000100 @"......A ......
+ 0090 00000104 00000108 0000010c 00000110 ................
+ 00a0 00000114 00000118 0000011c 00000120 ...............
+ 00b0 00000124 00000128 0000012c 00000130 ...$...(...,...0
+ 00c0 00000134 00000138 0000013c 00000140 ...4...8...<...@
+ 00d0 00000144 00000148 0000014c 00000150 ...D...H...L...P
+ 00e0 00000154 00000158 0000015c 00000160 ...T...X...\...`
+ 00f0 00000164 00000168 3f99999a 00000000 ...d...h?.......
+Contents of section .options:
+ 0000 01200000 00000000 80004002 00000000 . ........@.....
+ 0010 000000f1 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 8000c016 00000000 000000f1 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/late_rodata_misaligned_doubles.c b/tools/asm-processor/tests/late_rodata_misaligned_doubles.c
new file mode 100644
index 0000000..a453dbd
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_misaligned_doubles.c
@@ -0,0 +1,77 @@
+GLOBAL_ASM(
+.late_rodata
+ .float 4.01
+ .word 0
+ .double 4.02
+.text
+glabel a
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+double foo(void) { return 4.03; }
+
+GLOBAL_ASM(
+.late_rodata
+ .float 4.04
+ .double 4.05
+.text
+glabel b
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
+double bar(void) { return 4.06; }
+float baz(void) { return 4.07f; }
+
+GLOBAL_ASM(
+.late_rodata
+ .double 4.08
+.text
+glabel c
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+)
+
diff --git a/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump b/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump
new file mode 100644
index 0000000..cdba84d
--- /dev/null
+++ b/tools/asm-processor/tests/late_rodata_misaligned_doubles.objdump
@@ -0,0 +1,56 @@
+
+tests/late_rodata_misaligned_doubles.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000120 .text
+00000000 l d .rodata 00000040 .rodata
+00000040 g F .text 0000001c foo
+0000009c g F .text 0000001c bar
+000000b8 g F .text 0000001c baz
+00000000 g F .text 00000040 a
+0000005c g F .text 00000040 b
+000000d4 g F .text 00000040 c
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000040 R_MIPS_HI16 .rodata
+00000048 R_MIPS_LO16 .rodata
+0000009c R_MIPS_HI16 .rodata
+000000a4 R_MIPS_LO16 .rodata
+000000b8 R_MIPS_HI16 .rodata
+000000c0 R_MIPS_LO16 .rodata
+
+
+Contents of section .text:
+ 0000 00000000 00000000 00000000 00000000 ................
+ 0010 00000000 00000000 00000000 00000000 ................
+ 0020 00000000 00000000 00000000 00000000 ................
+ 0030 00000000 00000000 00000000 00000000 ................
+ 0040 3c010000 03e00008 d4200010 03e00008 <........ ......
+ 0050 00000000 03e00008 00000000 00000000 ................
+ 0060 00000000 00000000 00000000 00000000 ................
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 00000000 00000000 00000000 3c010000 ............<...
+ 00a0 03e00008 d4200028 03e00008 00000000 ..... .(........
+ 00b0 03e00008 00000000 3c010000 03e00008 ........<.......
+ 00c0 c4200030 03e00008 00000000 03e00008 . .0............
+ 00d0 00000000 00000000 00000000 00000000 ................
+ 00e0 00000000 00000000 00000000 00000000 ................
+ 00f0 00000000 00000000 00000000 00000000 ................
+ 0100 00000000 00000000 00000000 00000000 ................
+ 0110 00000000 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 408051ec 00000000 4010147a e147ae14 @.Q.....@..z.G..
+ 0010 40101eb8 51eb851f 00000000 408147ae @...Q.......@.G.
+ 0020 40103333 33333333 40103d70 a3d70a3d @.333333@.=p...=
+ 0030 40823d71 00000000 401051eb 851eb852 @.=q....@.Q....R
+Contents of section .options:
+ 0000 01200000 00000000 80000002 00000000 . ..............
+ 0010 000000f3 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000002 00000000 000000f3 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/line-continuation-separate-file.s b/tools/asm-processor/tests/line-continuation-separate-file.s
new file mode 100644
index 0000000..e130180
--- /dev/null
+++ b/tools/asm-processor/tests/line-continuation-separate-file.s
@@ -0,0 +1,4 @@
+.rdata
+ label: .asciiz "1\n\
+2", \
+ "34", "56"
diff --git a/tools/asm-processor/tests/line-continuation.asmproc.d b/tools/asm-processor/tests/line-continuation.asmproc.d
new file mode 100644
index 0000000..687dd1a
--- /dev/null
+++ b/tools/asm-processor/tests/line-continuation.asmproc.d
@@ -0,0 +1,3 @@
+tests/line-continuation.o: tests/line-continuation-separate-file.s
+
+tests/line-continuation-separate-file.s:
diff --git a/tools/asm-processor/tests/line-continuation.c b/tools/asm-processor/tests/line-continuation.c
new file mode 100644
index 0000000..d5ab093
--- /dev/null
+++ b/tools/asm-processor/tests/line-continuation.c
@@ -0,0 +1,22 @@
+void foo(void) { "abcdef"; }
+
+GLOBAL_ASM(
+.rdata
+ .ascii "AB" \
+ "CD", "EF"
+ .ascii "GH\n\n\n\0\11\222\3333\44444\x1234567\n\nIJK"
+)
+
+void bar(void) { "hello"; }
+
+GLOBAL_ASM(
+.rdata
+ .asciiz "1\
+2"
+ .asciiz "34", "56"
+ .asciiz "78\n\n\n\0\11\222\3333\44444\x1234567\n\n9A"
+)
+
+void baz(void) { "ghijkl"; }
+
+GLOBAL_ASM("tests/line-continuation-separate-file.s")
diff --git a/tools/asm-processor/tests/line-continuation.objdump b/tools/asm-processor/tests/line-continuation.objdump
new file mode 100644
index 0000000..038766f
--- /dev/null
+++ b/tools/asm-processor/tests/line-continuation.objdump
@@ -0,0 +1,30 @@
+
+tests/line-continuation.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000030 .text
+00000000 l d .rodata 00000060 .rodata
+00000000 g F .text 00000010 foo
+00000010 g F .text 00000010 bar
+00000020 g F .text 00000010 baz
+
+
+Contents of section .text:
+ 0000 03e00008 00000000 03e00008 00000000 ................
+ 0010 03e00008 00000000 03e00008 00000000 ................
+ 0020 03e00008 00000000 03e00008 00000000 ................
+Contents of section .rodata:
+ 0000 61626364 65660000 41424344 45464748 abcdef..ABCDEFGH
+ 0010 0a0a0a00 0992db33 24343467 0a0a494a .......3$44g..IJ
+ 0020 4b000000 68656c6c 6f000000 31320033 K...hello...12.3
+ 0030 34003536 0037380a 0a0a0009 92db3324 4.56.78.......3$
+ 0040 3434670a 0a394100 6768696a 6b6c0000 44g..9A.ghijkl..
+ 0050 310a3200 33340035 36000000 00000000 1.2.34.56.......
+Contents of section .options:
+ 0000 01200000 00000000 80000000 00000000 . ..............
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000000 00000000 00000000 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/o0.c b/tools/asm-processor/tests/o0.c
new file mode 100644
index 0000000..6f8e5e4
--- /dev/null
+++ b/tools/asm-processor/tests/o0.c
@@ -0,0 +1,28 @@
+// COMPILE-FLAGS: -O0
+
+int a(void) { return 1; }
+GLOBAL_ASM(
+glabel foo
+addiu $a0, $a0, 1
+addiu $a0, $a0, 2
+addiu $a0, $a0, 3
+jr $ra
+addiu $a0, $a0, 4
+)
+float b(void) { return 1.2f; }
+GLOBAL_ASM(
+.late_rodata
+glabel float1
+.float 12.34
+
+.text
+glabel bar
+addiu $a0, $a0, 5
+addiu $a0, $a0, 6
+addiu $a0, $a0, 7
+addiu $a0, $a0, 8
+lui $v0, %hi(float1 + 1)
+jr $ra
+addiu $v0, $v0, %lo(float1 + 1)
+)
+float c(void) { return 1.3f; }
diff --git a/tools/asm-processor/tests/o0.objdump b/tools/asm-processor/tests/o0.objdump
new file mode 100644
index 0000000..f94ec7a
--- /dev/null
+++ b/tools/asm-processor/tests/o0.objdump
@@ -0,0 +1,44 @@
+
+tests/o0.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000090 .text
+00000000 l d .rodata 00000010 .rodata
+00000000 g F .text 0000001c a
+00000030 g F .text 00000020 b
+0000006c g F .text 00000020 c
+0000001c g F .text 00000014 foo
+00000050 g F .text 0000001c bar
+00000004 g .rodata 00000000 float1
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000030 R_MIPS_HI16 .rodata
+00000034 R_MIPS_LO16 .rodata
+0000006c R_MIPS_HI16 .rodata
+00000070 R_MIPS_LO16 .rodata
+00000060 R_MIPS_HI16 float1
+00000068 R_MIPS_LO16 float1
+
+
+Contents of section .text:
+ 0000 24020001 03e00008 00000000 03e00008 $...............
+ 0010 00000000 03e00008 00000000 24840001 ............$...
+ 0020 24840002 24840003 03e00008 24840004 $...$.......$...
+ 0030 3c010000 c4200000 03e00008 00000000 <.... ..........
+ 0040 03e00008 00000000 03e00008 00000000 ................
+ 0050 24840005 24840006 24840007 24840008 $...$...$...$...
+ 0060 3c020000 03e00008 24420001 3c010000 <.......$B..<...
+ 0070 c4200008 03e00008 00000000 03e00008 . ..............
+ 0080 00000000 03e00008 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff....
+Contents of section .options:
+ 0000 01200000 00000000 80000006 00000000 . ..............
+ 0010 00000011 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000016 00000000 00000011 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/o2.c b/tools/asm-processor/tests/o2.c
new file mode 100644
index 0000000..144a604
--- /dev/null
+++ b/tools/asm-processor/tests/o2.c
@@ -0,0 +1,26 @@
+// COMPILE-FLAGS: -O2
+
+int a(void) { return 1; }
+GLOBAL_ASM(
+glabel foo
+addiu $a0, $a0, 1
+addiu $a0, $a0, 2
+addiu $a0, $a0, 3
+jr $ra
+addiu $a0, $a0, 4
+)
+float b(void) { return 1.2f; }
+GLOBAL_ASM(
+.late_rodata
+glabel float1
+.float 12.34
+
+.text
+glabel bar
+addiu $a0, $a0, 5
+addiu $a0, $a0, 6
+lui $v0, %hi(float1 + 1)
+jr $ra
+addiu $v0, $v0, %lo(float1 + 1)
+)
+float c(void) { return 1.3f; }
diff --git a/tools/asm-processor/tests/o2.objdump b/tools/asm-processor/tests/o2.objdump
new file mode 100644
index 0000000..61e3fb0
--- /dev/null
+++ b/tools/asm-processor/tests/o2.objdump
@@ -0,0 +1,40 @@
+
+tests/o2.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000050 .text
+00000000 l d .rodata 00000010 .rodata
+00000000 g F .text 00000008 a
+0000001c g F .text 0000000c b
+0000003c g F .text 0000000c c
+00000008 g F .text 00000014 foo
+00000028 g F .text 00000014 bar
+00000004 g .rodata 00000000 float1
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+0000001c R_MIPS_HI16 .rodata
+00000024 R_MIPS_LO16 .rodata
+0000003c R_MIPS_HI16 .rodata
+00000044 R_MIPS_LO16 .rodata
+00000030 R_MIPS_HI16 float1
+00000038 R_MIPS_LO16 float1
+
+
+Contents of section .text:
+ 0000 03e00008 24020001 24840001 24840002 ....$...$...$...
+ 0010 24840003 03e00008 24840004 3c010000 $.......$...<...
+ 0020 03e00008 c4200000 24840005 24840006 ..... ..$...$...
+ 0030 3c020000 03e00008 24420001 3c010000 <.......$B..<...
+ 0040 03e00008 c4200008 00000000 00000000 ..... ..........
+Contents of section .rodata:
+ 0000 3f99999a 414570a4 3fa66666 00000000 ?...AEp.?.ff....
+Contents of section .options:
+ 0000 01200000 00000000 80000006 00000000 . ..............
+ 0010 00000011 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80000016 00000000 00000011 00000000 ................
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/pascal.objdump b/tools/asm-processor/tests/pascal.objdump
new file mode 100644
index 0000000..cb3740f
--- /dev/null
+++ b/tools/asm-processor/tests/pascal.objdump
@@ -0,0 +1,137 @@
+
+tests/pascal.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000000e0 .text
+00000000 l d .rodata 00000030 .rodata
+00000000 l d .data 00000010 .data
+00000000 l d .bss 00000010 .bss
+00000000 l O .bss 00000000 $dat
+00000000 g F .text 0000000c foo
+000000d0 g F .text 0000000c bar
+0000000c g F .text 00000004 test
+00000048 g F .text 00000004 test2
+0000008c g F .text 00000044 test3
+00000000 *UND* 00000000 get
+00000000 *UND* 00000000 put
+00000000 *UND* 00000000 pascal_close
+00000000 *UND* 00000000 fflush
+00000000 *UND* 00000000 filesize
+00000000 *UND* 00000000 curpos
+00000000 *UND* 00000000 seek
+00000000 *UND* 00000000 eof
+00000000 *UND* 00000000 eoln
+00000000 *UND* 00000000 page
+00000000 *UND* 00000000 reset
+00000000 *UND* 00000000 rewrite
+00000000 *UND* 00000000 cos
+00000000 *UND* 00000000 exp
+00000000 *UND* 00000000 sqrt
+00000000 *UND* 00000000 log
+00000000 *UND* 00000000 atan
+00000000 *UND* 00000000 sin
+00000000 *UND* 00000000 __random_float
+00000000 *UND* 00000000 clock
+00000000 *UND* 00000000 exit
+00000000 *UND* 00000000 __date
+00000000 *UND* 00000000 __time
+00000000 *UND* 00000000 get_arg
+00000000 *UND* 00000000 new
+00000000 *UND* 00000000 dispose
+00000000 *UND* 00000000 initfile
+00000000 *UND* 00000000 peek_char
+00000000 *UND* 00000000 next_char
+00000000 *UND* 00000000 readln
+00000000 *UND* 00000000 read_int64
+00000000 *UND* 00000000 read_card64
+00000000 *UND* 00000000 read_integer
+00000000 *UND* 00000000 read_cardinal
+00000000 *UND* 00000000 read_integer_range
+00000000 *UND* 00000000 read_real
+00000000 *UND* 00000000 read_double
+00000000 *UND* 00000000 read_extended
+00000000 *UND* 00000000 read_string
+00000000 *UND* 00000000 read_enum
+00000000 *UND* 00000000 read_char
+00000000 *UND* 00000000 read_char_range
+00000000 *UND* 00000000 read_boolean
+00000000 *UND* 00000000 read_set
+00000000 *UND* 00000000 writeln
+00000000 *UND* 00000000 write_int64
+00000000 *UND* 00000000 write_card64
+00000000 *UND* 00000000 write_integer
+00000000 *UND* 00000000 write_cardinal
+00000000 *UND* 00000000 write_boolean
+00000000 *UND* 00000000 write_char
+00000000 *UND* 00000000 write_real
+00000000 *UND* 00000000 write_double
+00000000 *UND* 00000000 write_extended
+00000000 *UND* 00000000 write_string
+00000000 *UND* 00000000 write_enum
+00000000 *UND* 00000000 write_set
+00000000 *UND* 00000000 caseerror
+00000000 *UND* 00000000 __pc_nloc_goto
+00000000 *UND* 00000000 memcpy
+00000000 *UND* 00000000 __in_range
+00000000 *UND* 00000000 __ll_mul
+00000000 *UND* 00000000 __ll_div
+00000000 *UND* 00000000 __ull_div
+00000000 *UND* 00000000 __ll_mod
+00000000 *UND* 00000000 __ll_rem
+00000000 *UND* 00000000 __ull_rem
+00000000 *UND* 00000000 __ll_lshift
+00000000 *UND* 00000000 __ll_rshift
+00000000 *UND* 00000000 __ll_to_f
+00000000 *UND* 00000000 __ull_to_f
+00000000 *UND* 00000000 __ll_to_d
+00000000 *UND* 00000000 __ull_to_d
+00000000 *UND* 00000000 __f_ll_ll
+00000000 *UND* 00000000 __f_to_ull
+00000000 *UND* 00000000 __d_to_ll
+00000000 *UND* 00000000 __d_to_ull
+00000000 *UND* 00000000 round64
+00000000 *UND* 00000000 trunc64
+00000000 *UND* 00000000 max64
+00000000 *UND* 00000000 min64
+00000000 *UND* 00000000 abs64
+00000000 *UND* 00000000 odd64
+00000000 *UND* 00000000 trapNaN
+00000000 *UND* 00000008 input
+00000000 *UND* 00000008 output
+00000000 *UND* 00000008 err
+00000000 *UND* 00000008 __Argc
+
+
+RELOCATION RECORDS FOR [.text]: (none)
+
+RELOCATION RECORDS FOR [.rodata]: (none)
+
+Contents of section .text:
+ 0000 00041080 03e00008 00441023 27bdffe8 .........D.#'...
+ 0010 18a00009 afa00004 8fae0004 008e7821 ..............x!
+ 0020 a1e00000 8fb80004 27190001 0325082a ........'....%.*
+ 0030 1420fff9 afb90004 10000001 00000000 . ..............
+ 0040 03e00008 27bd0018 00000000 00000000 ....'...........
+ 0050 00000000 00000000 00000000 00000000 ................
+ 0060 00000000 00000000 00000000 00000000 ................
+ 0070 00000000 00000000 00000000 00000000 ................
+ 0080 00000000 00000000 00000000 00000000 ................
+ 0090 00000000 00000000 00000000 00000000 ................
+ 00a0 00000000 00000000 00000000 00000000 ................
+ 00b0 00000000 00000000 00000000 00000000 ................
+ 00c0 00000000 00000000 00000000 00000000 ................
+ 00d0 00041080 03e00008 00441023 00000000 .........D.#....
+Contents of section .rodata:
+ 0000 00123123 00456456 00789789 00000001 ..1#.EdV.x......
+ 0010 3ff19999 9999999a 00000002 00000003 ?...............
+ 0020 4000cccc cccccccd 00000000 00000000 @...............
+Contents of section .data:
+ 0000 00002323 00003434 00000000 00000000 ..##..44........
+Contents of section .options:
+ 0000 01200000 00000000 80004016 00000000 . ........@.....
+ 0010 000000f0 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a300c036 00000000 000000f0 00000000 ...6............
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/pascal.p b/tools/asm-processor/tests/pascal.p
new file mode 100644
index 0000000..0886126
--- /dev/null
+++ b/tools/asm-processor/tests/pascal.p
@@ -0,0 +1,95 @@
+{ COMPILE-FLAGS: -O2 }
+
+function foo(x: integer): integer;
+begin
+ foo := x * 3
+end;
+
+GLOBAL_ASM(
+.section .data
+.word 0x2323
+
+.late_rodata
+.word 0x123123
+.word 0x456456
+.word 0x789789
+.text
+glabel test
+/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24
+/* 000094 00400094 18A00009 */ blez $a1, .L004000BC
+/* 000098 00400098 AFA00004 */ sw $zero, 4($sp)
+.L0040009C:
+/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp)
+/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6
+/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7)
+/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp)
+/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1
+/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1
+/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C
+/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp)
+.L004000BC:
+/* 0000BC 004000BC 10000001 */ b .L004000C4
+/* 0000C0 004000C0 00000000 */ nop
+.L004000C4:
+/* 0000C4 004000C4 03E00008 */ jr $ra
+/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24
+)
+
+GLOBAL_ASM(
+.section .data
+.word 0x3434
+
+.late_rodata
+.word 0x1
+.double 1.1
+.word 0x2, 0x3
+.text
+glabel test2
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+)
+
+GLOBAL_ASM(
+.late_rodata
+.double 2.1
+.text
+glabel test3
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+nop
+)
+
+function bar(x: integer): integer;
+begin
+ return x * 3
+end;
+
diff --git a/tools/asm-processor/tests/static-global.c b/tools/asm-processor/tests/static-global.c
new file mode 100644
index 0000000..a7f6169
--- /dev/null
+++ b/tools/asm-processor/tests/static-global.c
@@ -0,0 +1,33 @@
+// COMPILE-FLAGS: -O2
+// ASMP-FLAGS: --convert-statics=global
+static int xtext(int a, int b, int c);
+const int rodata1[] = {1};
+static const int rodata2[] = {2};
+int data1[] = {3};
+static int data2[] = {4};
+int bss1;
+static int bss2;
+
+GLOBAL_ASM(
+glabel bar
+lui $a0, %hi(rodata2)
+lw $a0, %lo(rodata2)($a0)
+lui $a1, %hi(data2)
+lw $a1, %lo(data2)($a0)
+lui $a2, %hi(bss2)
+lw $a2, %lo(bss2)($a0)
+jal xtext
+nop
+jr $ra
+nop
+nop
+nop
+)
+
+static int xtext(int a, int b, int c) {
+ return 1;
+}
+
+void baz(void) {
+ xtext(bss2, rodata2[0], data2[0]);
+}
diff --git a/tools/asm-processor/tests/static-global.objdump b/tools/asm-processor/tests/static-global.objdump
new file mode 100644
index 0000000..a519e4f
--- /dev/null
+++ b/tools/asm-processor/tests/static-global.objdump
@@ -0,0 +1,58 @@
+
+tests/static-global.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000080 .text
+00000000 l d .rodata 00000010 .rodata
+00000000 l d .data 00000010 .data
+00000000 l d .bss 00000010 .bss
+00000000 g O .rodata 00000004 rodata1
+00000000 g O .data 00000004 data1
+00000000 g O .bss 00000004 bss1
+00000044 g F .text 00000034 baz
+00000000 g F .text 00000030 bar
+00000004 g O .rodata 00000000 rodata2
+00000004 g O .data 00000000 data2
+00000004 g O .bss 00000000 bss2
+00000030 g F .text 00000000 xtext
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+0000004c R_MIPS_HI16 .bss
+00000064 R_MIPS_LO16 .bss
+00000050 R_MIPS_HI16 .rodata
+0000005c R_MIPS_LO16 .rodata
+00000054 R_MIPS_HI16 .data
+00000058 R_MIPS_LO16 .data
+00000060 R_MIPS_26 .text
+00000000 R_MIPS_HI16 rodata2
+00000004 R_MIPS_LO16 rodata2
+00000008 R_MIPS_HI16 data2
+0000000c R_MIPS_LO16 data2
+00000010 R_MIPS_HI16 bss2
+00000014 R_MIPS_LO16 bss2
+00000018 R_MIPS_26 xtext
+
+
+Contents of section .text:
+ 0000 3c040000 8c840000 3c050000 8c850000 <.......<.......
+ 0010 3c060000 8c860000 0c000000 00000000 <...............
+ 0020 03e00008 00000000 00000000 00000000 ................
+ 0030 afa40000 afa50004 afa60008 03e00008 ................
+ 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<...
+ 0050 3c050000 3c060000 8cc60004 8ca50004 <...<...........
+ 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'...
+ 0070 03e00008 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 00000001 00000002 00000000 00000000 ................
+Contents of section .data:
+ 0000 00000003 00000004 00000000 00000000 ................
+Contents of section .options:
+ 0000 01200000 00000000 a0000074 00000000 . .........t....
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a0000074 00000000 00000000 00000000 ...t............
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/static.c b/tools/asm-processor/tests/static.c
new file mode 100644
index 0000000..c265021
--- /dev/null
+++ b/tools/asm-processor/tests/static.c
@@ -0,0 +1,32 @@
+// COMPILE-FLAGS: -O2
+static int xtext(int a, int b, int c);
+const int rodata1[] = {1};
+static const int rodata2[] = {2};
+int data1[] = {3};
+static int data2[] = {4};
+int bss1;
+static int bss2;
+
+GLOBAL_ASM(
+glabel bar
+lui $a0, %hi(rodata2)
+lw $a0, %lo(rodata2)($a0)
+lui $a1, %hi(data2)
+lw $a1, %lo(data2)($a0)
+lui $a2, %hi(bss2)
+lw $a2, %lo(bss2)($a0)
+jal xtext
+nop
+jr $ra
+nop
+nop
+nop
+)
+
+static int xtext(int a, int b, int c) {
+ return 1;
+}
+
+void baz(void) {
+ xtext(bss2, rodata2[0], data2[0]);
+}
diff --git a/tools/asm-processor/tests/static.objdump b/tools/asm-processor/tests/static.objdump
new file mode 100644
index 0000000..dd62c94
--- /dev/null
+++ b/tools/asm-processor/tests/static.objdump
@@ -0,0 +1,58 @@
+
+tests/static.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 00000080 .text
+00000000 l d .rodata 00000010 .rodata
+00000000 l d .data 00000010 .data
+00000000 l d .bss 00000010 .bss
+00000004 l O .rodata 00000000 rodata2
+00000004 l O .data 00000000 data2
+00000004 l O .bss 00000000 bss2
+00000030 l F .text 00000000 xtext
+00000000 g O .rodata 00000004 rodata1
+00000000 g O .data 00000004 data1
+00000000 g O .bss 00000004 bss1
+00000044 g F .text 00000034 baz
+00000000 g F .text 00000030 bar
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+0000004c R_MIPS_HI16 .bss
+00000064 R_MIPS_LO16 .bss
+00000050 R_MIPS_HI16 .rodata
+0000005c R_MIPS_LO16 .rodata
+00000054 R_MIPS_HI16 .data
+00000058 R_MIPS_LO16 .data
+00000060 R_MIPS_26 .text
+00000000 R_MIPS_HI16 rodata2
+00000004 R_MIPS_LO16 rodata2
+00000008 R_MIPS_HI16 data2
+0000000c R_MIPS_LO16 data2
+00000010 R_MIPS_HI16 bss2
+00000014 R_MIPS_LO16 bss2
+00000018 R_MIPS_26 xtext
+
+
+Contents of section .text:
+ 0000 3c040000 8c840000 3c050000 8c850000 <.......<.......
+ 0010 3c060000 8c860000 0c000000 00000000 <...............
+ 0020 03e00008 00000000 00000000 00000000 ................
+ 0030 afa40000 afa50004 afa60008 03e00008 ................
+ 0040 24020001 27bdffe8 afbf0014 3c040000 $...'.......<...
+ 0050 3c050000 3c060000 8cc60004 8ca50004 <...<...........
+ 0060 0c00000c 8c840004 8fbf0014 27bd0018 ............'...
+ 0070 03e00008 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 00000001 00000002 00000000 00000000 ................
+Contents of section .data:
+ 0000 00000003 00000004 00000000 00000000 ................
+Contents of section .options:
+ 0000 01200000 00000000 a0000074 00000000 . .........t....
+ 0010 00000000 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a0000074 00000000 00000000 00000000 ...t............
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/test1.c b/tools/asm-processor/tests/test1.c
new file mode 100644
index 0000000..475555a
--- /dev/null
+++ b/tools/asm-processor/tests/test1.c
@@ -0,0 +1,71 @@
+
+GLOBAL_ASM(
+.rdata
+.word 0x1212
+)
+
+GLOBAL_ASM(
+.late_rodata
+.word 0x123123
+.text
+glabel test
+/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24
+/* 000094 00400094 18A00009 */ blez $a1, .L004000BC
+/* 000098 00400098 AFA00004 */ sw $zero, 4($sp)
+.L0040009C:
+/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp)
+/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6
+/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7)
+/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp)
+/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1
+/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1
+/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C
+/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp)
+.L004000BC:
+/* 0000BC 004000BC 10000001 */ b .L004000C4
+/* 0000C0 004000C0 00000000 */ nop
+.L004000C4:
+/* 0000C4 004000C4 03E00008 */ jr $ra
+/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24
+)
+
+char bss1[3];
+GLOBAL_ASM(
+.bss
+bss2:
+.space 3
+)
+char bss3[3];
+char bss4[3];
+const int rodata1[2] = {1};
+extern int some_rodata;
+
+unsigned g(float, int);
+unsigned f(void) {
+ return g(1.1f, some_rodata);
+}
+
+GLOBAL_ASM(
+.rdata
+glabel some_rodata
+.word 0x1313
+.text
+.late_rodata
+.word 0x321321
+.text
+glabel g
+/* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18
+/* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp)
+/* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4
+/* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100)
+/* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at)
+/* 0000D4 004000D4 0C10002C */ jal func_004000B0
+/* 0000D8 004000D8 00000000 */ nop
+/* 0000DC 004000DC 10000001 */ b .L004000E4
+/* 0000E0 004000E0 00000000 */ nop
+.L004000E4:
+/* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp)
+/* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18
+/* 0000EC 004000EC 03E00008 */ jr $ra
+/* 0000F0 004000F0 00000000 */ nop
+)
diff --git a/tools/asm-processor/tests/test1.objdump b/tools/asm-processor/tests/test1.objdump
new file mode 100644
index 0000000..b97ae46
--- /dev/null
+++ b/tools/asm-processor/tests/test1.objdump
@@ -0,0 +1,54 @@
+
+tests/test1.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000000b0 .text
+00000000 l d .rodata 00000020 .rodata
+00000000 l d .bss 00000010 .bss
+00000000 g O .bss 00000003 bss1
+00000008 g O .bss 00000003 bss3
+0000000c g O .bss 00000003 bss4
+00000004 g O .rodata 00000008 rodata1
+0000003c g F .text 0000003c f
+00000000 g F .text 0000003c test
+0000000c g .rodata 00000000 some_rodata
+00000078 g F .text 00000004 g
+00000000 *UND* 00000000 D_410100
+00000000 *UND* 00000000 func_004000B0
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000044 R_MIPS_HI16 .rodata
+00000054 R_MIPS_LO16 .rodata
+00000048 R_MIPS_HI16 some_rodata
+0000004c R_MIPS_LO16 some_rodata
+00000050 R_MIPS_26 g
+00000084 R_MIPS_HI16 D_410100
+00000088 R_MIPS_LO16 D_410100
+0000008c R_MIPS_26 func_004000B0
+
+
+Contents of section .text:
+ 0000 27bdffe8 18a00009 afa00004 8fae0004 '...............
+ 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'...
+ 0020 0325082a 1420fff9 afb90004 10000001 .%.*. ..........
+ 0030 00000000 03e00008 27bd0018 27bdffe8 ........'...'...
+ 0040 afbf0014 3c010000 3c050000 8ca50000 ....<...<.......
+ 0050 0c000000 c42c0014 10000003 00000000 .....,..........
+ 0060 10000001 00000000 8fbf0014 27bd0018 ............'...
+ 0070 03e00008 00000000 27bdffe8 afbf0014 ........'.......
+ 0080 240e0004 3c010000 ac2e0000 0c000000 $...<...........
+ 0090 00000000 10000001 00000000 8fbf0014 ................
+ 00a0 27bd0018 03e00008 00000000 00000000 '...............
+Contents of section .rodata:
+ 0000 00001212 00000001 00000000 00001313 ................
+ 0010 00123123 3f8ccccd 00321321 00000000 ..1#?....2.!....
+Contents of section .options:
+ 0000 01200000 00000000 a0000022 00000000 . ........."....
+ 0010 00001010 00000000 00000000 00007ff0 ................
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a300c032 00000000 00001010 00000000 ...2............
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/test2.c b/tools/asm-processor/tests/test2.c
new file mode 100644
index 0000000..15969fe
--- /dev/null
+++ b/tools/asm-processor/tests/test2.c
@@ -0,0 +1,69 @@
+const char buf1[1] = {1};
+float func1(void) {
+ "func1";
+ return 0.1f;
+}
+const char buf2[1] = {2};
+void func2(void) {
+ *(volatile float*)0 = -3.5792360305786133f;
+ *(volatile float*)0 = -3.5792362689971924f;
+ // "func2";
+ // return 0.2f;
+}
+const char buf3[1] = {3};
+int func3(int x) {
+ switch(x) {
+ case 0:
+ return 1;
+ case 1:
+ return 2;
+ case 2:
+ return 3;
+ case 3:
+ return 4;
+ case 4:
+ return 5;
+ case 5:
+ return 4;
+ case 6:
+ return 4;
+ case 7:
+ return 4;
+ default:
+ return 3;
+ }
+}
+
+#if 1
+GLOBAL_ASM(
+.rdata
+.word 0x66756e63 # func
+.word 0x34000000 # 4\0\0\0
+.word jumptarget + 4
+
+.late_rodata
+glabel rv
+.word 0x3e4ccccd # 0.2f
+.word jumptarget + 8
+
+.text
+glabel func4
+lui $at, %hi(rv)
+glabel jumptarget
+jr $ra
+lwc1 $f0, %lo(rv)($at)
+jr $ra
+nop
+jr $ra
+nop
+jr $ra
+nop
+jr $ra
+nop
+)
+#else
+float func4(void) {
+ "func4";
+ return 0.2f;
+}
+#endif
diff --git a/tools/asm-processor/tests/test2.objdump b/tools/asm-processor/tests/test2.objdump
new file mode 100644
index 0000000..276ed9f
--- /dev/null
+++ b/tools/asm-processor/tests/test2.objdump
@@ -0,0 +1,76 @@
+
+tests/test2.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000000f0 .text
+00000000 l d .rodata 00000060 .rodata
+00000000 g O .rodata 00000001 buf1
+00000000 g F .text 0000001c func1
+0000000c g O .rodata 00000001 buf2
+0000001c g F .text 00000028 func2
+00000010 g O .rodata 00000001 buf3
+00000044 g F .text 0000007c func3
+000000c4 g F .text 00000000 jumptarget
+000000c0 g F .text 0000000c func4
+0000004c g .rodata 00000000 rv
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000000 R_MIPS_HI16 .rodata
+00000008 R_MIPS_LO16 .rodata
+0000001c R_MIPS_HI16 .rodata
+00000020 R_MIPS_LO16 .rodata
+00000028 R_MIPS_HI16 .rodata
+0000002c R_MIPS_LO16 .rodata
+00000054 R_MIPS_HI16 .rodata
+0000005c R_MIPS_LO16 .rodata
+000000c0 R_MIPS_HI16 rv
+000000c8 R_MIPS_LO16 rv
+
+
+RELOCATION RECORDS FOR [.rodata]:
+OFFSET TYPE VALUE
+0000002c R_MIPS_32 .text
+00000030 R_MIPS_32 .text
+00000034 R_MIPS_32 .text
+00000038 R_MIPS_32 .text
+0000003c R_MIPS_32 .text
+00000040 R_MIPS_32 .text
+00000044 R_MIPS_32 .text
+00000048 R_MIPS_32 .text
+0000001c R_MIPS_32 jumptarget
+00000050 R_MIPS_32 jumptarget
+
+
+Contents of section .text:
+ 0000 3c010000 03e00008 c4200020 03e00008 <........ . ....
+ 0010 00000000 03e00008 00000000 3c010000 ............<...
+ 0020 c4240024 e4040000 3c010000 c4260028 .$.$....<....&.(
+ 0030 e4060000 03e00008 00000000 03e00008 ................
+ 0040 00000000 2c810008 10200017 00000000 ....,.... ......
+ 0050 00047080 3c010000 002e0821 8c2e002c ..p.<......!...,
+ 0060 01c00008 00000000 03e00008 24020001 ............$...
+ 0070 03e00008 24020002 03e00008 24020003 ....$.......$...
+ 0080 03e00008 24020004 03e00008 24020005 ....$.......$...
+ 0090 03e00008 24020004 03e00008 24020004 ....$.......$...
+ 00a0 03e00008 24020004 03e00008 24020003 ....$.......$...
+ 00b0 03e00008 00000000 03e00008 00000000 ................
+ 00c0 3c010000 03e00008 c4200000 03e00008 <........ ......
+ 00d0 00000000 03e00008 00000000 03e00008 ................
+ 00e0 00000000 03e00008 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 01000000 66756e63 31000000 02000000 ....func1.......
+ 0010 03000000 66756e63 34000000 00000004 ....func4.......
+ 0020 3dcccccd c0651234 c0651235 00000068 =....e.4.e.5...h
+ 0030 00000070 00000078 00000080 00000088 ...p...x........
+ 0040 00000090 00000098 000000a0 3e4ccccd ............>L..
+ 0050 00000008 00000000 00000000 00000000 ................
+Contents of section .options:
+ 0000 01200000 00000000 80004016 00000000 . ........@.....
+ 0010 00000051 00000000 00000000 00007ff0 ...Q............
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 80004016 00000000 00000051 00000000 ..@........Q....
+ 0010 00000000 00007ff0 ........
diff --git a/tools/asm-processor/tests/test3.c b/tools/asm-processor/tests/test3.c
new file mode 100644
index 0000000..d74bb4c
--- /dev/null
+++ b/tools/asm-processor/tests/test3.c
@@ -0,0 +1,70 @@
+
+GLOBAL_ASM(
+.rdata
+.word 321321
+.text
+glabel test
+/* 000090 00400090 27BDFFF8 */ addiu $sp, $sp, -24
+/* 000094 00400094 18A00009 */ blez $a1, .L004000BC
+/* 000098 00400098 AFA00004 */ sw $zero, 4($sp)
+.L0040009C:
+/* 00009C 0040009C 8FAE0004 */ lw $t6, 4($sp)
+/* 0000A0 004000A0 008E7821 */ addu $t7, $a0, $t6
+/* 0000A4 004000A4 A1E00000 */ sb $zero, ($t7)
+/* 0000A8 004000A8 8FB80004 */ lw $t8, 4($sp)
+/* 0000AC 004000AC 27190001 */ addiu $t9, $t8, 1
+/* 0000B0 004000B0 0325082A */ slt $at, $t9, $a1
+/* 0000B4 004000B4 1420FFF9 */ bnez $at, .L0040009C
+/* 0000B8 004000B8 AFB90004 */ sw $t9, 4($sp)
+.L004000BC:
+/* 0000BC 004000BC 10000001 */ b .L004000C4
+/* 0000C0 004000C0 00000000 */ nop
+.L004000C4:
+/* 0000C4 004000C4 03E00008 */ jr $ra
+/* 0000C8 004000C8 27BD0008 */ addiu $sp, $sp, 24
+)
+
+// static -> no symbols
+// bss
+char globalBuf[4];
+const char constBuf[4];
+
+// data
+char globalBufInit[4] = {1};
+
+// rodata
+const char constBufInit[4] = {1};
+const char constBufInit2[1] = {2};
+const char constBufInit3[1] = {3};
+
+unsigned g(void);
+unsigned f(void) {
+ // aligns to 4 or 8 byte boundary (char -> 4, double -> 8)
+ double x = 5.1;
+ float y = 5.2f;
+ float z = 5.3f;
+ "Hello ";
+ "World";
+ return g();
+}
+
+GLOBAL_ASM(
+.rdata
+.word 123123
+.text
+glabel g
+/* 0000C0 004000C0 27BDFFE8 */ addiu $sp, $sp, -0x18
+/* 0000C4 004000C4 AFBF0014 */ sw $ra, 0x14($sp)
+/* 0000C8 004000C8 240E0004 */ addiu $t6, $zero, 4
+/* 0000CC 004000CC 3C010041 */ lui $at, %hi(D_410100)
+/* 0000D0 004000D0 AC2E0100 */ sw $t6, %lo(D_410100)($at)
+/* 0000D4 004000D4 0C10002C */ jal func_004000B0
+/* 0000D8 004000D8 00000000 */ nop
+/* 0000DC 004000DC 10000001 */ b .L004000E4
+/* 0000E0 004000E0 00000000 */ nop
+.L004000E4:
+/* 0000E4 004000E4 8FBF0014 */ lw $ra, 0x14($sp)
+/* 0000E8 004000E8 27BD0018 */ addiu $sp, $sp, 0x18
+/* 0000EC 004000EC 03E00008 */ jr $ra
+/* 0000F0 004000F0 00000000 */ nop
+)
diff --git a/tools/asm-processor/tests/test3.objdump b/tools/asm-processor/tests/test3.objdump
new file mode 100644
index 0000000..bfa7f6e
--- /dev/null
+++ b/tools/asm-processor/tests/test3.objdump
@@ -0,0 +1,64 @@
+
+tests/test3.o: file format elf32-tradbigmips
+
+SYMBOL TABLE:
+00000000 l d .text 000000d0 .text
+00000000 l d .rodata 00000040 .rodata
+00000000 l d .data 00000010 .data
+00000000 l d .bss 00000010 .bss
+00000000 g O .bss 00000004 globalBuf
+00000004 g O .bss 00000004 constBuf
+00000000 g O .data 00000004 globalBufInit
+00000004 g O .rodata 00000004 constBufInit
+00000008 g O .rodata 00000001 constBufInit2
+0000000c g O .rodata 00000001 constBufInit3
+0000003c g F .text 00000054 f
+00000000 g F .text 00000004 test
+00000090 g F .text 00000004 g
+00000000 *UND* 00000000 D_410100
+00000000 *UND* 00000000 func_004000B0
+
+
+RELOCATION RECORDS FOR [.text]:
+OFFSET TYPE VALUE
+00000044 R_MIPS_HI16 .rodata
+00000048 R_MIPS_LO16 .rodata
+00000050 R_MIPS_HI16 .rodata
+00000054 R_MIPS_LO16 .rodata
+0000005c R_MIPS_HI16 .rodata
+00000060 R_MIPS_LO16 .rodata
+00000068 R_MIPS_26 g
+0000009c R_MIPS_HI16 D_410100
+000000a0 R_MIPS_LO16 D_410100
+000000a4 R_MIPS_26 func_004000B0
+
+
+Contents of section .text:
+ 0000 27bdffe8 18a00009 afa00004 8fae0004 '...............
+ 0010 008e7821 a1e00000 8fb80004 27190001 ..x!........'...
+ 0020 0325082a 1420fff9 afb90004 10000001 .%.*. ..........
+ 0030 00000000 03e00008 27bd0018 27bdffd8 ........'...'...
+ 0040 afbf0014 3c010000 d4240028 f7a40020 ....<....$.(...
+ 0050 3c010000 c4260030 e7a6001c 3c010000 <....&.0....<...
+ 0060 c4280034 e7a80018 0c000000 00000000 .(.4............
+ 0070 10000003 00000000 10000001 00000000 ................
+ 0080 8fbf0014 27bd0028 03e00008 00000000 ....'..(........
+ 0090 27bdffe8 afbf0014 240e0004 3c010000 '.......$...<...
+ 00a0 ac2e0000 0c000000 00000000 10000001 ................
+ 00b0 00000000 8fbf0014 27bd0018 03e00008 ........'.......
+ 00c0 00000000 00000000 00000000 00000000 ................
+Contents of section .rodata:
+ 0000 0004e729 01000000 02000000 03000000 ...)............
+ 0010 48656c6c 6f202000 576f726c 64000000 Hello .World...
+ 0020 0001e0f3 00000000 40146666 66666666 ........@.ffffff
+ 0030 40a66666 40a9999a 00000000 00000000 @.ff@...........
+Contents of section .data:
+ 0000 01000000 00000000 00000000 00000000 ................
+Contents of section .options:
+ 0000 01200000 00000000 a0000002 00000000 . ..............
+ 0010 00000170 00000000 00000000 00007ff0 ...p............
+ 0020 07100000 00000000 00000000 00000000 ................
+ 0030 08100000 00000000 00000000 00000000 ................
+Contents of section .reginfo:
+ 0000 a300c032 00000000 00000170 00000000 ...2.......p....
+ 0010 00000000 00007ff0 ........