diff --git a/Dockerfile b/Dockerfile index 47ebeca8d4..bea63cb110 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,21 +1,22 @@ -FROM ubuntu:18.04 as build +FROM ubuntu:21.10 as build +ENV TZ=UTC -RUN apt-get update && \ +RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone && \ + apt-get update && \ apt-get install -y \ binutils-mips-linux-gnu \ build-essential \ pkg-config \ python3 \ python3-pip \ - wget \ git \ + wget \ unzip \ clang-tidy \ clang-format \ - clang-format-11 \ - nano \ - vbindiff \ - libpng-dev + libpng-dev && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* RUN python3 -m pip install --user colorama ansiwrap attrs watchdog python-Levenshtein RUN python3 -m pip install --upgrade attrs pycparser @@ -24,3 +25,6 @@ ENV LANG C.UTF-8 RUN mkdir /oot WORKDIR /oot + +CMD ["/bin/sh", "-c", \ + "echo 'usage:\n docker run --rm --mount type=bind,source=\"$(pwd)\",destination=/oot oot make -j$(nproc) setup\n docker run --rm --mount type=bind,source=\"$(pwd)\",destination=/oot oot make -j$(nproc)'"] diff --git a/Doxyfile b/Doxyfile index 67f2da713b..8d98f6bf9b 100644 --- a/Doxyfile +++ b/Doxyfile @@ -38,7 +38,7 @@ PROJECT_NAME = "Ocarina of Time Source" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = +PROJECT_NUMBER = # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a @@ -291,7 +291,7 @@ OPTIMIZE_OUTPUT_VHDL = NO # Note that for custom extensions you also need to set FILE_PATTERNS otherwise # the files are not read by doxygen. -EXTENSION_MAPPING = +EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable diff --git a/Jenkinsfile b/Jenkinsfile index a89b04d5d3..2c483075c0 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -39,9 +39,9 @@ pipeline { } steps { sh 'mkdir reports' - sh 'python3 progress.py csv >> reports/progress.csv' - sh 'python3 progress.py csv -m >> reports/progress_matching.csv' - sh 'python3 progress.py shield-json > reports/progress_shield.json' + sh 'python3 progress.py csv >> reports/progress-oot-nonmatching.csv' + sh 'python3 progress.py csv -m >> reports/progress-oot-matching.csv' + sh 'python3 progress.py shield-json > reports/progress-oot-shield.json' stash includes: 'reports/*', name: 'reports' } } @@ -54,9 +54,9 @@ pipeline { } steps { unstash 'reports' - sh 'cat reports/progress.csv >> /var/www/html/reports/progress.csv' - sh 'cat reports/progress_matching.csv >> /var/www/html/reports/progress_matching.csv' - sh 'cat reports/progress_shield.json > /var/www/html/reports/progress_shield.json' + sh 'cat reports/progress-oot-nonmatching.csv >> /var/www/zelda64.dev/assets/csv/progress-oot-nonmatching.csv' + sh 'cat reports/progress-oot-matching.csv >> /var/www/zelda64.dev/assets/csv/progress-oot-matching.csv' + sh 'cat reports/progress-oot-shield.json > /var/www/zelda64.dev/assets/csv/progress-oot-shield.json' } } } diff --git a/Makefile b/Makefile index c676359201..8d06110e2c 100644 --- a/Makefile +++ b/Makefile @@ -30,6 +30,10 @@ ifeq ($(COMPILER),gcc) NON_MATCHING := 1 endif +# Set prefix to mips binutils binaries (mips-linux-gnu-ld => 'mips-linux-gnu-') - Change at your own risk! +# In nearly all cases, not having 'mips-linux-gnu-*' binaries on the PATH is indicative of missing dependencies +MIPS_BINUTILS_PREFIX ?= mips-linux-gnu- + ifeq ($(NON_MATCHING),1) CFLAGS += -DNON_MATCHING CPPFLAGS += -DNON_MATCHING @@ -55,11 +59,11 @@ else endif endif +N_THREADS ?= $(shell nproc) + #### Tools #### -ifeq ($(shell type mips-linux-gnu-ld >/dev/null 2>/dev/null; echo $$?), 0) - MIPS_BINUTILS_PREFIX := mips-linux-gnu- -else - $(error Please install or build mips-linux-gnu) +ifneq ($(shell type $(MIPS_BINUTILS_PREFIX)ld >/dev/null 2>/dev/null; echo $$?), 0) + $(error Please install or build $(MIPS_BINUTILS_PREFIX)) endif # Detect compiler and set variables appropriately. @@ -105,6 +109,7 @@ MKLDSCRIPT := tools/mkldscript MKDMADATA := tools/mkdmadata ELF2ROM := tools/elf2rom ZAPD := tools/ZAPD/ZAPD.out +FADO := tools/fado/fado.elf OPTFLAGS := -O2 ASFLAGS := -march=vr4300 -32 -Iinclude @@ -150,9 +155,12 @@ O_FILES := $(foreach f,$(S_FILES:.s=.o),build/$f) \ $(foreach f,$(C_FILES:.c=.o),build/$f) \ $(foreach f,$(wildcard baserom/*),build/$f.o) +OVL_RELOC_FILES := $(shell $(CPP) $(CPPFLAGS) $(SPEC) | grep -o '[^"]*_reloc.o' ) + # Automatic dependency files -# (Only asm_processor dependencies are handled for now) -DEP_FILES := $(O_FILES:.o=.asmproc.d) +# (Only asm_processor dependencies and reloc dependencies are handled for now) +DEP_FILES := $(O_FILES:.o=.asmproc.d) $(OVL_RELOC_FILES:.o=.d) + TEXTURE_FILES_PNG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.png)) TEXTURE_FILES_JPG := $(foreach dir,$(ASSET_BIN_DIRS),$(wildcard $(dir)/*.jpg)) @@ -185,6 +193,8 @@ build/src/libultra/libc/%.o: OPTFLAGS := -O2 build/src/libultra/rmon/%.o: OPTFLAGS := -O2 build/src/libultra/gu/%.o: OPTFLAGS := -O2 +build/assets/misc/z_select_static/%.o: CFLAGS += -DF3DEX_GBI + build/src/libultra/gu/%.o: CC := $(CC_OLD) build/src/libultra/io/%.o: CC := $(CC_OLD) build/src/libultra/libc/%.o: CC := $(CC_OLD) @@ -211,21 +221,6 @@ ifeq ($(COMPARE),1) @md5sum -c checksum.md5 endif -$(ROM): $(ELF) - $(ELF2ROM) -cic 6105 $< $@ - -$(ELF): $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES) build/ldscript.txt build/undefined_syms.txt - $(LD) -T build/undefined_syms.txt -T build/ldscript.txt --no-check-sections --accept-unknown-input-arch --emit-relocs -Map build/z64.map -o $@ - -build/$(SPEC): $(SPEC) - $(CPP) $(CPPFLAGS) $< > $@ - -build/ldscript.txt: build/$(SPEC) - $(MKLDSCRIPT) $< $@ - -build/undefined_syms.txt: undefined_syms.txt - $(CPP) $(CPPFLAGS) $< > build/undefined_syms.txt - clean: $(RM) -r $(ROM) $(ELF) build @@ -243,16 +238,44 @@ setup: $(MAKE) -C tools python3 fixbaserom.py python3 extract_baserom.py - python3 extract_assets.py + python3 extract_assets.py -j$(N_THREADS) -resources: $(ASSET_FILES_OUT) test: $(ROM) $(EMULATOR) $(EMU_FLAGS) $< + .PHONY: all clean setup test distclean assetclean #### Various Recipes #### +$(ROM): $(ELF) + $(ELF2ROM) -cic 6105 $< $@ + +$(ELF): $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) $(O_FILES) $(OVL_RELOC_FILES) build/ldscript.txt build/undefined_syms.txt + $(LD) -T build/undefined_syms.txt -T build/ldscript.txt --no-check-sections --accept-unknown-input-arch --emit-relocs -Map build/z64.map -o $@ + +## Order-only prerequisites +# These ensure e.g. the O_FILES are built before the OVL_RELOC_FILES. +# The intermediate phony targets avoid quadratically-many dependencies between the targets and prerequisites. + +o_files: $(O_FILES) +$(OVL_RELOC_FILES): | o_files + +asset_files: $(TEXTURE_FILES_OUT) $(ASSET_FILES_OUT) +$(O_FILES): | asset_files + +.PHONY: o_files asset_files + + +build/$(SPEC): $(SPEC) + $(CPP) $(CPPFLAGS) $< > $@ + +build/ldscript.txt: build/$(SPEC) + $(MKLDSCRIPT) $< $@ + +build/undefined_syms.txt: undefined_syms.txt + $(CPP) $(CPPFLAGS) $< > $@ + build/baserom/%.o: baserom/% $(OBJCOPY) -I binary -O elf32-big $< $@ @@ -260,7 +283,7 @@ build/asm/%.o: asm/%.s $(AS) $(ASFLAGS) $< -o $@ build/data/%.o: data/%.s - iconv --from UTF-8 --to EUC-JP $< | $(AS) $(ASFLAGS) -o $@ + $(AS) $(ASFLAGS) $< -o $@ build/assets/text/%.enc.h: assets/text/%.h assets/text/charmap.txt python3 tools/msgenc.py assets/text/charmap.txt $< $@ @@ -280,13 +303,6 @@ build/dmadata_table_spec.h: build/$(SPEC) build/src/boot/z_std_dma.o: build/dmadata_table_spec.h build/src/dmadata/dmadata.o: build/dmadata_table_spec.h -build/src/overlays/%.o: src/overlays/%.c - $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< - $(CC_CHECK) $< - $(ZAPD) bovl -eh -i $@ -cfg $< --outputpath $(@D)/$(notdir $(@D))_reloc.s $(ZAPDFLAGS) - -test -f $(@D)/$(notdir $(@D))_reloc.s && $(AS) $(ASFLAGS) $(@D)/$(notdir $(@D))_reloc.s -o $(@D)/$(notdir $(@D))_reloc.o - @$(OBJDUMP) -d $@ > $(@:.o=.s) - build/src/%.o: src/%.c $(CC) -c $(CFLAGS) $(MIPS_VERSION) $(OPTFLAGS) -o $@ $< $(CC_CHECK) $< @@ -304,6 +320,10 @@ build/src/libultra/libc/llcvt.o: src/libultra/libc/llcvt.c python3 tools/set_o32abi_bit.py $@ @$(OBJDUMP) -d $@ > $(@:.o=.s) +build/src/overlays/%_reloc.o: build/$(SPEC) + $(FADO) $$(tools/reloc_prereq $< $(notdir $*)) -n $(notdir $*) -o $(@:.o=.s) -M $(@:.o=.d) + $(AS) $(ASFLAGS) $(@:.o=.s) -o $@ + build/%.inc.c: %.png $(ZAPD) btex -eh -tt $(subst .,,$(suffix $*)) -i $< -o $@ diff --git a/README.md b/README.md index 4495a0e398..2ab4733861 100644 --- a/README.md +++ b/README.md @@ -5,8 +5,8 @@ [jenkins]: https://jenkins.deco.mp/job/OOT/job/master [jenkins-badge]: https://img.shields.io/jenkins/build?jobUrl=https%3A%2F%2Fjenkins.deco.mp%2Fjob%2FOOT%2Fjob%2Fmaster -[progress]: https://zelda64.dev/progress.html -[progress-badge]: https://img.shields.io/endpoint?url=https://zelda64.dev/reports/progress_shield.json +[progress]: https://zelda64.dev/games/oot +[progress-badge]: https://img.shields.io/endpoint?url=https://zelda64.dev/assets/csv/progress-oot-shield.json [contributors]: https://github.com/zeldaret/oot/graphs/contributors [contributors-badge]: https://img.shields.io/github/contributors/zeldaret/oot @@ -39,37 +39,24 @@ It builds the following ROM: ## Installation +We recommend using WSL on Windows, or native Linux, which the rest of this readme describes. We currently have instructions for + +* [Windows](#Windows), with and without WSL +* [macOS](docs/BUILDING_MACOS.md) +* [Linux](#Linux-Native-or-under-WSL--VM), natively or using WSL / VM +* [Docker](docs/BUILDING_DOCKER.md) + +(These will also depend on the Linux instructions.) +Some of these may also be out of date or unmaintained; usually our contributors use WSL, Linux, and macOS, so these instructions should be up to date. + ### Windows -For Windows 10, install WSL and a distribution by following this -[Windows Subsystem for Linux Installation Guide](https://docs.microsoft.com/en-us/windows/wsl/install-win10). -We recommend using Debian or Ubuntu 18.04 Linux distributions. +For Windows 10 or 11, install WSL and a distribution by following this +[WSL Installation Guide](https://docs.microsoft.com/en-us/windows/wsl/install). +We recommend using Ubuntu 20.04 as the Linux distribution. -For older versions of Windows, install a Linux VM or refer to either [Cygwin](#Cygwin) or [Docker](#Docker) instructions. +For older versions of Windows, install a Linux VM or refer to either [Cygwin](docs/BUILDING_CYGWIN.md) or [Docker](docs/BUILDING_DOCKER.md) instructions. -### macOS - -For macOS, use homebrew to install the following dependencies: - -* coreutils -* make -* python3 -* md5sha1sum -* libpng - -You can install them with the following commands: - -```bash -brew update -brew install coreutils make python3 md5sha1sum libpng -``` - -You'll also need to [build and install mips-linux-binutils](docs/BUILDING_BINUTILS_MACOS.md). - -Going forward in this guide, please use `gmake` whenever you encounter a `make` command. -The `make` that comes with MacOS behaves differently than GNU make and is incompatible with this project. - -You should now be able to continue from [step 2](#2-clone-the-repository) of the Linux instructions. ### Linux (Native or under WSL / VM) @@ -90,6 +77,12 @@ sudo apt-get update sudo apt-get install git build-essential binutils-mips-linux-gnu python3 libpng-dev ``` +To install the Python dependencies simply run in a terminal: + +```bash +python3 -m pip install colorama +``` + If you are using GCC as the compiler for Ocarina of Time, you will also need: * gcc-mips-linux-gnu @@ -102,6 +95,12 @@ Clone `https://github.com/zeldaret/oot.git` where you wish to have the project, git clone https://github.com/zeldaret/oot.git ``` +This will copy the GitHub repository contents into a new folder in the current directory called `oot`. Change into this directory before doing anything else: + +```bash +cd oot +``` + #### 3. Prepare a base ROM Copy over your copy of the Master Quest (Debug) ROM inside the root of this new project directory. @@ -143,62 +142,12 @@ md5sum: WARNING: 1 computed checksum did NOT match This means that the built ROM isn't the same as the base one, so something went wrong or some part of the code doesn't match. **NOTE:** to speed up the build, you can either: + * pass `-jN` to `make setup` and `make`, where N is the number of threads to use in the build. The generally-accepted wisdom is to use the number of virtual cores your computer has. * pass `-j` to `make setup` and `make`, to use as many threads as possible, but beware that this can use too much memory on lower-end systems. Both of these have the disadvantage that the ordering of the terminal output is scrambled, so for debugging it is best to stick to one thread (i.e. not pass `-j` or `-jN`). -### Cygwin - -If you want to use Cygwin, you will need to: - -* Download and install [Git Bash](https://git-scm.com/download/win). -* Download and install [Cygwin](https://cygwin.com). -* [Build and install mips-linux-binutils](docs/BUILDING_BINUTILS_CYGWIN.md). - -Once mips-linux-binutils is installed you will need to install the following packages using Cygwin's installer: - -* libiconv -* dos2unix -* python3 -* libpng-devel - -Then you can continue from step [step 2](#2-clone-the-repository) of the Linux instructions. - -Note that, before building anything, you will need to run the following commands to fix line endings: - -```bash -dos2unix fixle.sh -./fixle.sh -``` - -### Docker - -#### 1. Setup requirements - -To use Docker, you'll need either Docker Desktop or Docker Toolbox installed and setup based on your system. - -You'll also need to prepare a local version of the project with a copied base ROM (see steps [2](#2-clone-the-repository) and [3](#3-prepare-a-base-rom) of the Linux instructions). - -#### 2. Create the docker image - -From inside your local project, run the following command: - -```bash -docker build . -t oot -``` - -#### 3. Start the container - -To start the container, you can mount your local filesystem into the docker container and run an interactive bash session. - -```bash -docker run -it --rm --mount type=bind,source="$(pwd)",destination=/oot oot /bin/bash -``` - -#### 4. Setup and Build the ROM - -Once inside the container, you can follow steps [4](#4-setup-the-rom-and-build-process) and [5](#5-build-the-rom) of the Linux instructions to setup and build the ROM, or run any other command you need. ## Contributing diff --git a/assets/xml/misc/z_select_static.xml b/assets/xml/misc/z_select_static.xml new file mode 100644 index 0000000000..63844e86da --- /dev/null +++ b/assets/xml/misc/z_select_static.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/objects/gameplay_dangeon_keep.xml b/assets/xml/objects/gameplay_dangeon_keep.xml index d973327ac3..d16eb4c41c 100644 --- a/assets/xml/objects/gameplay_dangeon_keep.xml +++ b/assets/xml/objects/gameplay_dangeon_keep.xml @@ -6,6 +6,7 @@ + @@ -39,8 +40,9 @@ - - + + + diff --git a/assets/xml/objects/gameplay_field_keep.xml b/assets/xml/objects/gameplay_field_keep.xml index 82e91605bd..28fa975d7d 100644 --- a/assets/xml/objects/gameplay_field_keep.xml +++ b/assets/xml/objects/gameplay_field_keep.xml @@ -23,7 +23,7 @@ - + @@ -41,10 +41,10 @@ - + - + @@ -52,11 +52,11 @@ - + - + diff --git a/assets/xml/objects/gameplay_keep.xml b/assets/xml/objects/gameplay_keep.xml index 1497ae724f..63aa8eff7d 100644 --- a/assets/xml/objects/gameplay_keep.xml +++ b/assets/xml/objects/gameplay_keep.xml @@ -704,6 +704,10 @@ + + + + diff --git a/assets/xml/objects/object_ahg.xml b/assets/xml/objects/object_ahg.xml index 2bf39576ad..f1c2c34a37 100644 --- a/assets/xml/objects/object_ahg.xml +++ b/assets/xml/objects/object_ahg.xml @@ -1,7 +1,6 @@ - - @@ -17,28 +16,24 @@ - --> - - - diff --git a/assets/xml/objects/object_ani.xml b/assets/xml/objects/object_ani.xml index c69656043f..bb85f51a4a 100644 --- a/assets/xml/objects/object_ani.xml +++ b/assets/xml/objects/object_ani.xml @@ -2,7 +2,7 @@ - + @@ -35,8 +35,8 @@ - - + + diff --git a/assets/xml/objects/object_aob.xml b/assets/xml/objects/object_aob.xml index e6202d0cf9..61b28914bd 100644 --- a/assets/xml/objects/object_aob.xml +++ b/assets/xml/objects/object_aob.xml @@ -20,7 +20,7 @@ - + diff --git a/assets/xml/objects/object_bdoor.xml b/assets/xml/objects/object_bdoor.xml index 80f7302fe2..644c06ea86 100644 --- a/assets/xml/objects/object_bdoor.xml +++ b/assets/xml/objects/object_bdoor.xml @@ -1,10 +1,15 @@ - + - + + + + + + diff --git a/assets/xml/objects/object_bird.xml b/assets/xml/objects/object_bird.xml index 167a5022dc..c0b5cac3e4 100644 --- a/assets/xml/objects/object_bird.xml +++ b/assets/xml/objects/object_bird.xml @@ -8,7 +8,7 @@ - + diff --git a/assets/xml/objects/object_bji.xml b/assets/xml/objects/object_bji.xml index 31f9873022..d2a82080fb 100644 --- a/assets/xml/objects/object_bji.xml +++ b/assets/xml/objects/object_bji.xml @@ -1,7 +1,6 @@ - - @@ -17,14 +16,10 @@ - --> - - - diff --git a/assets/xml/objects/object_blkobj.xml b/assets/xml/objects/object_blkobj.xml index a073077b82..9527292838 100644 --- a/assets/xml/objects/object_blkobj.xml +++ b/assets/xml/objects/object_blkobj.xml @@ -6,7 +6,7 @@ - + diff --git a/assets/xml/objects/object_bob.xml b/assets/xml/objects/object_bob.xml index 5c33ea778f..289e994e47 100644 --- a/assets/xml/objects/object_bob.xml +++ b/assets/xml/objects/object_bob.xml @@ -21,7 +21,9 @@ - + + + diff --git a/assets/xml/objects/object_boj.xml b/assets/xml/objects/object_boj.xml index faf0622f76..b7662c2566 100644 --- a/assets/xml/objects/object_boj.xml +++ b/assets/xml/objects/object_boj.xml @@ -1,7 +1,6 @@ - - @@ -17,20 +16,18 @@ - --> - - diff --git a/assets/xml/objects/object_box.xml b/assets/xml/objects/object_box.xml index efcec619b5..34162fc94f 100644 --- a/assets/xml/objects/object_box.xml +++ b/assets/xml/objects/object_box.xml @@ -12,7 +12,7 @@ - + diff --git a/assets/xml/objects/object_bv.xml b/assets/xml/objects/object_bv.xml index 83ff039f53..b6ef9e45f9 100644 --- a/assets/xml/objects/object_bv.xml +++ b/assets/xml/objects/object_bv.xml @@ -9,7 +9,7 @@ - + @@ -48,7 +48,7 @@ - + diff --git a/assets/xml/objects/object_bxa.xml b/assets/xml/objects/object_bxa.xml index cac49d63e1..fb78c117e0 100644 --- a/assets/xml/objects/object_bxa.xml +++ b/assets/xml/objects/object_bxa.xml @@ -5,8 +5,9 @@ - + - + + diff --git a/assets/xml/objects/object_cne.xml b/assets/xml/objects/object_cne.xml index 99daae4ccb..3860f2c3df 100644 --- a/assets/xml/objects/object_cne.xml +++ b/assets/xml/objects/object_cne.xml @@ -1,7 +1,6 @@ - - @@ -17,14 +16,10 @@ - --> - - - diff --git a/assets/xml/objects/object_crow.xml b/assets/xml/objects/object_crow.xml index 77337c6445..5304246a00 100644 --- a/assets/xml/objects/object_crow.xml +++ b/assets/xml/objects/object_crow.xml @@ -1,7 +1,7 @@ - + diff --git a/assets/xml/objects/object_ddan_objects.xml b/assets/xml/objects/object_ddan_objects.xml index 2ae6d679b7..b7df6ed847 100644 --- a/assets/xml/objects/object_ddan_objects.xml +++ b/assets/xml/objects/object_ddan_objects.xml @@ -11,16 +11,16 @@ - + - + - + diff --git a/assets/xml/objects/object_dekunuts.xml b/assets/xml/objects/object_dekunuts.xml index 5fceef4165..4a4508ee0b 100644 --- a/assets/xml/objects/object_dekunuts.xml +++ b/assets/xml/objects/object_dekunuts.xml @@ -2,7 +2,7 @@ - + diff --git a/assets/xml/objects/object_demo_6k.xml b/assets/xml/objects/object_demo_6k.xml index 73058d5e46..2e8db238f9 100644 --- a/assets/xml/objects/object_demo_6k.xml +++ b/assets/xml/objects/object_demo_6k.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_demo_kekkai.xml b/assets/xml/objects/object_demo_kekkai.xml index 1b9c9b4027..d1ac785b5e 100644 --- a/assets/xml/objects/object_demo_kekkai.xml +++ b/assets/xml/objects/object_demo_kekkai.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_dnk.xml b/assets/xml/objects/object_dnk.xml index b1e79464b8..1efec46aad 100644 --- a/assets/xml/objects/object_dnk.xml +++ b/assets/xml/objects/object_dnk.xml @@ -2,7 +2,7 @@ - + diff --git a/assets/xml/objects/object_dns.xml b/assets/xml/objects/object_dns.xml index 086c4bd11c..e66a639874 100644 --- a/assets/xml/objects/object_dns.xml +++ b/assets/xml/objects/object_dns.xml @@ -16,7 +16,7 @@ - + diff --git a/assets/xml/objects/object_dog.xml b/assets/xml/objects/object_dog.xml index 151a208f36..ef00442b60 100644 --- a/assets/xml/objects/object_dog.xml +++ b/assets/xml/objects/object_dog.xml @@ -1,41 +1,41 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/objects/object_ds.xml b/assets/xml/objects/object_ds.xml index 0413a9e2e8..b2fb1a5c26 100644 --- a/assets/xml/objects/object_ds.xml +++ b/assets/xml/objects/object_ds.xml @@ -31,7 +31,7 @@ - + diff --git a/assets/xml/objects/object_dy_obj.xml b/assets/xml/objects/object_dy_obj.xml index 4d141d5464..9d7dae3e0a 100644 --- a/assets/xml/objects/object_dy_obj.xml +++ b/assets/xml/objects/object_dy_obj.xml @@ -98,7 +98,7 @@ - + @@ -116,6 +116,6 @@ - + diff --git a/assets/xml/objects/object_ec.xml b/assets/xml/objects/object_ec.xml index 7ec83e284d..fdeccef4c5 100644 --- a/assets/xml/objects/object_ec.xml +++ b/assets/xml/objects/object_ec.xml @@ -2,7 +2,7 @@ - + diff --git a/assets/xml/objects/object_efc_erupc.xml b/assets/xml/objects/object_efc_erupc.xml index 800d9535f1..4ce96a48a1 100644 --- a/assets/xml/objects/object_efc_erupc.xml +++ b/assets/xml/objects/object_efc_erupc.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_ei.xml b/assets/xml/objects/object_ei.xml index e4132491f4..cabad17ff8 100644 --- a/assets/xml/objects/object_ei.xml +++ b/assets/xml/objects/object_ei.xml @@ -45,7 +45,7 @@ - + diff --git a/assets/xml/objects/object_fd.xml b/assets/xml/objects/object_fd.xml index 1b96e9f22e..d915b38c2f 100644 --- a/assets/xml/objects/object_fd.xml +++ b/assets/xml/objects/object_fd.xml @@ -47,7 +47,7 @@ - + diff --git a/assets/xml/objects/object_fd2.xml b/assets/xml/objects/object_fd2.xml index 8689098b9b..b3fbdcb216 100644 --- a/assets/xml/objects/object_fd2.xml +++ b/assets/xml/objects/object_fd2.xml @@ -24,7 +24,7 @@ - + diff --git a/assets/xml/objects/object_fhg.xml b/assets/xml/objects/object_fhg.xml index f3a4a55cae..eb07d8eb34 100644 --- a/assets/xml/objects/object_fhg.xml +++ b/assets/xml/objects/object_fhg.xml @@ -16,10 +16,10 @@ - + - + diff --git a/assets/xml/objects/object_fish.xml b/assets/xml/objects/object_fish.xml index f5ad4f6da0..2555f69b00 100644 --- a/assets/xml/objects/object_fish.xml +++ b/assets/xml/objects/object_fish.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_fr.xml b/assets/xml/objects/object_fr.xml index 5935f371d4..25ee2ad42e 100644 --- a/assets/xml/objects/object_fr.xml +++ b/assets/xml/objects/object_fr.xml @@ -11,7 +11,8 @@ - + + diff --git a/assets/xml/objects/object_fu.xml b/assets/xml/objects/object_fu.xml index 82c449e3de..3947e438c0 100644 --- a/assets/xml/objects/object_fu.xml +++ b/assets/xml/objects/object_fu.xml @@ -27,13 +27,13 @@ - + - + diff --git a/assets/xml/objects/object_fw.xml b/assets/xml/objects/object_fw.xml index e71f83092f..51462a3166 100644 --- a/assets/xml/objects/object_fw.xml +++ b/assets/xml/objects/object_fw.xml @@ -91,7 +91,7 @@ - + diff --git a/assets/xml/objects/object_fz.xml b/assets/xml/objects/object_fz.xml index dad6fec5ce..02f6b31076 100644 --- a/assets/xml/objects/object_fz.xml +++ b/assets/xml/objects/object_fz.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_ge1.xml b/assets/xml/objects/object_ge1.xml index 79e0768b81..c3c3e0db39 100644 --- a/assets/xml/objects/object_ge1.xml +++ b/assets/xml/objects/object_ge1.xml @@ -63,7 +63,7 @@ - + diff --git a/assets/xml/objects/object_gi_arrow.xml b/assets/xml/objects/object_gi_arrow.xml index 4b58787a9d..2520338cf9 100644 --- a/assets/xml/objects/object_gi_arrow.xml +++ b/assets/xml/objects/object_gi_arrow.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_arrowcase.xml b/assets/xml/objects/object_gi_arrowcase.xml index 267b0a734d..51c1af83ad 100644 --- a/assets/xml/objects/object_gi_arrowcase.xml +++ b/assets/xml/objects/object_gi_arrowcase.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bean.xml b/assets/xml/objects/object_gi_bean.xml index e74247816f..2091fb3362 100644 --- a/assets/xml/objects/object_gi_bean.xml +++ b/assets/xml/objects/object_gi_bean.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bomb_1.xml b/assets/xml/objects/object_gi_bomb_1.xml index bae86c11d8..13188d0bba 100644 --- a/assets/xml/objects/object_gi_bomb_1.xml +++ b/assets/xml/objects/object_gi_bomb_1.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bomb_2.xml b/assets/xml/objects/object_gi_bomb_2.xml index 1400c4a4d4..35cad2512b 100644 --- a/assets/xml/objects/object_gi_bomb_2.xml +++ b/assets/xml/objects/object_gi_bomb_2.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bombpouch.xml b/assets/xml/objects/object_gi_bombpouch.xml index 07134748c3..09cfdea364 100644 --- a/assets/xml/objects/object_gi_bombpouch.xml +++ b/assets/xml/objects/object_gi_bombpouch.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_boomerang.xml b/assets/xml/objects/object_gi_boomerang.xml index 3c1a0fe7fc..df0b013d31 100644 --- a/assets/xml/objects/object_gi_boomerang.xml +++ b/assets/xml/objects/object_gi_boomerang.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_boots_2.xml b/assets/xml/objects/object_gi_boots_2.xml index 8e9cd1028d..02884d5b5d 100644 --- a/assets/xml/objects/object_gi_boots_2.xml +++ b/assets/xml/objects/object_gi_boots_2.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bosskey.xml b/assets/xml/objects/object_gi_bosskey.xml index e5e4bc86c9..5c986e3dbb 100644 --- a/assets/xml/objects/object_gi_bosskey.xml +++ b/assets/xml/objects/object_gi_bosskey.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bottle.xml b/assets/xml/objects/object_gi_bottle.xml index 3b0884a03f..809ba8a67f 100644 --- a/assets/xml/objects/object_gi_bottle.xml +++ b/assets/xml/objects/object_gi_bottle.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bottle_letter.xml b/assets/xml/objects/object_gi_bottle_letter.xml index 443219caf5..27cfb67681 100644 --- a/assets/xml/objects/object_gi_bottle_letter.xml +++ b/assets/xml/objects/object_gi_bottle_letter.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bow.xml b/assets/xml/objects/object_gi_bow.xml index 946e9c4965..2ae89e04c5 100644 --- a/assets/xml/objects/object_gi_bow.xml +++ b/assets/xml/objects/object_gi_bow.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_bracelet.xml b/assets/xml/objects/object_gi_bracelet.xml index 5a0b62a60a..4b18e3f796 100644 --- a/assets/xml/objects/object_gi_bracelet.xml +++ b/assets/xml/objects/object_gi_bracelet.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_brokensword.xml b/assets/xml/objects/object_gi_brokensword.xml index 408741ac54..4c907e9778 100644 --- a/assets/xml/objects/object_gi_brokensword.xml +++ b/assets/xml/objects/object_gi_brokensword.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_butterfly.xml b/assets/xml/objects/object_gi_butterfly.xml index 76ac706096..aa7cc59c78 100644 --- a/assets/xml/objects/object_gi_butterfly.xml +++ b/assets/xml/objects/object_gi_butterfly.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_coin.xml b/assets/xml/objects/object_gi_coin.xml index 22e29f255f..a8eecbad11 100644 --- a/assets/xml/objects/object_gi_coin.xml +++ b/assets/xml/objects/object_gi_coin.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_compass.xml b/assets/xml/objects/object_gi_compass.xml index 076229b11e..1e7c5cf758 100644 --- a/assets/xml/objects/object_gi_compass.xml +++ b/assets/xml/objects/object_gi_compass.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_dekupouch.xml b/assets/xml/objects/object_gi_dekupouch.xml index 3d6d95d98a..dc8469e750 100644 --- a/assets/xml/objects/object_gi_dekupouch.xml +++ b/assets/xml/objects/object_gi_dekupouch.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_egg.xml b/assets/xml/objects/object_gi_egg.xml index 2b2e2847db..370cd82a5c 100644 --- a/assets/xml/objects/object_gi_egg.xml +++ b/assets/xml/objects/object_gi_egg.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_eye_lotion.xml b/assets/xml/objects/object_gi_eye_lotion.xml index 5128c5f6ff..3cd8c16b81 100644 --- a/assets/xml/objects/object_gi_eye_lotion.xml +++ b/assets/xml/objects/object_gi_eye_lotion.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_fire.xml b/assets/xml/objects/object_gi_fire.xml index a57fba6e86..671bf3362d 100644 --- a/assets/xml/objects/object_gi_fire.xml +++ b/assets/xml/objects/object_gi_fire.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_fish.xml b/assets/xml/objects/object_gi_fish.xml index edb39dc297..8b932135f7 100644 --- a/assets/xml/objects/object_gi_fish.xml +++ b/assets/xml/objects/object_gi_fish.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_frog.xml b/assets/xml/objects/object_gi_frog.xml index f180fd267b..577f1dd0b6 100644 --- a/assets/xml/objects/object_gi_frog.xml +++ b/assets/xml/objects/object_gi_frog.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_gerudo.xml b/assets/xml/objects/object_gi_gerudo.xml index 3be8d34620..72b320aeb4 100644 --- a/assets/xml/objects/object_gi_gerudo.xml +++ b/assets/xml/objects/object_gi_gerudo.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_gerudomask.xml b/assets/xml/objects/object_gi_gerudomask.xml index b53bf24af6..9debfa88f1 100644 --- a/assets/xml/objects/object_gi_gerudomask.xml +++ b/assets/xml/objects/object_gi_gerudomask.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_ghost.xml b/assets/xml/objects/object_gi_ghost.xml index 186f4c74b7..786b50521b 100644 --- a/assets/xml/objects/object_gi_ghost.xml +++ b/assets/xml/objects/object_gi_ghost.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_glasses.xml b/assets/xml/objects/object_gi_glasses.xml index 63d32ab5ac..756fce9090 100644 --- a/assets/xml/objects/object_gi_glasses.xml +++ b/assets/xml/objects/object_gi_glasses.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_gloves.xml b/assets/xml/objects/object_gi_gloves.xml index 1b4282dcaa..2e87b97f7e 100644 --- a/assets/xml/objects/object_gi_gloves.xml +++ b/assets/xml/objects/object_gi_gloves.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_goddess.xml b/assets/xml/objects/object_gi_goddess.xml index 50cbdd8918..f45faa4245 100644 --- a/assets/xml/objects/object_gi_goddess.xml +++ b/assets/xml/objects/object_gi_goddess.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_grass.xml b/assets/xml/objects/object_gi_grass.xml index ae7834201a..3d2ee3bd61 100644 --- a/assets/xml/objects/object_gi_grass.xml +++ b/assets/xml/objects/object_gi_grass.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_hammer.xml b/assets/xml/objects/object_gi_hammer.xml index feb5c8659d..d592e6b4ba 100644 --- a/assets/xml/objects/object_gi_hammer.xml +++ b/assets/xml/objects/object_gi_hammer.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_heart.xml b/assets/xml/objects/object_gi_heart.xml index 48e78b1b5c..b861897573 100644 --- a/assets/xml/objects/object_gi_heart.xml +++ b/assets/xml/objects/object_gi_heart.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_hearts.xml b/assets/xml/objects/object_gi_hearts.xml index d2e763e631..569d814982 100644 --- a/assets/xml/objects/object_gi_hearts.xml +++ b/assets/xml/objects/object_gi_hearts.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_hookshot.xml b/assets/xml/objects/object_gi_hookshot.xml index a6b3b0fdac..d8a2bacae1 100644 --- a/assets/xml/objects/object_gi_hookshot.xml +++ b/assets/xml/objects/object_gi_hookshot.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_hoverboots.xml b/assets/xml/objects/object_gi_hoverboots.xml index c4a67877b2..78a96c353c 100644 --- a/assets/xml/objects/object_gi_hoverboots.xml +++ b/assets/xml/objects/object_gi_hoverboots.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_insect.xml b/assets/xml/objects/object_gi_insect.xml index 7af5b5b3b2..4bd5cca1c0 100644 --- a/assets/xml/objects/object_gi_insect.xml +++ b/assets/xml/objects/object_gi_insect.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_jewel.xml b/assets/xml/objects/object_gi_jewel.xml index e83c651164..c433207657 100644 --- a/assets/xml/objects/object_gi_jewel.xml +++ b/assets/xml/objects/object_gi_jewel.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_key.xml b/assets/xml/objects/object_gi_key.xml index a37d45a71c..be1af7f8d4 100644 --- a/assets/xml/objects/object_gi_key.xml +++ b/assets/xml/objects/object_gi_key.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_ki_tan_mask.xml b/assets/xml/objects/object_gi_ki_tan_mask.xml index f66535af37..85565241e8 100644 --- a/assets/xml/objects/object_gi_ki_tan_mask.xml +++ b/assets/xml/objects/object_gi_ki_tan_mask.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_liquid.xml b/assets/xml/objects/object_gi_liquid.xml index 5eeeca0fd2..b91c58cd9f 100644 --- a/assets/xml/objects/object_gi_liquid.xml +++ b/assets/xml/objects/object_gi_liquid.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_longsword.xml b/assets/xml/objects/object_gi_longsword.xml index 7161e42e38..360a678449 100644 --- a/assets/xml/objects/object_gi_longsword.xml +++ b/assets/xml/objects/object_gi_longsword.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_m_arrow.xml b/assets/xml/objects/object_gi_m_arrow.xml index 0fd659ae95..774e73f8f1 100644 --- a/assets/xml/objects/object_gi_m_arrow.xml +++ b/assets/xml/objects/object_gi_m_arrow.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_magicpot.xml b/assets/xml/objects/object_gi_magicpot.xml index 7623e6353e..feeda1510a 100644 --- a/assets/xml/objects/object_gi_magicpot.xml +++ b/assets/xml/objects/object_gi_magicpot.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_map.xml b/assets/xml/objects/object_gi_map.xml index 8887dd22c9..6812dbe518 100644 --- a/assets/xml/objects/object_gi_map.xml +++ b/assets/xml/objects/object_gi_map.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_medal.xml b/assets/xml/objects/object_gi_medal.xml index 28e5b1e683..2c10c57508 100644 --- a/assets/xml/objects/object_gi_medal.xml +++ b/assets/xml/objects/object_gi_medal.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_melody.xml b/assets/xml/objects/object_gi_melody.xml index b01fca9538..c91a293863 100644 --- a/assets/xml/objects/object_gi_melody.xml +++ b/assets/xml/objects/object_gi_melody.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_milk.xml b/assets/xml/objects/object_gi_milk.xml index 00b9530d95..5c976cd4ff 100644 --- a/assets/xml/objects/object_gi_milk.xml +++ b/assets/xml/objects/object_gi_milk.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_mushroom.xml b/assets/xml/objects/object_gi_mushroom.xml index 5b19bca743..8cb47aa1cc 100644 --- a/assets/xml/objects/object_gi_mushroom.xml +++ b/assets/xml/objects/object_gi_mushroom.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_niwatori.xml b/assets/xml/objects/object_gi_niwatori.xml index 713cc1ce5a..73e1e5bb33 100644 --- a/assets/xml/objects/object_gi_niwatori.xml +++ b/assets/xml/objects/object_gi_niwatori.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_nuts.xml b/assets/xml/objects/object_gi_nuts.xml index 5508fe8569..03d4fcd86f 100644 --- a/assets/xml/objects/object_gi_nuts.xml +++ b/assets/xml/objects/object_gi_nuts.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_ocarina.xml b/assets/xml/objects/object_gi_ocarina.xml index 7693cc122f..5473b323ad 100644 --- a/assets/xml/objects/object_gi_ocarina.xml +++ b/assets/xml/objects/object_gi_ocarina.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_ocarina_0.xml b/assets/xml/objects/object_gi_ocarina_0.xml index 336d338946..a17d7e5b82 100644 --- a/assets/xml/objects/object_gi_ocarina_0.xml +++ b/assets/xml/objects/object_gi_ocarina_0.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_pachinko.xml b/assets/xml/objects/object_gi_pachinko.xml index 5f808baf92..806f15c103 100644 --- a/assets/xml/objects/object_gi_pachinko.xml +++ b/assets/xml/objects/object_gi_pachinko.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_powder.xml b/assets/xml/objects/object_gi_powder.xml index fb7dc0155d..a0a261b80d 100644 --- a/assets/xml/objects/object_gi_powder.xml +++ b/assets/xml/objects/object_gi_powder.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_prescription.xml b/assets/xml/objects/object_gi_prescription.xml index 081de301c4..e0ef1fc1ff 100644 --- a/assets/xml/objects/object_gi_prescription.xml +++ b/assets/xml/objects/object_gi_prescription.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_rabit_mask.xml b/assets/xml/objects/object_gi_rabit_mask.xml index 75f855550d..838b032c78 100644 --- a/assets/xml/objects/object_gi_rabit_mask.xml +++ b/assets/xml/objects/object_gi_rabit_mask.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_redead_mask.xml b/assets/xml/objects/object_gi_redead_mask.xml index 7de08487f8..1b663c9b78 100644 --- a/assets/xml/objects/object_gi_redead_mask.xml +++ b/assets/xml/objects/object_gi_redead_mask.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_rupy.xml b/assets/xml/objects/object_gi_rupy.xml index 0a1af96d0f..815e4bf3f9 100644 --- a/assets/xml/objects/object_gi_rupy.xml +++ b/assets/xml/objects/object_gi_rupy.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_saw.xml b/assets/xml/objects/object_gi_saw.xml index dcc038b7c1..2bc5e11730 100644 --- a/assets/xml/objects/object_gi_saw.xml +++ b/assets/xml/objects/object_gi_saw.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_scale.xml b/assets/xml/objects/object_gi_scale.xml index 1cf5de5b99..3b227756ee 100644 --- a/assets/xml/objects/object_gi_scale.xml +++ b/assets/xml/objects/object_gi_scale.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_seed.xml b/assets/xml/objects/object_gi_seed.xml index 82c15c82d2..9159d8dda0 100644 --- a/assets/xml/objects/object_gi_seed.xml +++ b/assets/xml/objects/object_gi_seed.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_shield_1.xml b/assets/xml/objects/object_gi_shield_1.xml index 2e93695699..0bff097641 100644 --- a/assets/xml/objects/object_gi_shield_1.xml +++ b/assets/xml/objects/object_gi_shield_1.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_shield_2.xml b/assets/xml/objects/object_gi_shield_2.xml index 176ae025fe..eeff7a3dd0 100644 --- a/assets/xml/objects/object_gi_shield_2.xml +++ b/assets/xml/objects/object_gi_shield_2.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_shield_3.xml b/assets/xml/objects/object_gi_shield_3.xml index 250bf7fea3..1411bf0f15 100644 --- a/assets/xml/objects/object_gi_shield_3.xml +++ b/assets/xml/objects/object_gi_shield_3.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_skj_mask.xml b/assets/xml/objects/object_gi_skj_mask.xml index e6c90f76f1..eec3493c3d 100644 --- a/assets/xml/objects/object_gi_skj_mask.xml +++ b/assets/xml/objects/object_gi_skj_mask.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_soul.xml b/assets/xml/objects/object_gi_soul.xml index 76ffc56852..5fa19ad992 100644 --- a/assets/xml/objects/object_gi_soul.xml +++ b/assets/xml/objects/object_gi_soul.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_stick.xml b/assets/xml/objects/object_gi_stick.xml index fed89f4659..84e2cdd8c3 100644 --- a/assets/xml/objects/object_gi_stick.xml +++ b/assets/xml/objects/object_gi_stick.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_sutaru.xml b/assets/xml/objects/object_gi_sutaru.xml index a2606afbe3..87169b9c19 100644 --- a/assets/xml/objects/object_gi_sutaru.xml +++ b/assets/xml/objects/object_gi_sutaru.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_sword_1.xml b/assets/xml/objects/object_gi_sword_1.xml index e1119abca0..341bf77b1e 100644 --- a/assets/xml/objects/object_gi_sword_1.xml +++ b/assets/xml/objects/object_gi_sword_1.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_ticketstone.xml b/assets/xml/objects/object_gi_ticketstone.xml index 0fa37fe11e..d1059ed0a6 100644 --- a/assets/xml/objects/object_gi_ticketstone.xml +++ b/assets/xml/objects/object_gi_ticketstone.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gi_truth_mask.xml b/assets/xml/objects/object_gi_truth_mask.xml index f28c7cbcad..140b182597 100644 --- a/assets/xml/objects/object_gi_truth_mask.xml +++ b/assets/xml/objects/object_gi_truth_mask.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gla.xml b/assets/xml/objects/object_gla.xml index 499a3720d1..ca4d9225da 100644 --- a/assets/xml/objects/object_gla.xml +++ b/assets/xml/objects/object_gla.xml @@ -70,7 +70,7 @@ - + diff --git a/assets/xml/objects/object_gnd.xml b/assets/xml/objects/object_gnd.xml index 152d57c7b9..53d2bbde4c 100644 --- a/assets/xml/objects/object_gnd.xml +++ b/assets/xml/objects/object_gnd.xml @@ -1,9 +1,9 @@ - + - + @@ -18,16 +18,16 @@ - + - + - + @@ -40,36 +40,36 @@ - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + - - + + - + diff --git a/assets/xml/objects/object_god_lgt.xml b/assets/xml/objects/object_god_lgt.xml index 60df9e4693..98fbd9f370 100644 --- a/assets/xml/objects/object_god_lgt.xml +++ b/assets/xml/objects/object_god_lgt.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_gt.xml b/assets/xml/objects/object_gt.xml index 1d79d4e39e..dd48318d1d 100644 --- a/assets/xml/objects/object_gt.xml +++ b/assets/xml/objects/object_gt.xml @@ -12,15 +12,15 @@ - + - + - + @@ -33,6 +33,6 @@ - + diff --git a/assets/xml/objects/object_hintnuts.xml b/assets/xml/objects/object_hintnuts.xml index f419f7546a..f7da2e8f5c 100644 --- a/assets/xml/objects/object_hintnuts.xml +++ b/assets/xml/objects/object_hintnuts.xml @@ -2,7 +2,7 @@ - + diff --git a/assets/xml/objects/object_horse_link_child.xml b/assets/xml/objects/object_horse_link_child.xml index f93abfa521..1491189a13 100644 --- a/assets/xml/objects/object_horse_link_child.xml +++ b/assets/xml/objects/object_horse_link_child.xml @@ -13,7 +13,7 @@ - + diff --git a/assets/xml/objects/object_human.xml b/assets/xml/objects/object_human.xml index 22ca818190..c52398446b 100644 --- a/assets/xml/objects/object_human.xml +++ b/assets/xml/objects/object_human.xml @@ -44,7 +44,7 @@ - + diff --git a/assets/xml/objects/object_in.xml b/assets/xml/objects/object_in.xml index 84c1140475..155b9c9ad1 100644 --- a/assets/xml/objects/object_in.xml +++ b/assets/xml/objects/object_in.xml @@ -119,7 +119,7 @@ - + diff --git a/assets/xml/objects/object_jj.xml b/assets/xml/objects/object_jj.xml index 62bae8cb91..96ff7dc02a 100644 --- a/assets/xml/objects/object_jj.xml +++ b/assets/xml/objects/object_jj.xml @@ -3,7 +3,7 @@ - + @@ -24,7 +24,7 @@ - + @@ -72,6 +72,6 @@ - + diff --git a/assets/xml/objects/object_jya_obj.xml b/assets/xml/objects/object_jya_obj.xml index 5b488e86de..4a203b0b92 100644 --- a/assets/xml/objects/object_jya_obj.xml +++ b/assets/xml/objects/object_jya_obj.xml @@ -55,15 +55,15 @@ - + - + - + - - - + + + diff --git a/assets/xml/objects/object_kanban.xml b/assets/xml/objects/object_kanban.xml index 9ffc7a2ceb..faa7f7ce38 100644 --- a/assets/xml/objects/object_kanban.xml +++ b/assets/xml/objects/object_kanban.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_kingdodongo.xml b/assets/xml/objects/object_kingdodongo.xml index 932b0b16d8..b3da9a6086 100644 --- a/assets/xml/objects/object_kingdodongo.xml +++ b/assets/xml/objects/object_kingdodongo.xml @@ -108,6 +108,14 @@ + + + + + + + + diff --git a/assets/xml/objects/object_km1.xml b/assets/xml/objects/object_km1.xml index 0a918a798e..4d17119251 100644 --- a/assets/xml/objects/object_km1.xml +++ b/assets/xml/objects/object_km1.xml @@ -1,7 +1,7 @@ - + @@ -17,9 +17,9 @@ - + - + @@ -29,7 +29,7 @@ - + diff --git a/assets/xml/objects/object_kusa.xml b/assets/xml/objects/object_kusa.xml index 67291a5543..3b9ee43c6c 100644 --- a/assets/xml/objects/object_kusa.xml +++ b/assets/xml/objects/object_kusa.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_kw1.xml b/assets/xml/objects/object_kw1.xml index eab561b1fb..534c223b29 100644 --- a/assets/xml/objects/object_kw1.xml +++ b/assets/xml/objects/object_kw1.xml @@ -1,7 +1,7 @@ - + @@ -26,14 +26,14 @@ - + - + - + diff --git a/assets/xml/objects/object_kz.xml b/assets/xml/objects/object_kz.xml index fe9ac5c06e..303988c60d 100644 --- a/assets/xml/objects/object_kz.xml +++ b/assets/xml/objects/object_kz.xml @@ -1,43 +1,45 @@  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - + + + + diff --git a/assets/xml/objects/object_link_boy.xml b/assets/xml/objects/object_link_boy.xml new file mode 100644 index 0000000000..cd5ac2900e --- /dev/null +++ b/assets/xml/objects/object_link_boy.xml @@ -0,0 +1,271 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/assets/xml/objects/object_link_child.xml b/assets/xml/objects/object_link_child.xml index 0e0bd8be36..3d4c48fdc0 100644 --- a/assets/xml/objects/object_link_child.xml +++ b/assets/xml/objects/object_link_child.xml @@ -1,75 +1,76 @@ + - - - - + + + + - - - - - - + + + + + + - - - - - + + + + + - - - - - - + + + + + + - - - - - + + + + + - + - - - - - - - - - + + + + + + + + + - - + + - - + + - + - + @@ -91,12 +92,12 @@ - + - - + + @@ -108,7 +109,7 @@ - + @@ -118,108 +119,108 @@ - + - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - + + + - - - - + + + + + - - - - + + + + + + + + + + + + + + + + + + + - - - - - - - - - - + + + + + + - - - - - - - - - + + + + + + + + + - - - - + + + + - - - - - + - + - + - + - + - + + + + + diff --git a/assets/xml/objects/object_ma1.xml b/assets/xml/objects/object_ma1.xml index 63eeb38950..466670e18a 100644 --- a/assets/xml/objects/object_ma1.xml +++ b/assets/xml/objects/object_ma1.xml @@ -1,7 +1,7 @@ - + diff --git a/assets/xml/objects/object_ma2.xml b/assets/xml/objects/object_ma2.xml index ce5910fb80..0b6eabff70 100644 --- a/assets/xml/objects/object_ma2.xml +++ b/assets/xml/objects/object_ma2.xml @@ -21,7 +21,7 @@ - + diff --git a/assets/xml/objects/object_medal.xml b/assets/xml/objects/object_medal.xml index 533872a551..badeb05323 100644 --- a/assets/xml/objects/object_medal.xml +++ b/assets/xml/objects/object_medal.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_mizu_objects.xml b/assets/xml/objects/object_mizu_objects.xml index 1abd73bc0b..f25c29d6c3 100644 --- a/assets/xml/objects/object_mizu_objects.xml +++ b/assets/xml/objects/object_mizu_objects.xml @@ -10,7 +10,7 @@ - + @@ -25,17 +25,17 @@ - + - + - + - + diff --git a/assets/xml/objects/object_mo.xml b/assets/xml/objects/object_mo.xml index a0e8ded406..df4b5c640a 100644 --- a/assets/xml/objects/object_mo.xml +++ b/assets/xml/objects/object_mo.xml @@ -2,7 +2,7 @@ - + @@ -63,12 +63,12 @@ - + - + diff --git a/assets/xml/objects/object_mori_objects.xml b/assets/xml/objects/object_mori_objects.xml index c81fea92ec..bef9686f5c 100644 --- a/assets/xml/objects/object_mori_objects.xml +++ b/assets/xml/objects/object_mori_objects.xml @@ -1,8 +1,8 @@ - + - + diff --git a/assets/xml/objects/object_ms.xml b/assets/xml/objects/object_ms.xml index a87d0e6b36..66923df8ae 100644 --- a/assets/xml/objects/object_ms.xml +++ b/assets/xml/objects/object_ms.xml @@ -2,7 +2,7 @@ - + diff --git a/assets/xml/objects/object_nwc.xml b/assets/xml/objects/object_nwc.xml index 96ffa32383..e93aa22c08 100644 --- a/assets/xml/objects/object_nwc.xml +++ b/assets/xml/objects/object_nwc.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_ny.xml b/assets/xml/objects/object_ny.xml index e2e8187ff8..631db9c505 100644 --- a/assets/xml/objects/object_ny.xml +++ b/assets/xml/objects/object_ny.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_oF1d_map.xml b/assets/xml/objects/object_oF1d_map.xml index c4f3a41f82..079189319c 100644 --- a/assets/xml/objects/object_oF1d_map.xml +++ b/assets/xml/objects/object_oF1d_map.xml @@ -1,5 +1,5 @@ - + @@ -12,13 +12,13 @@ - + - + @@ -30,6 +30,6 @@ - + diff --git a/assets/xml/objects/object_oF1s.xml b/assets/xml/objects/object_oF1s.xml index 11359eff53..22d4169a2b 100644 --- a/assets/xml/objects/object_oF1s.xml +++ b/assets/xml/objects/object_oF1s.xml @@ -1,10 +1,6 @@ - - - - - @@ -22,16 +18,11 @@ - --> - - - diff --git a/assets/xml/objects/object_ossan.xml b/assets/xml/objects/object_ossan.xml index 78480cd76d..963053f3f4 100644 --- a/assets/xml/objects/object_ossan.xml +++ b/assets/xml/objects/object_ossan.xml @@ -1,8 +1,8 @@ - - + + diff --git a/assets/xml/objects/object_owl.xml b/assets/xml/objects/object_owl.xml index fdc64b3aa9..e6fa5ca371 100644 --- a/assets/xml/objects/object_owl.xml +++ b/assets/xml/objects/object_owl.xml @@ -53,11 +53,11 @@ - - - - + + + + diff --git a/assets/xml/objects/object_po_composer.xml b/assets/xml/objects/object_po_composer.xml index 2ab8d64d85..1e1d79c73f 100644 --- a/assets/xml/objects/object_po_composer.xml +++ b/assets/xml/objects/object_po_composer.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_po_field.xml b/assets/xml/objects/object_po_field.xml index 10b402e2c7..542c387bcf 100644 --- a/assets/xml/objects/object_po_field.xml +++ b/assets/xml/objects/object_po_field.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_po_sisters.xml b/assets/xml/objects/object_po_sisters.xml index e0c9f0834b..7752843444 100644 --- a/assets/xml/objects/object_po_sisters.xml +++ b/assets/xml/objects/object_po_sisters.xml @@ -18,11 +18,11 @@ - - - - + + + + - + diff --git a/assets/xml/objects/object_poh.xml b/assets/xml/objects/object_poh.xml index 009d0fca3f..96c7e08182 100644 --- a/assets/xml/objects/object_poh.xml +++ b/assets/xml/objects/object_poh.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_ps.xml b/assets/xml/objects/object_ps.xml index 043e232d64..c37b898653 100644 --- a/assets/xml/objects/object_ps.xml +++ b/assets/xml/objects/object_ps.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_ru1.xml b/assets/xml/objects/object_ru1.xml index 3d413619ff..482949c903 100644 --- a/assets/xml/objects/object_ru1.xml +++ b/assets/xml/objects/object_ru1.xml @@ -38,10 +38,10 @@ - + - + @@ -60,9 +60,9 @@ - + - + diff --git a/assets/xml/objects/object_ru2.xml b/assets/xml/objects/object_ru2.xml index 2a8d70af3e..d6cea22915 100644 --- a/assets/xml/objects/object_ru2.xml +++ b/assets/xml/objects/object_ru2.xml @@ -49,7 +49,7 @@ - + @@ -58,7 +58,7 @@ - + diff --git a/assets/xml/objects/object_sa.xml b/assets/xml/objects/object_sa.xml index a19446453b..8a63840409 100644 --- a/assets/xml/objects/object_sa.xml +++ b/assets/xml/objects/object_sa.xml @@ -1,7 +1,7 @@ - + @@ -72,7 +72,7 @@ - + diff --git a/assets/xml/objects/object_sb.xml b/assets/xml/objects/object_sb.xml index 64d3bb005a..0df0f4de30 100644 --- a/assets/xml/objects/object_sb.xml +++ b/assets/xml/objects/object_sb.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_sd.xml b/assets/xml/objects/object_sd.xml index c72efeae10..c872472e71 100644 --- a/assets/xml/objects/object_sd.xml +++ b/assets/xml/objects/object_sd.xml @@ -52,7 +52,7 @@ - + diff --git a/assets/xml/objects/object_siofuki.xml b/assets/xml/objects/object_siofuki.xml index a23240a728..5b4764d9cf 100644 --- a/assets/xml/objects/object_siofuki.xml +++ b/assets/xml/objects/object_siofuki.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_skj.xml b/assets/xml/objects/object_skj.xml index 3abdd610f8..9d9c1c3a0b 100644 --- a/assets/xml/objects/object_skj.xml +++ b/assets/xml/objects/object_skj.xml @@ -23,7 +23,7 @@ - + @@ -52,7 +52,7 @@ - + diff --git a/assets/xml/objects/object_spot00_break.xml b/assets/xml/objects/object_spot00_break.xml index d3be88315f..bee1361fab 100644 --- a/assets/xml/objects/object_spot00_break.xml +++ b/assets/xml/objects/object_spot00_break.xml @@ -7,7 +7,7 @@ - + diff --git a/assets/xml/objects/object_spot06_objects.xml b/assets/xml/objects/object_spot06_objects.xml index e3da63b0f0..5084fd244e 100644 --- a/assets/xml/objects/object_spot06_objects.xml +++ b/assets/xml/objects/object_spot06_objects.xml @@ -16,9 +16,9 @@ - + - + diff --git a/assets/xml/objects/object_spot08_obj.xml b/assets/xml/objects/object_spot08_obj.xml index 4d71f3473f..8d2aa760ce 100644 --- a/assets/xml/objects/object_spot08_obj.xml +++ b/assets/xml/objects/object_spot08_obj.xml @@ -15,13 +15,13 @@ - + - + diff --git a/assets/xml/objects/object_spot16_obj.xml b/assets/xml/objects/object_spot16_obj.xml index d39de812a9..b7a6ff4d54 100644 --- a/assets/xml/objects/object_spot16_obj.xml +++ b/assets/xml/objects/object_spot16_obj.xml @@ -6,6 +6,6 @@ - + diff --git a/assets/xml/objects/object_spot17_obj.xml b/assets/xml/objects/object_spot17_obj.xml index 02b5db5620..d4239d8d28 100644 --- a/assets/xml/objects/object_spot17_obj.xml +++ b/assets/xml/objects/object_spot17_obj.xml @@ -1,6 +1,6 @@ - + diff --git a/assets/xml/objects/object_sst.xml b/assets/xml/objects/object_sst.xml index a80780741e..378351b220 100644 --- a/assets/xml/objects/object_sst.xml +++ b/assets/xml/objects/object_sst.xml @@ -1,8 +1,9 @@ + - + diff --git a/assets/xml/objects/object_st.xml b/assets/xml/objects/object_st.xml index fe617cf148..3d8617116d 100644 --- a/assets/xml/objects/object_st.xml +++ b/assets/xml/objects/object_st.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_stream.xml b/assets/xml/objects/object_stream.xml index 59b0838e47..cd9ab07636 100644 --- a/assets/xml/objects/object_stream.xml +++ b/assets/xml/objects/object_stream.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_toki_objects.xml b/assets/xml/objects/object_toki_objects.xml index cd07e60d2b..fe22dcca08 100644 --- a/assets/xml/objects/object_toki_objects.xml +++ b/assets/xml/objects/object_toki_objects.xml @@ -1,4 +1,5 @@  + diff --git a/assets/xml/objects/object_trap.xml b/assets/xml/objects/object_trap.xml index 56195cf41b..5c462a3127 100644 --- a/assets/xml/objects/object_trap.xml +++ b/assets/xml/objects/object_trap.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_wf.xml b/assets/xml/objects/object_wf.xml index ebfb708d2d..96ea841032 100644 --- a/assets/xml/objects/object_wf.xml +++ b/assets/xml/objects/object_wf.xml @@ -6,7 +6,7 @@ - + @@ -21,10 +21,10 @@ - + - + diff --git a/assets/xml/objects/object_ydan_objects.xml b/assets/xml/objects/object_ydan_objects.xml index f46d6f657b..5c2c27a05a 100644 --- a/assets/xml/objects/object_ydan_objects.xml +++ b/assets/xml/objects/object_ydan_objects.xml @@ -1,20 +1,20 @@ + - - + - + - + - + diff --git a/assets/xml/objects/object_zf.xml b/assets/xml/objects/object_zf.xml index 7f20eb7866..c5c79c7cca 100644 --- a/assets/xml/objects/object_zf.xml +++ b/assets/xml/objects/object_zf.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/objects/object_zl1.xml b/assets/xml/objects/object_zl1.xml index c7082a3db7..1b83550605 100644 --- a/assets/xml/objects/object_zl1.xml +++ b/assets/xml/objects/object_zl1.xml @@ -96,7 +96,7 @@ - + diff --git a/assets/xml/objects/object_zl4.xml b/assets/xml/objects/object_zl4.xml index b43e5ba34e..e87a654656 100644 --- a/assets/xml/objects/object_zl4.xml +++ b/assets/xml/objects/object_zl4.xml @@ -43,7 +43,7 @@ - + diff --git a/assets/xml/objects/object_zo.xml b/assets/xml/objects/object_zo.xml index 77465760ef..e362c45f77 100644 --- a/assets/xml/objects/object_zo.xml +++ b/assets/xml/objects/object_zo.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/overlays/ovl_Bg_Ganon_Otyuka.xml b/assets/xml/overlays/ovl_Bg_Ganon_Otyuka.xml index 871c97b409..6b9a9a7441 100644 --- a/assets/xml/overlays/ovl_Bg_Ganon_Otyuka.xml +++ b/assets/xml/overlays/ovl_Bg_Ganon_Otyuka.xml @@ -1,13 +1,13 @@ - + - + @@ -23,7 +23,7 @@ - + diff --git a/assets/xml/overlays/ovl_Bg_Jya_Cobra.xml b/assets/xml/overlays/ovl_Bg_Jya_Cobra.xml index 4e40918f87..874bb1ec67 100644 --- a/assets/xml/overlays/ovl_Bg_Jya_Cobra.xml +++ b/assets/xml/overlays/ovl_Bg_Jya_Cobra.xml @@ -5,6 +5,6 @@ - + diff --git a/assets/xml/overlays/ovl_Boss_Ganon.xml b/assets/xml/overlays/ovl_Boss_Ganon.xml index 49cd1b24a2..e84792fa37 100644 --- a/assets/xml/overlays/ovl_Boss_Ganon.xml +++ b/assets/xml/overlays/ovl_Boss_Ganon.xml @@ -12,7 +12,7 @@ - + diff --git a/assets/xml/overlays/ovl_Boss_Ganon2.xml b/assets/xml/overlays/ovl_Boss_Ganon2.xml index 73a8ebb3f7..cbb8389968 100644 --- a/assets/xml/overlays/ovl_Boss_Ganon2.xml +++ b/assets/xml/overlays/ovl_Boss_Ganon2.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/overlays/ovl_En_Bili.xml b/assets/xml/overlays/ovl_En_Bili.xml index 483a2fcd46..35c3fa301e 100644 --- a/assets/xml/overlays/ovl_En_Bili.xml +++ b/assets/xml/overlays/ovl_En_Bili.xml @@ -2,6 +2,6 @@ - + diff --git a/assets/xml/overlays/ovl_End_Title.xml b/assets/xml/overlays/ovl_End_Title.xml index 82dceca252..841d45f6dd 100644 --- a/assets/xml/overlays/ovl_End_Title.xml +++ b/assets/xml/overlays/ovl_End_Title.xml @@ -6,12 +6,12 @@ - + - + diff --git a/assets/xml/overlays/ovl_Magic_Dark.xml b/assets/xml/overlays/ovl_Magic_Dark.xml index cd8d455921..b7247fefba 100644 --- a/assets/xml/overlays/ovl_Magic_Dark.xml +++ b/assets/xml/overlays/ovl_Magic_Dark.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/overlays/ovl_Oceff_Storm.xml b/assets/xml/overlays/ovl_Oceff_Storm.xml index a46b4330cb..59aaaf6ad6 100644 --- a/assets/xml/overlays/ovl_Oceff_Storm.xml +++ b/assets/xml/overlays/ovl_Oceff_Storm.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/overlays/ovl_Oceff_Wipe4.xml b/assets/xml/overlays/ovl_Oceff_Wipe4.xml index e0b4cd7b6a..07a3e8fbc4 100644 --- a/assets/xml/overlays/ovl_Oceff_Wipe4.xml +++ b/assets/xml/overlays/ovl_Oceff_Wipe4.xml @@ -1,4 +1,5 @@ + diff --git a/assets/xml/scenes/dungeons/ddan.xml b/assets/xml/scenes/dungeons/ddan.xml index f6572b9f8e..197839bde2 100644 --- a/assets/xml/scenes/dungeons/ddan.xml +++ b/assets/xml/scenes/dungeons/ddan.xml @@ -12,7 +12,7 @@ - + diff --git a/assets/xml/scenes/overworld/souko.xml b/assets/xml/scenes/overworld/souko.xml index 508beb85d7..bc6336b360 100644 --- a/assets/xml/scenes/overworld/souko.xml +++ b/assets/xml/scenes/overworld/souko.xml @@ -1,7 +1,7 @@ - - + + diff --git a/data/code_800F7260.bss.s b/data/code_800F7260.bss.s deleted file mode 100644 index 7a55499e0e..0000000000 --- a/data/code_800F7260.bss.s +++ /dev/null @@ -1,85 +0,0 @@ -.include "macro.inc" - -# assembler directives -.set noat # allow manual use of $at -.set noreorder # don't insert nops after branches -.set gp=64 # allow use of 64-bit general purpose registers - -.section .bss - -.balign 16 - -glabel D_8016BAD0 - .space 0x1B0 - -glabel D_8016BC80 - .space 0x240 - -glabel D_8016BEC0 - .space 0x420 - -glabel D_8016C2E0 - .space 0x3C0 - -glabel D_8016C6A0 - .space 0x180 - -glabel D_8016C820 - .space 0x90 - -glabel D_8016C8B0 - .space 0xF0 - -glabel sSoundRequests - .space 0x1800 - -glabel sSoundBankListEnd - .space 0x8 - -glabel sSoundBankFreeListStart - .space 0x8 - -glabel sSoundBankUnused - .space 0x8 - -glabel gActiveSounds - .space 0xA8 - -glabel sCurSfxPlayerChannelIdx - .space 0x4 - -glabel gSoundBankMuted - .space 0xC - -glabel sUnusedBankLerp - .space 0x70 - -glabel gAudioSfxSwapSource - .space 0x18 - -glabel gAudioSfxSwapTarget - .space 0x18 - -glabel gAudioSfxSwapMode - .space 0x10 - -glabel D_8016E320 - .space 0x28 - -glabel D_8016E348 - .space 0x8 - -glabel sAudioSeqCmds - .space 0x400 - -glabel D_8016E750 - .space 0x990 - -glabel D_8016F0E0 # unused? - .space 0xA0 - -glabel gAudioContext - .space 0x6450 - -glabel D_801755D0 - .space 0x20 diff --git a/data/code_800F9280.data.s b/data/code_800F9280.data.s deleted file mode 100644 index a55ab4d8aa..0000000000 --- a/data/code_800F9280.data.s +++ /dev/null @@ -1,104 +0,0 @@ -.include "macro.inc" - -# assembler directives -.set noat # allow manual use of $at -.set noreorder # don't insert nops after branches -.set gp=64 # allow use of 64-bit general purpose registers - -.section .data - -.balign 16 - -glabel sSeqCmdWrPos - .incbin "baserom.z64", 0xBAA5A0, 0x4 - -glabel sSeqCmdRdPos - .incbin "baserom.z64", 0xBAA5A4, 0x4 - -glabel D_80133408 - .incbin "baserom.z64", 0xBAA5A8, 0x4 - -glabel D_8013340C - .incbin "baserom.z64", 0xBAA5AC, 0x4 - -glabel D_80133410 - .incbin "baserom.z64", 0xBAA5B0, 0x4 - -glabel gAudioSpecId - .incbin "baserom.z64", 0xBAA5B4, 0x4 - -glabel D_80133418 - .incbin "baserom.z64", 0xBAA5B8, 0x8 - -glabel D_80133420 - .incbin "baserom.z64", 0xBAA5C0, 0x48 - -glabel D_80133468 - .incbin "baserom.z64", 0xBAA608, 0x48 - -glabel D_801334B0 - .incbin "baserom.z64", 0xBAA650, 0x90 - -glabel D_80133540 - .incbin "baserom.z64", 0xBAA6E0, 0x48 - -glabel D_80133588 - .incbin "baserom.z64", 0xBAA728, 0x48 - -glabel D_801335D0 - .incbin "baserom.z64", 0xBAA770, 0x48 - -glabel D_80133618 - .incbin "baserom.z64", 0xBAA7B8, 0x48 - -glabel D_80133660 - .incbin "baserom.z64", 0xBAA800, 0x48 - -glabel D_801336A8 - .incbin "baserom.z64", 0xBAA848, 0x48 - -glabel D_801336F0 - .incbin "baserom.z64", 0xBAA890, 0x48 - -glabel D_80133738 - .incbin "baserom.z64", 0xBAA8D8, 0x90 - -glabel gAudioSpecs - .incbin "baserom.z64", 0xBAA968, 0xC - .word D_80133420 - .incbin "baserom.z64", 0xBAA978, 0x34 - .word D_80133468 - .incbin "baserom.z64", 0xBAA9B0, 0x34 - .word D_801334B0 - .incbin "baserom.z64", 0xBAA9E8, 0x34 - .word D_80133540 - .incbin "baserom.z64", 0xBAAA20, 0x34 - .word D_80133588 - .incbin "baserom.z64", 0xBAAA58, 0x34 - .word D_801335D0 - .incbin "baserom.z64", 0xBAAA90, 0x34 - .word D_80133618 - .incbin "baserom.z64", 0xBAAAC8, 0x34 - .word D_80133660 - .incbin "baserom.z64", 0xBAAB00, 0x34 - .word D_801336A8 - .incbin "baserom.z64", 0xBAAB38, 0x34 - .word D_80133660 - .incbin "baserom.z64", 0xBAAB70, 0x34 - .word D_801336F0 - .incbin "baserom.z64", 0xBAABA8, 0x34 - .word D_80133738 - .incbin "baserom.z64", 0xBAABE0, 0x34 - .word D_80133738 - .incbin "baserom.z64", 0xBAAC18, 0x34 - .word D_80133420 - .incbin "baserom.z64", 0xBAAC50, 0x34 - .word D_80133660 - .incbin "baserom.z64", 0xBAAC88, 0x34 - .word D_80133420 - .incbin "baserom.z64", 0xBAACC0, 0x34 - .word D_80133420 - .incbin "baserom.z64", 0xBAACF8, 0x34 - .word D_801334B0 - .incbin "baserom.z64", 0xBAAD30, 0x30 - \ No newline at end of file diff --git a/data/fault.bss.s b/data/fault.bss.s index bda55d9b97..b66f9cf837 100644 --- a/data/fault.bss.s +++ b/data/fault.bss.s @@ -9,10 +9,10 @@ .balign 16 -glabel sFaultStructPtr +glabel sFaultInstance .space 4 -glabel sFaultIsWaitingForInput +glabel sFaultAwaitingInput .space 4 glabel sFaultStack @@ -21,5 +21,5 @@ glabel sFaultStack glabel sFaultThreadInfo .space 0x20 -glabel gFaultStruct +glabel gFaultMgr .space 0x850 diff --git a/docs/BUILDING_BINUTILS_MACOS.md b/docs/BUILDING_BINUTILS_MACOS.md deleted file mode 100644 index c03a1b909b..0000000000 --- a/docs/BUILDING_BINUTILS_MACOS.md +++ /dev/null @@ -1,47 +0,0 @@ -# Building mips-linux-binutils on MacOS - -The following instructions are written for MacOS users but should apply to any unix-like system, with maybe some modifications at the end regarding the bash_profile. - -Create destination dir for binutils -```bash -sudo mkdir -p /opt/cross -``` - -Create and enter local working dir -```bash -mkdir ~/binutils-tmp -cd ~/binutils-tmp -``` - -Get and extract binutils source -```bash -wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.bz2 -tar xjf binutils-2.35.tar.bz2 -``` - -Create and enter build dir -```bash -mkdir build-binutils -cd build-binutils -``` - -Configure the build -```bash -../binutils-2.35/configure --target=mips-linux-gnu --prefix=/opt/cross --disable-gprof --disable-gdb --disable-werror -``` - -Make and install binutils -```bash -make -j -sudo make install -``` - -Edit your ~/.bash_profile to add the new binutils binaries to the system PATH -```bash -echo "export PATH=$PATH:/opt/cross/bin" >> ~/.bash_profile -``` - -Reload ~/.bash_profile (or just launch a new terminal tab) -```bash -source ~/.bash_profile -``` diff --git a/docs/BUILDING_BINUTILS_CYGWIN.md b/docs/BUILDING_CYGWIN.md similarity index 52% rename from docs/BUILDING_BINUTILS_CYGWIN.md rename to docs/BUILDING_CYGWIN.md index 31fbdfe6c5..a673bdd73b 100644 --- a/docs/BUILDING_BINUTILS_CYGWIN.md +++ b/docs/BUILDING_CYGWIN.md @@ -1,4 +1,17 @@ -# Building mips-linux-binutils on Windows using Cygwin +# Building with Cygwin + +**N.B.** These have not been tested recently, you may find the requirements have changed a bit. + +If you want to use Cygwin, you will need to: + + +## 1. Install Git Bash and Cygwin + +* Download and install [Git Bash](https://git-scm.com/download/win). +* Download and install [Cygwin](https://cygwin.com). + + +## 2. Build mips-linux-binutils on Windows using Cygwin First, you will need to install the following packages using the Cygwin installer: - make @@ -40,3 +53,34 @@ Add the new binutils binaries to your system PATH: You can do that by adding `PATH=$PATH:/opt/cross/bin` to `~/.bashrc` and then reloading `~/.bashrc`. Alternatively you can edit the `Path` variable in `Edit the system environment variables`>`Environment Variables` (in which case you will need to relaunch your terminal). + + +## 3. Install required Cygwin packages + +Once mips-linux-binutils is installed you will need to install the following packages using Cygwin's installer: + +* libiconv +* dos2unix +* python3 +* libpng-devel + + +## 4. Install required Python packages + +To install the Python dependencies simply run in a terminal: + +```bash +python3 -m pip install colorama +``` + + +## 5. Continue with Linux instructions + +You should be able to continue from step [step 2](../README.md#2-clone-the-repository) of the Linux instructions. + +**N.B.** Before building anything, you will need to run the following commands to fix line endings: + +```bash +dos2unix fixle.sh +./fixle.sh +``` diff --git a/docs/BUILDING_DOCKER.md b/docs/BUILDING_DOCKER.md new file mode 100644 index 0000000000..afc35b48bc --- /dev/null +++ b/docs/BUILDING_DOCKER.md @@ -0,0 +1,27 @@ +# Building using Docker + +## 1. Setup requirements + +To use Docker, you'll need either Docker Desktop or Docker Toolbox installed and setup based on your system. + +You'll also need to prepare a local version of the project with a copied base ROM (see steps [2](../README.md#2-clone-the-repository) and [3](../README.md#3-prepare-a-base-rom) of the Linux instructions). + +## 2. Create the Docker image + +From inside your local project, run the following command: + +```bash +docker build . -t oot +``` + +## 3. Start the container + +To start the container, you can mount your local filesystem into the Docker container and run an interactive bash session. + +```bash +docker run -it --rm --mount type=bind,source="$(pwd)",destination=/oot oot /bin/bash +``` + +## 4. Setup and Build the ROM + +Once inside the container, you can follow steps [4](../README.md#4-setup-the-rom-and-build-process) and [5](../README.md#5-build-the-rom) of the Linux instructions to setup and build the ROM, or run any other command you need. diff --git a/docs/BUILDING_MACOS.md b/docs/BUILDING_MACOS.md new file mode 100644 index 0000000000..a5668eeea7 --- /dev/null +++ b/docs/BUILDING_MACOS.md @@ -0,0 +1,89 @@ +# Building on macOS + +**N.B.** C++17 is required to build the asset processing program that we use (ZAPD), so check your OS version can support this before proceeding. + + +## 1. Dependencies + +For macOS, use Homebrew to install the following dependencies: + +* coreutils +* make +* python3 +* libpng +* bash +* clang-format + +You can install them with the following commands: + +```bash +brew update +brew install coreutils make python3 libpng bash clang-format +``` + +(The repository expects Homebrew-installed programs to be either linked correctly in `$PATH` etc. or in their default locations.) + +To install the Python dependencies simply run in a terminal: + +```bash +python3 -m pip install colorama +``` + + +## 2. Building mips-linux-binutils + +The following instructions are written for MacOS users but should apply to any Unix-like system, with maybe some modifications at the end regarding the bash_profile. + +Create destination dir for binutils +```bash +sudo mkdir -p /opt/cross +``` + +Create and enter local working dir +```bash +mkdir ~/binutils-tmp +cd ~/binutils-tmp +``` + +Get and extract binutils source +```bash +wget https://ftp.gnu.org/gnu/binutils/binutils-2.35.tar.bz2 +tar xjf binutils-2.35.tar.bz2 +``` +(You may find this command does not work: if so, just access the URL in a browser and save it to `~/binutils-tmp`.) + +Create and enter a build directory +```bash +mkdir build-binutils +cd build-binutils +``` + +Configure the build +```bash +../binutils-2.35/configure --target=mips-linux-gnu --prefix=/opt/cross --disable-gprof --disable-gdb --disable-werror +``` + +Make and install binutils +```bash +make -j +sudo make install +``` + +Edit your `~/.bash_profile`/`~/.zsh_profile` (or whichever shell you use) to add the new binutils binaries to the system PATH +```bash +echo "export PATH=$PATH:/opt/cross/bin" >> ~/.bash_profile +``` + +Reload `~/.bash_profile` (or just launch a new terminal tab) +```bash +source ~/.bash_profile +``` + +If this worked, you can now delete the temporary directory `~/binutils-tmp`. + + +## 3. Final note + +Apple's version of `make` is very out-of-date, so you should use the brew-installed `gmake` in place of `make` in this repo from now on. + +You should now be able to continue from [step 2](../README.md#2-clone-the-repository) of the Linux instructions. diff --git a/docs/Documenting.md b/docs/Documenting.md index f8b3566499..03a12ebbd4 100644 --- a/docs/Documenting.md +++ b/docs/Documenting.md @@ -4,9 +4,9 @@ This project uses [Doxygen](https://www.doxygen.nl/index.html) to generate documentation pages from comments found in the source files. This guide focuses on writing compatible comments and ensuring consistency across the codebase. ```diff - Note - -As the codebase is constantly changing, only document what is complete, well-understood and not +As the codebase is constantly changing, only document what is complete, well-understood and not already covered by good naming. This is especially true for function parameters and return values. -Also note that there is no obligation to completing the documentation steps for functions you +Also note that there is no obligation to completing the documentation steps for functions you work on if you do not want to at the time. ``` To generate a doxygen manual for the project, ensure you have doxygen installed and then cd into the project root directory and run `doxygen Doxyfile`. @@ -97,4 +97,4 @@ For centered rendering on a separate line: /** * \f[ \textrm{Your LaTeX Here} \f] */ -``` \ No newline at end of file +``` diff --git a/docs/tutorial/beginning_decomp.md b/docs/tutorial/beginning_decomp.md index 9c5aa45f17..c9421ffd30 100644 --- a/docs/tutorial/beginning_decomp.md +++ b/docs/tutorial/beginning_decomp.md @@ -60,8 +60,8 @@ The above is a rough ordering for the beginner. As you become more experienced, Associated to each actor is a `.data` file, containing data that the actor uses. This ranges from spawn positions, to display lists, to even some cutscene data. Since the structure of the data is very inconsistent between actors, automatic importing has been very limited, so the vast majority must be done manually. -There are two ways of transfering the data into an actor: we can either -- import it all naively as words (`s32`s), which will still allow it to compile, and sort out the actual types later, or +There are two ways of transfering the data into an actor: we can either +- import it all naively as words (`s32`s), which will still allow it to compile, and sort out the actual types later, or - we can extern each piece of data as we come across it, and come back to it later when we have a better idea of what it is. We will concentrate on the second here; the other is covered in [the document about data](data.md). Thankfully this means we essentially don't have to do anything to the data yet. Nevertheless, it is often quite helpful to copy over at least some of the data and leave it commented out for later replacement. *Data must go in the same order as in the data file, and data is "all or nothing": you cannot only import some of it*. @@ -93,7 +93,7 @@ from the main directory of the repository. In this case, the C file is `src/over ![Copying the context](images/ctx.png) -Now, open the file containing the assembly for `EnJj_Init`. +Now, open the file containing the assembly for `EnJj_Init`. ![Copying the Init asm](images/init_asm.png) @@ -117,7 +117,7 @@ void EnJj_Init(EnJj *this, GlobalContext *globalCtx) { ActorShape_Init(&this->actor.shape, 0.0f, NULL, 0.0f); temp_v0 = this->actor.params; temp_a1 = this + 0x164; - [...] + [...] ``` Typically for all buth the simplest functions, there is a lot that needs fixing before we are anywhere near seeing how close we are to the original code. You will notice that mips2c creates a lot of temporary variables. Usually most of these will turn out to not be real, and we need to remove the right ones to get the code to match. @@ -217,7 +217,7 @@ void EnJj_Init(Actor *thisx, GlobalContext *globalCtx) { In the next sections, we shall sort out the various initialisation functions that occur in Init. There are several types, and one of the reasons we are using EnJj as the example is that it has several of the most common ones. A disadvantage of this actor is that it has an unusually complicated Init: we can see that it does three different things depending on the value of its params. ### Init chains - + Almost always, one of the first items in `Init` is a function that looks like ```C @@ -324,7 +324,7 @@ this->dyna.bgId = DynaPoly_SetBgActor(globalCtx, &globalCtx->colCtx.dyna, &this- Next, replace `(DynaPolyActor *) this` by `&this->dyna`. There's not a lot more we can do to the DynaPoly stuff right now, so just remove the casts to void and move on. ### Colliders - + The next common thing that actors have is colliders. Not every actor has these, but most do, even if they don't just use them for collision system purposes. The relevant functions in this actor are @@ -355,7 +355,7 @@ Collider_SetCylinder(globalCtx, &this->collider, &this->dyna.actor, &D_80A88CB4) (You may prefer to just comment out temps initially, to keep track of where they were.) -The last thing we need to deal with is the last variable of `Collider_SetCylinder`, which is again data. +The last thing we need to deal with is the last variable of `Collider_SetCylinder`, which is again data. + +Contains +- **Fairy** a library for reading N64 ELF files (big-endian) +- **Fado** a program for generating the `.ovl`/relocation section for Zelda64 overlay files + +Compatible with both IDO and GCC. + +Format is the standard .ovl section, with the relocs divided by section. It will also print the name the associated variable if it can find it in the ELF (for IDO, this is only if it is not static, whereas GCC sometimes seems to retain all of them). diff --git a/tools/fado/find_program.sh b/tools/fado/find_program.sh new file mode 100755 index 0000000000..755b94c584 --- /dev/null +++ b/tools/fado/find_program.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +for i in "${@:2}" + do + RESULT=$(IFS=:;find $PATH -maxdepth 1 -name "$i" -print -quit 2> /dev/null | grep -o '[^/]*$') + COUNT=$(echo "$RESULT" | wc -c) + + if [ $COUNT -gt 1 ] + then + echo $RESULT + exit 0 + fi + done + +echo $1 +exit 0 diff --git a/tools/fado/include/fado.h b/tools/fado/include/fado.h new file mode 100644 index 0000000000..6044d0a245 --- /dev/null +++ b/tools/fado/include/fado.h @@ -0,0 +1,8 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include + +void Fado_Relocs(FILE* outputFile, int inputFilesCount, FILE** inputFiles, const char* ovlName); +// void Fado_WriteRelocFile(FILE* outputFile, FILE** inputFiles, int inputFilesCount); diff --git a/tools/fado/include/help.h b/tools/fado/include/help.h new file mode 100644 index 0000000000..e005262794 --- /dev/null +++ b/tools/fado/include/help.h @@ -0,0 +1,24 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include +#include + +typedef struct { + struct option longOpt; + char* helpArg; + char* helpMsg; +} OptInfo; + +typedef struct { + char* helpArg; + char* helpMsg; +} PosArgInfo; + +/* Formatting sizes used by Help_PrintHelp. Change them before calling Help_PrintHelp to use custom values */ +extern size_t helpTextWidth; +extern size_t helpDtIndent; +extern size_t helpDdIndent; + +void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo* posArgInfo, size_t optCount, const OptInfo* optInfo, const char* epilogue); diff --git a/tools/fado/include/macros.h b/tools/fado/include/macros.h new file mode 100644 index 0000000000..9d3731080d --- /dev/null +++ b/tools/fado/include/macros.h @@ -0,0 +1,21 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include "vc_vector/vc_vector.h" + +/* C macros */ +#define ARRAY_COUNT(arr) (signed long long)(sizeof(arr) / sizeof(arr[0])) +#define ARRAY_COUNTU(arr) (unsigned long long)(sizeof(arr) / sizeof(arr[0])) + +/* Mathematical macros */ +#define ABS(x) ((x) < 0 ? -(x) : (x)) + +#define CLAMP(x, min, max) ((x) < (min) ? (min) : (x) > (max) ? (max) : (x)) +#define CLAMP_MAX(x, max) ((x) > (max) ? (max) : (x)) +#define CLAMP_MIN(x, min) ((x) < (min) ? (min) : (x)) +#define MEDIAN3(a1, a2, a3) \ + ((a2 >= a1) ? ((a3 >= a2) ? a2 : ((a1 >= a3) ? a1 : a3)) : ((a2 >= a3) ? a2 : ((a3 >= a1) ? a1 : a3))) + +/* vc_vector macros - really these should go in vc_vector.h, but not much choice without touching the library files */ +#define VC_FOREACH(i, v) for (i = vc_vector_begin(v); i != vc_vector_end(v); i = vc_vector_next(v, i)) diff --git a/tools/fado/include/mido.h b/tools/fado/include/mido.h new file mode 100644 index 0000000000..b40d8a4c30 --- /dev/null +++ b/tools/fado/include/mido.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include "vc_vector/vc_vector.h" + +int Mido_WriteDependencyFile(FILE* dependencyFile, const char* relocFile, vc_vector* inputFilesVector); diff --git a/tools/fado/lib/fairy/fairy.c b/tools/fado/lib/fairy/fairy.c new file mode 100644 index 0000000000..90bd4d1c5b --- /dev/null +++ b/tools/fado/lib/fairy/fairy.c @@ -0,0 +1,330 @@ +/** + * Functions for working with N64 ELF files. + * For now relies on (GNU) elf.h, but may move away from this in future. + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fairy.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "vc_vector/vc_vector.h" + +VerbosityLevel gVerbosity = VERBOSITY_NONE; + +int Fairy_DebugPrintf(const char* file, int line, const char* func,VerbosityLevel level, const char* fmt, ...) { + if (gVerbosity >= level) { + int ret = 0; + va_list args; + va_start(args, fmt); + + if (gVerbosity >= VERBOSITY_DEBUG) { + ret += fprintf(stderr, "%s:%d:%s: ", file, line, func); + } + + ret += vfprintf(stderr, fmt, args); + va_end(args); + return ret; + } + return 0; +} + +/* Endian readers. MIPS is BE, so only need these */ +static Elf32_Half Fairy_ReadHalf(const uint8_t* data) { + return data[0] << 8 | data[1] << 0; +} + +static Elf32_Word Fairy_ReadWord(const uint8_t* data) { + return data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3] << 0; +} + +static bool Fairy_VerifyMagic(const uint8_t* data) { + return (data[0] == 0x7F && data[1] == 'E' && data[2] == 'L' && data[3] == 'F'); +} + +static uint16_t Fairy_Swap16(uint16_t x) { + return ((x & 0xFF) << 0x8) | ((x & 0xFF00) >> 0x8); +} + +static uint32_t Fairy_Swap32(uint32_t x) { + return ((x & 0xFF) << 0x18) | ((x & 0xFF00) << 0x8) | ((x & 0xFF0000) >> 0x8) | ((x & 0xFF000000) >> 0x18); +} + +/* "Re-encode/Re-endianise", i.e. byteswap if required */ +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define REEND16(x) Fairy_Swap16(x) +#define REEND32(x) Fairy_Swap32(x) +#else +#define REEND16(x) (x) +#define REEND32(x) (x) +#endif + +const char* Fairy_StringFromDefine(const FairyDefineString* dict, int define) { + size_t i; + for (i = 0; dict[i].string != NULL; i++) { + if (dict[i].define == define) { + return dict[i].string; + } + } + return NULL; +} + +/** + * Returns true if the string 'initial' is contained in the string 'string' + * 'initial' must be null-terminated, 'string' ideally is. + */ +bool Fairy_StartsWith(const char* string, const char* initial) { + char s; + char i; + do { + s = *string++; + i = *initial++; + if (i == '\0') { + return true; + } + } while (s == i); + return false; +} + +/* Reading functions */ + +/** + * Every reading function: + * - Returns the pointer to the struct + * - Takes the ouput struct or array as its first argument. This must be pre-allocated + * - Takes the input file as the second argument (At least until I am persuaded to read the whole file into RAM...) + * - The rest of the arguments are important information about the struct it is reading (offset and size, usually) + */ + +FairyFileHeader* Fairy_ReadFileHeader(FairyFileHeader* header, FILE* file) { + fseek(file, 0, SEEK_SET); + assert(fread(header, 0x34, 1, file) != 0); + + if (!Fairy_VerifyMagic(header->e_ident)) { + fprintf(stderr, "Not a valid ELF file\n"); + return NULL; + } + + if (header->e_ident[EI_CLASS] != ELFCLASS32) { + fprintf(stderr, "Not a 32-bit ELF file\n"); + return NULL; + } + + header->e_type = REEND16(header->e_type); + header->e_machine = REEND16(header->e_machine); + header->e_version = REEND32(header->e_version); + header->e_entry = REEND32(header->e_entry); + header->e_phoff = REEND32(header->e_phoff); + header->e_shoff = REEND32(header->e_shoff); + header->e_flags = REEND32(header->e_flags); + header->e_ehsize = REEND16(header->e_ehsize); + header->e_phentsize = REEND16(header->e_phentsize); + header->e_phnum = REEND16(header->e_phnum); + header->e_shentsize = REEND16(header->e_shentsize); + header->e_shnum = REEND16(header->e_shnum); + header->e_shstrndx = REEND16(header->e_shstrndx); + + return header; +} + +/* tableOffset and number should be obtained from the file header */ +FairySecHeader* Fairy_ReadSectionTable(FairySecHeader* sectionTable, FILE* file, size_t tableOffset, size_t number) { + size_t entrySize = sizeof(FairySecHeader); + size_t tableSize = number * entrySize; + + fseek(file, tableOffset, SEEK_SET); + assert(fread(sectionTable, tableSize, 1, file) != 0); + + /* Since the section table happens to only have entries of width 4, we can byteswap it by pretending it is a raw + * uint32_t array */ + { + size_t i; + uint32_t* data = (uint32_t*)sectionTable; + for (i = 0; i < tableSize / sizeof(uint32_t); i++) { + data[i] = REEND32(data[i]); + } + } + + return sectionTable; +} + +FairySym* Fairy_ReadSymbolTable(FairySym* symbolTable, FILE* file, size_t tableOffset, size_t tableSize) { + size_t number = tableSize / sizeof(FairySym); + + fseek(file, tableOffset, SEEK_SET); + assert(fread(symbolTable, tableSize, 1, file) != 0); + + /* Reend the variables that are larger than bytes */ + { + size_t i; + for (i = 0; i < number; i++) { + symbolTable[i].st_name = REEND32(symbolTable[i].st_name); + symbolTable[i].st_value = REEND32(symbolTable[i].st_value); + symbolTable[i].st_size = REEND32(symbolTable[i].st_size); + symbolTable[i].st_shndx = REEND16(symbolTable[i].st_shndx); + } + } + + return symbolTable; +} + +/* Can be used for both the section header string table and the strtab */ +char* Fairy_ReadStringTable(char* stringTable, FILE* file, size_t tableOffset, size_t tableSize) { + fseek(file, tableOffset, SEEK_SET); + assert(fread(stringTable, tableSize, 1, file) != 0); + return stringTable; +} + +/* offset and number are attained from the section table */ +FairyRel* Fairy_ReadRelocs(FairyRel* relocTable, FILE* file, size_t offset, size_t size) { + fseek(file, offset, SEEK_SET); + assert(fread(relocTable, size, 1, file) != 0); + + /* Reend the variables that are larger than bytes */ + { + size_t i; + uint32_t* data = (uint32_t*)relocTable; + for (i = 0; i < size / sizeof(uint32_t); i++) { + data[i] = REEND32(data[i]); + } + } + + return relocTable; +} + +char* Fairy_GetSectionName(FairySecHeader* sectionTable, char* shstrtab, size_t index) { + return &shstrtab[sectionTable[index].sh_name]; +} + +/* Look up the index in the symbol table and return a pointer to the beginning of its string */ +char* Fairy_GetSymbolName(FairySym* symtab, char* strtab, size_t index) { + return &strtab[symtab[index].st_name]; +} + +/* FairyFileInfo functions */ + +void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + char* shstrtab; + int i; + + assert(fileInfo != NULL); + assert(file != NULL); + + fileInfo->progBitsSections = vc_vector_create(3, sizeof(Elf32_Section), NULL); + for (i = 0; i < 3; i++) { + fileInfo->progBitsSizes[i] = 0; + } + Fairy_ReadFileHeader(&fileHeader, file); + + sectionTable = malloc(fileHeader.e_shnum * fileHeader.e_shentsize); + Fairy_ReadSectionTable(sectionTable, file, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[fileHeader.e_shstrndx].sh_size * sizeof(char)); + fseek(file, sectionTable[fileHeader.e_shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sectionTable[fileHeader.e_shstrndx].sh_size, 1, file) != 0); + + /* Search for the sections we need */ + { + size_t currentIndex; + FairySecHeader currentSection; + for (currentIndex = 0; currentIndex < 3; currentIndex++) { + fileInfo->relocTablesInfo[currentIndex].sectionData = NULL; + } + + for (currentIndex = 0; currentIndex < fileHeader.e_shnum; currentIndex++) { + currentSection = sectionTable[currentIndex]; + + switch (currentSection.sh_type) { + case SHT_PROGBITS: + assert(vc_vector_push_back(fileInfo->progBitsSections, ¤tIndex)); + if (strcmp(&shstrtab[currentSection.sh_name + 1], "text") == 0) { + fileInfo->progBitsSizes[FAIRY_SECTION_TEXT] += currentSection.sh_size; + FAIRY_DEBUG_PRINTF("text section size: 0x%X\n", fileInfo->progBitsSizes[FAIRY_SECTION_TEXT]); + } else if (strcmp(&shstrtab[currentSection.sh_name + 1], "data") == 0) { + fileInfo->progBitsSizes[FAIRY_SECTION_DATA] += currentSection.sh_size; + FAIRY_DEBUG_PRINTF("data section size: 0x%X\n", fileInfo->progBitsSizes[FAIRY_SECTION_DATA]); + } else if (Fairy_StartsWith(&shstrtab[currentSection.sh_name + 1], "rodata")) { /* May be several */ + fileInfo->progBitsSizes[FAIRY_SECTION_RODATA] += currentSection.sh_size; + FAIRY_DEBUG_PRINTF("rodata section size: 0x%X\n", fileInfo->progBitsSizes[FAIRY_SECTION_RODATA]); + } + break; + + case SHT_SYMTAB: + if (strcmp(&shstrtab[currentSection.sh_name + 1], "symtab") == 0) { + fileInfo->symtabInfo.sectionSize = currentSection.sh_size; + fileInfo->symtabInfo.sectionData = malloc(currentSection.sh_size); + Fairy_ReadSymbolTable(fileInfo->symtabInfo.sectionData, file, currentSection.sh_offset, + currentSection.sh_size); + } + break; + + case SHT_STRTAB: + if (strcmp(&shstrtab[currentSection.sh_name + 1], "strtab") == 0) { + FAIRY_DEBUG_PRINTF("%s", "strtab found\n"); + fileInfo->strtab = malloc(currentSection.sh_size); + Fairy_ReadStringTable(fileInfo->strtab, file, currentSection.sh_offset, currentSection.sh_size); + } + break; + + case SHT_REL: + /* This assumes only one reloc section of each name */ + // TODO: is this a problem? + { + FairySection relocSection = FAIRY_SECTION_OTHER; + + if (strcmp(&shstrtab[currentSection.sh_name + 5], "text") == 0) { + relocSection = FAIRY_SECTION_TEXT; + FAIRY_DEBUG_PRINTF("%s", "Found rel.text section\n"); + } else if (strcmp(&shstrtab[currentSection.sh_name + 5], "data") == 0) { + relocSection = FAIRY_SECTION_DATA; + FAIRY_DEBUG_PRINTF("%s", "Found rel.data section\n"); + } else if (strcmp(&shstrtab[currentSection.sh_name + 5], "rodata") == 0) { + relocSection = FAIRY_SECTION_RODATA; + FAIRY_DEBUG_PRINTF("%s", "Found rel.rodata section\n"); + } else { + break; + } + + fileInfo->relocTablesInfo[relocSection].sectionSize = currentSection.sh_size; + fileInfo->relocTablesInfo[relocSection].sectionData = malloc(currentSection.sh_size); + Fairy_ReadRelocs(fileInfo->relocTablesInfo[relocSection].sectionData, file, + currentSection.sh_offset, currentSection.sh_size); + } + break; + + default: + break; + } + } + } + + free(sectionTable); + free(shstrtab); +} + +void Fairy_DestroyFile(FairyFileInfo* fileInfo) { + size_t i; + for (i = 0; i < 3; i++) { + if (fileInfo->relocTablesInfo[i].sectionData != NULL) { + FAIRY_DEBUG_PRINTF("Freeing reloc section %zd data\n", i); + free(fileInfo->relocTablesInfo[i].sectionData); + } + } + + vc_vector_release(fileInfo->progBitsSections); + + FAIRY_DEBUG_PRINTF("%s","Freeing symtab data\n"); + free(fileInfo->symtabInfo.sectionData); + + FAIRY_DEBUG_PRINTF("%s", "Freeing strtab data\n"); + free(fileInfo->strtab); +} diff --git a/tools/fado/lib/fairy/fairy.h b/tools/fado/lib/fairy/fairy.h new file mode 100644 index 0000000000..573ca61290 --- /dev/null +++ b/tools/fado/lib/fairy/fairy.h @@ -0,0 +1,70 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#pragma once + +#include +#include +#include + +#include "vc_vector/vc_vector.h" + +#define FAIRY_DEF_STRING(prefix, x) \ + { prefix##x, #x } + +typedef enum { + VERBOSITY_NONE, + VERBOSITY_INFO, + VERBOSITY_DEBUG //, +} VerbosityLevel; + +extern VerbosityLevel gVerbosity; + +typedef Elf32_Ehdr FairyFileHeader; +typedef Elf32_Shdr FairySecHeader; +typedef Elf32_Sym FairySym; +typedef Elf32_Rel FairyRel; + +typedef struct { + int define; + const char* string; +} FairyDefineString; + +typedef struct { + void* sectionData; + size_t sectionSize; +} FairySectionInfo; + +typedef struct { + FairySectionInfo symtabInfo; + char* strtab; + Elf32_Word progBitsSizes[3]; + vc_vector* progBitsSections; + FairySectionInfo relocTablesInfo[3]; +} FairyFileInfo; + +typedef enum { + FAIRY_SECTION_TEXT, + FAIRY_SECTION_DATA, + FAIRY_SECTION_RODATA, + FAIRY_SECTION_OTHER //, +} FairySection; + +/* Prints debugging information to stderr. To be used via the macros. */ +int Fairy_DebugPrintf(const char* file, int line, const char* func, VerbosityLevel level, const char* fmt, ...); +#define FAIRY_INFO_PRINTF(fmt, ...) Fairy_DebugPrintf(__FILE__, __LINE__, __func__, VERBOSITY_INFO, fmt, __VA_ARGS__) +#define FAIRY_DEBUG_PRINTF(fmt, ...) Fairy_DebugPrintf(__FILE__, __LINE__, __func__, VERBOSITY_DEBUG, fmt, __VA_ARGS__) + +const char* Fairy_StringFromDefine(const FairyDefineString* dict, int define); +bool Fairy_StartsWith(const char* string, const char* initial); + +FairyFileHeader* Fairy_ReadFileHeader(FairyFileHeader* header, FILE* file); +FairySecHeader* Fairy_ReadSectionTable(FairySecHeader* sectionTable, FILE* file, size_t tableOffset, size_t number); +FairySym* Fairy_ReadSymbolTable(FairySym* symbolTable, FILE* file, size_t tableOffset, size_t tableSize); +char* Fairy_ReadStringTable(char* stringTable, FILE* file, size_t tableOffset, size_t tableSize); +FairyRel* Fairy_ReadRelocs(FairyRel* relocTable, FILE* file, size_t offset, size_t number); + +char* Fairy_GetSectionName(FairySecHeader* sectionTable, char* shstrtab, size_t index); +char* Fairy_GetSymbolName(FairySym* symtab, char* strtab, size_t index); + +void Fairy_InitFile(FairyFileInfo* fileInfo, FILE* file); +void Fairy_DestroyFile(FairyFileInfo* fileInfo); diff --git a/tools/fado/lib/fairy/fairy_data.inc b/tools/fado/lib/fairy/fairy_data.inc new file mode 100644 index 0000000000..b4e29ceb09 --- /dev/null +++ b/tools/fado/lib/fairy/fairy_data.inc @@ -0,0 +1,126 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fairy.h" +#include + +// clang-format off +static const FairyDefineString stTypes[] = { + FAIRY_DEF_STRING(STT_, NOTYPE), + FAIRY_DEF_STRING(STT_, OBJECT), + FAIRY_DEF_STRING(STT_, FUNC), + FAIRY_DEF_STRING(STT_, SECTION), + FAIRY_DEF_STRING(STT_, FILE), + FAIRY_DEF_STRING(STT_, COMMON), + FAIRY_DEF_STRING(STT_, TLS), + FAIRY_DEF_STRING(STT_, NUM), + FAIRY_DEF_STRING(STT_, LOOS), + FAIRY_DEF_STRING(STT_, GNU_IFUNC), + FAIRY_DEF_STRING(STT_, HIOS), + FAIRY_DEF_STRING(STT_, LOPROC), + FAIRY_DEF_STRING(STT_, HIPROC), + { 0 }, +}; + +static const FairyDefineString stBinds[] = { + FAIRY_DEF_STRING(STB_, LOCAL), + FAIRY_DEF_STRING(STB_, GLOBAL), + FAIRY_DEF_STRING(STB_, WEAK), + FAIRY_DEF_STRING(STB_, NUM), + FAIRY_DEF_STRING(STB_, LOOS), + FAIRY_DEF_STRING(STB_, GNU_UNIQUE), + FAIRY_DEF_STRING(STB_, HIOS), + FAIRY_DEF_STRING(STB_, LOPROC), + FAIRY_DEF_STRING(STB_, HIPROC), + { 0 }, +}; + +static const FairyDefineString stVisibilities[] = { + FAIRY_DEF_STRING(STV_, DEFAULT), + FAIRY_DEF_STRING(STV_, INTERNAL), + FAIRY_DEF_STRING(STV_, HIDDEN), + FAIRY_DEF_STRING(STV_, PROTECTED), + { 0 }, +}; + +/* TODO: understand this data better: there are several cases with the same number */ +static const FairyDefineString shTypes[] = { + FAIRY_DEF_STRING(SHT_, NULL), + FAIRY_DEF_STRING(SHT_, PROGBITS), + FAIRY_DEF_STRING(SHT_, SYMTAB), + FAIRY_DEF_STRING(SHT_, STRTAB), + FAIRY_DEF_STRING(SHT_, RELA), + FAIRY_DEF_STRING(SHT_, HASH), + FAIRY_DEF_STRING(SHT_, DYNAMIC), + FAIRY_DEF_STRING(SHT_, NOTE), + FAIRY_DEF_STRING(SHT_, NOBITS), + FAIRY_DEF_STRING(SHT_, REL), + FAIRY_DEF_STRING(SHT_, SHLIB), + FAIRY_DEF_STRING(SHT_, DYNSYM), + FAIRY_DEF_STRING(SHT_, INIT_ARRAY), + FAIRY_DEF_STRING(SHT_, FINI_ARRAY), + FAIRY_DEF_STRING(SHT_, PREINIT_ARRAY), + FAIRY_DEF_STRING(SHT_, GROUP), + FAIRY_DEF_STRING(SHT_, SYMTAB_SHNDX), + FAIRY_DEF_STRING(SHT_, NUM), + FAIRY_DEF_STRING(SHT_, LOOS), + FAIRY_DEF_STRING(SHT_, GNU_ATTRIBUTES), + FAIRY_DEF_STRING(SHT_, GNU_HASH), + FAIRY_DEF_STRING(SHT_, GNU_LIBLIST), + FAIRY_DEF_STRING(SHT_, CHECKSUM), + FAIRY_DEF_STRING(SHT_, LOSUNW), + FAIRY_DEF_STRING(SHT_, SUNW_move), + FAIRY_DEF_STRING(SHT_, SUNW_COMDAT), + FAIRY_DEF_STRING(SHT_, SUNW_syminfo), + FAIRY_DEF_STRING(SHT_, GNU_verdef), + FAIRY_DEF_STRING(SHT_, GNU_verneed), + FAIRY_DEF_STRING(SHT_, GNU_versym), + FAIRY_DEF_STRING(SHT_, HISUNW), + FAIRY_DEF_STRING(SHT_, HIOS), + FAIRY_DEF_STRING(SHT_, LOPROC), + FAIRY_DEF_STRING(SHT_, HIPROC), + FAIRY_DEF_STRING(SHT_, LOUSER), + FAIRY_DEF_STRING(SHT_, HIUSER), + FAIRY_DEF_STRING(SHT_, MIPS_LIBLIST), + FAIRY_DEF_STRING(SHT_, MIPS_MSYM), + FAIRY_DEF_STRING(SHT_, MIPS_CONFLICT), + FAIRY_DEF_STRING(SHT_, MIPS_GPTAB), + FAIRY_DEF_STRING(SHT_, MIPS_UCODE), + FAIRY_DEF_STRING(SHT_, MIPS_DEBUG), + FAIRY_DEF_STRING(SHT_, MIPS_REGINFO), + FAIRY_DEF_STRING(SHT_, MIPS_PACKAGE), + FAIRY_DEF_STRING(SHT_, MIPS_PACKSYM), + FAIRY_DEF_STRING(SHT_, MIPS_RELD), + FAIRY_DEF_STRING(SHT_, MIPS_IFACE), + FAIRY_DEF_STRING(SHT_, MIPS_CONTENT), + FAIRY_DEF_STRING(SHT_, MIPS_OPTIONS), + FAIRY_DEF_STRING(SHT_, MIPS_SHDR), + FAIRY_DEF_STRING(SHT_, MIPS_FDESC), + FAIRY_DEF_STRING(SHT_, MIPS_EXTSYM), + FAIRY_DEF_STRING(SHT_, MIPS_DENSE), + FAIRY_DEF_STRING(SHT_, MIPS_PDESC), + FAIRY_DEF_STRING(SHT_, MIPS_LOCSYM), + FAIRY_DEF_STRING(SHT_, MIPS_AUXSYM), + FAIRY_DEF_STRING(SHT_, MIPS_OPTSYM), + FAIRY_DEF_STRING(SHT_, MIPS_LOCSTR), + FAIRY_DEF_STRING(SHT_, MIPS_LINE), + FAIRY_DEF_STRING(SHT_, MIPS_RFDESC), + FAIRY_DEF_STRING(SHT_, MIPS_DELTASYM), + FAIRY_DEF_STRING(SHT_, MIPS_DELTAINST), + FAIRY_DEF_STRING(SHT_, MIPS_DELTACLASS), + FAIRY_DEF_STRING(SHT_, MIPS_DWARF), + FAIRY_DEF_STRING(SHT_, MIPS_DELTADECL), + FAIRY_DEF_STRING(SHT_, MIPS_SYMBOL_LIB), + FAIRY_DEF_STRING(SHT_, MIPS_EVENTS), + FAIRY_DEF_STRING(SHT_, MIPS_TRANSLATE), + FAIRY_DEF_STRING(SHT_, MIPS_PIXIE), + FAIRY_DEF_STRING(SHT_, MIPS_XLATE), + FAIRY_DEF_STRING(SHT_, MIPS_XLATE_DEBUG), + FAIRY_DEF_STRING(SHT_, MIPS_WHIRL), + FAIRY_DEF_STRING(SHT_, MIPS_EH_REGION), + FAIRY_DEF_STRING(SHT_, MIPS_XLATE_OLD), + FAIRY_DEF_STRING(SHT_, MIPS_PDR_EXCEPTION), + // FAIRY_DEF_STRING(SHT_, MIPS_XHASH), /* New in 2019 */ + { 0 }, +}; + +// clang-format on diff --git a/tools/fado/lib/fairy/fairy_print.c b/tools/fado/lib/fairy/fairy_print.c new file mode 100644 index 0000000000..65fb7e015e --- /dev/null +++ b/tools/fado/lib/fairy/fairy_print.c @@ -0,0 +1,462 @@ +/** + * Functions for printing various sections of an N64 ELF file using the functions in Fairy, similarly to readelf + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fairy.h" + +#include +#include +#include +#include +#include +#include + +#include "fairy_data.inc" + +void Fairy_PrintSymbolTable(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + size_t shstrndx; + char* shstrtab; + FairySym* symbolTable = NULL; + size_t symbolTableNum = 0; + char* strtab = NULL; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0); + + { + size_t currentIndex; + size_t strtabndx = 0; + for (currentIndex = 0; currentIndex < fileHeader.e_shnum; currentIndex++) { + FairySecHeader currentHeader = sectionTable[currentIndex]; + + switch (currentHeader.sh_type) { + case SHT_SYMTAB: + if (strcmp(&shstrtab[currentHeader.sh_name], ".symtab") == 0) { + printf("symtab found\n"); + symbolTableNum = currentHeader.sh_size / sizeof(FairySym); + symbolTable = malloc(currentHeader.sh_size); + Fairy_ReadSymbolTable(symbolTable, inputFile, currentHeader.sh_offset, currentHeader.sh_size); + } + break; + + case SHT_STRTAB: + if (strcmp(&shstrtab[currentHeader.sh_name], ".strtab") == 0) { + strtabndx = currentIndex; + } + break; + + default: + break; + } + } + + if (symbolTable == NULL) { + puts("No symtab found."); + free(sectionTable); + return; + } + + if (strtabndx != 0) { + printf("strtab found\n"); + printf("Size: %X bytes\n", sectionTable[strtabndx].sh_size); + strtab = malloc(sectionTable[strtabndx].sh_size); + printf("and mallocked\n"); + fseek(inputFile, sectionTable[strtabndx].sh_offset, SEEK_SET); + printf("file offset sought: %X\n", sectionTable[strtabndx].sh_offset); + assert(fread(strtab, sectionTable[strtabndx].sh_size, 1, inputFile) != 0); + printf("file read\n"); + } + } + + { + size_t currentIndex; + printf("Symbol table\n"); + printf(" Num: Value Size Type Bind Vis Ndx Name\n"); + for (currentIndex = 0; currentIndex < symbolTableNum; currentIndex++) { + FairySym currentSymbol = symbolTable[currentIndex]; + printf("%4zd: ", currentIndex); + printf("%08X ", currentSymbol.st_value); + printf("%4X ", currentSymbol.st_size); + printf("%-11s ", Fairy_StringFromDefine(stTypes, ELF32_ST_TYPE(currentSymbol.st_info))); + printf("%-10s ", Fairy_StringFromDefine(stBinds, ELF32_ST_BIND(currentSymbol.st_info))); + printf("%-11s ", Fairy_StringFromDefine(stVisibilities, ELF32_ST_VISIBILITY(currentSymbol.st_other))); + + if (currentSymbol.st_shndx != 0) { + printf("%3X ", currentSymbol.st_shndx); + } else { + printf("UND "); + } + + if (strtab != NULL) { + printf("%s", &strtab[currentSymbol.st_name]); + } else { + printf("%4X ", currentSymbol.st_name); + } + putchar('\n'); + } + } + + free(sectionTable); + free(symbolTable); + if (strtab != NULL) { + free(strtab); + } +} + +void Fairy_PrintRelocs(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + FairyRel* relocs; + size_t shstrndx; + char* shstrtab; + size_t currentSection; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0); + + for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) { + if (sectionTable[currentSection].sh_type != SHT_REL) { + continue; + } + printf("Section size: %d\n", sectionTable[currentSection].sh_size); + + relocs = malloc(sectionTable[currentSection].sh_size * sizeof(char)); + + Fairy_ReadRelocs(relocs, inputFile, sectionTable[currentSection].sh_offset, + sectionTable[currentSection].sh_size); + + // fseek(inputFile, sectionTable[currentSection].sh_offset, SEEK_SET); + // assert(fread(relocs, sectionTable[currentSection].sh_size, 1, inputFile) != 0); + + printf("Relocs in section [%2zd]: %s:\n", currentSection, shstrtab + sectionTable[currentSection].sh_name); + printf("Offset Info Type Symbol\n"); + { + size_t currentReloc; + for (currentReloc = 0; currentReloc < sectionTable[currentSection].sh_size / sizeof(*relocs); + currentReloc++) { + + printf("%08X,%08X ", relocs[currentReloc].r_offset, relocs[currentReloc].r_info); + + switch (ELF32_R_TYPE(relocs[currentReloc].r_info)) { + case R_MIPS_NONE: + printf("%-15s", "R_MIPS_NONE"); + break; + case R_MIPS_16: + printf("%-15s", "R_MIPS_16"); + break; + case R_MIPS_32: + printf("%-15s", "R_MIPS_32"); + break; + case R_MIPS_REL32: + printf("%-15s", "R_MIPS_REL32"); + break; + case R_MIPS_26: + printf("%-15s", "R_MIPS_26"); + break; + case R_MIPS_HI16: + printf("%-15s", "R_MIPS_HI16"); + break; + case R_MIPS_LO16: + printf("%-15s", "R_MIPS_LO16"); + break; + default: + break; + } + + printf("%X", ELF32_R_SYM(relocs[currentReloc].r_info)); + + putchar('\n'); + } + putchar('\n'); + } + putchar('\n'); + + free(relocs); + } + free(sectionTable); + free(shstrtab); +} + +void Fairy_PrintSectionTable(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + size_t shstrndx; + char* shstrtab; + size_t currentSection; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0); + + printf("[Nr] Name Type Addr Off Size ES Flg Lk Inf Al\n"); + for (currentSection = 0; currentSection < fileHeader.e_shnum; currentSection++) { + FairySecHeader entry = sectionTable[currentSection]; + printf("[%2zd] ", currentSection); + printf("%-15s", shstrtab + entry.sh_name); + + printf("%-15s", Fairy_StringFromDefine(shTypes, entry.sh_type)); + + // printf("%08X ", entry.sh_type); + printf("%08X ", entry.sh_addr); + printf("%06X ", entry.sh_offset); + printf("%06X ", entry.sh_size); + printf("%02X ", entry.sh_entsize); + // printf("%08X ", entry.sh_flags); + + { + char flagChars[] = { 'W', 'A', 'X', 'M', 'S', 'I', 'L', 'O', 'G', 'T', 'C', 'x', 'o', 'E', 'p' }; + uint32_t flags = entry.sh_flags; + size_t shift; + int pad = 4; + for (shift = 0; shift < sizeof(flagChars); shift++) { + if ((flags >> shift) & 1) { + putchar(flagChars[shift]); + pad--; + } + } + if (pad > 0) { + printf("%*s", pad, ""); + } + } + + printf("%2X ", entry.sh_link); + printf("%3X ", entry.sh_info); + printf("%2X", entry.sh_addralign); + putchar('\n'); + } +} + +typedef enum { REL_SECTION_NONE, REL_SECTION_TEXT, REL_SECTION_DATA, REL_SECTION_RODATA } FairyOverlayRelSection; + +const char* relSectionStrings[] = { + NULL, + ".text", + ".data", + ".rodata", +}; + +static uint32_t Fairy_PackReloc(FairyOverlayRelSection sec, FairyRel rel) { + return (sec << 0x1E) | (ELF32_R_TYPE(rel.r_info) << 0x18) | rel.r_offset; +} + +void Fairy_PrintSectionSizes(FairySecHeader* sectionTable, FILE* inputFile, size_t tableSize, char* shstrtab) { + size_t number = tableSize / sizeof(FairySecHeader); + FairySecHeader currentHeader; + char* sectionName; + size_t relocSectionsCount = 0; + size_t* relocSectionIndices; + int* relocSectionSection; + size_t currentRelocSection = 0; + FairySecHeader symtabHeader; + FairySym* symtab; + FairySecHeader strtabHeader; + char* strtab = NULL; + // size_t symtabSize; + + uint32_t textSize = 0; + uint32_t dataSize = 0; + uint32_t rodataSize = 0; + uint32_t bssSize = 0; + uint32_t relocCount = 0; + + size_t currentSection; + bool symtabFound = false; + bool strtabFound = false; + /* Count the reloc sections */ + for (currentSection = 0; currentSection < number; currentSection++) { + if (sectionTable[currentSection].sh_type == SHT_REL) { + relocSectionsCount++; + } + } + printf("relocSectionsCount: %zd\n", relocSectionsCount); + + relocSectionIndices = malloc(relocSectionsCount * sizeof(int)); + relocSectionSection = malloc(relocSectionsCount * sizeof(int)); + + /* Find the section sizes and the reloc sections */ + for (currentSection = 0; currentSection < number; currentSection++) { + currentHeader = sectionTable[currentSection]; + sectionName = &shstrtab[currentHeader.sh_name + 1]; /* ignore the initial '.' */ + switch (currentHeader.sh_type) { + case SHT_PROGBITS: + if (Fairy_StartsWith(sectionName, "rodata")) { + printf("rodata\n"); + rodataSize += currentHeader.sh_size; + break; + } + if (Fairy_StartsWith(sectionName, "data")) { + printf("data\n"); + dataSize += currentHeader.sh_size; + break; + } + if (Fairy_StartsWith(sectionName, "text")) { + printf("text\n"); + textSize += currentHeader.sh_size; + break; + } + break; + + case SHT_NOBITS: + if (Fairy_StartsWith(sectionName, "bss")) { + printf("bss\n"); + bssSize += currentHeader.sh_size; + } + break; + + case SHT_REL: + relocSectionIndices[currentRelocSection] = currentSection; + sectionName += 4; /* ignore the "rel." part */ + if (Fairy_StartsWith(sectionName, "rodata")) { + printf(".rel.rodata\n"); + relocSectionSection[currentRelocSection] = REL_SECTION_RODATA; + } else if (Fairy_StartsWith(sectionName, "data")) { + printf(".rel.data\n"); + relocSectionSection[currentRelocSection] = REL_SECTION_DATA; + } else if (Fairy_StartsWith(sectionName, "text")) { + printf(".rel.text\n"); + relocSectionSection[currentRelocSection] = REL_SECTION_TEXT; + } + + currentRelocSection++; + break; + + case SHT_SYMTAB: + if (Fairy_StartsWith(sectionName, "symtab")) { + symtabHeader = currentHeader; + symtabFound = true; + } + break; + + case SHT_STRTAB: + if (Fairy_StartsWith(sectionName, "strtab")) { + strtabHeader = currentHeader; + strtabFound = true; + } + break; + + default: + break; + } + } + /* Can use symbols here too */ + puts(".section .ovl"); + printf("# OverlayInfo\n"); + printf(".word 0x%08X # .text size\n", textSize); + printf(".word 0x%08X # .data size\n", dataSize); + printf(".word 0x%08X # .rodata size\n", rodataSize); + printf(".word 0x%08X # .bss size\n\n", bssSize); + + if (!symtabFound) { + fprintf(stderr, "Symbol table not found"); + return; + } + /* Obtain the symbol table */ + symtab = malloc(symtabHeader.sh_size); + + // TODO: Consider replacing this with a lighter-weight read: sufficient to get the name, shndx + Fairy_ReadSymbolTable(symtab, inputFile, symtabHeader.sh_offset, symtabHeader.sh_size); + + if (!strtabFound) { + fprintf(stderr, "String table not found"); + } else { + /* Obtain the string table */ + strtab = malloc(strtabHeader.sh_size); + fseek(inputFile, strtabHeader.sh_offset, SEEK_SET); + assert(fread(strtab, strtabHeader.sh_size, 1, inputFile) != 0); + } + + /* Do single-file relocs */ + { + FairyRel* relocs; + for (currentSection = 0; currentSection < relocSectionsCount; currentSection++) { + size_t currentReloc; + size_t sectionRelocCount; + currentHeader = sectionTable[relocSectionIndices[currentSection]]; + sectionRelocCount = currentHeader.sh_size / sizeof(FairyRel); + relocs = malloc(currentHeader.sh_size); + Fairy_ReadRelocs(relocs, inputFile, currentHeader.sh_offset, currentHeader.sh_size); + + for (currentReloc = 0; currentReloc < sectionRelocCount; currentReloc++) { + FairySym symbol = symtab[ELF32_R_SYM(relocs[currentReloc].r_info)]; + if (symbol.st_shndx == SHN_UNDEF) { + continue; // TODO: this is where multifile has to look elsewhere + } + + printf(".word 0x%08X", Fairy_PackReloc(relocSectionSection[currentSection], relocs[currentReloc])); + printf(" # %X (%s), %X, 0x%06X", relocSectionSection[currentSection], &shstrtab[currentHeader.sh_name], + ELF32_R_TYPE(relocs[currentReloc].r_info), relocs[currentReloc].r_offset); + if (strtab != NULL) { + printf(", %s", &strtab[symbol.st_name]); + } + putchar('\n'); + + relocCount++; + } + + free(relocs); + } + } + + printf(".word %d # relocCount\n", relocCount); + + { + uint32_t ovlSectionSize = ((relocCount + 8) & ~0x03) * sizeof(uint32_t); + + printf("\n.word 0x%08X # Overlay section size\n", ovlSectionSize); + } + + free(relocSectionIndices); + free(relocSectionSection); + if (strtab != NULL) { + free(strtab); + } +} + +void PrintZeldaReloc(FILE* inputFile) { + FairyFileHeader fileHeader; + FairySecHeader* sectionTable; + size_t shstrndx; + char* shstrtab; + + Fairy_ReadFileHeader(&fileHeader, inputFile); + sectionTable = malloc(fileHeader.e_shentsize * fileHeader.e_shnum); + shstrndx = fileHeader.e_shstrndx; + + Fairy_ReadSectionTable(sectionTable, inputFile, fileHeader.e_shoff, fileHeader.e_shnum); + + shstrtab = malloc(sectionTable[shstrndx].sh_size * sizeof(char)); + + fseek(inputFile, sectionTable[shstrndx].sh_offset, SEEK_SET); + assert(fread(shstrtab, sectionTable[shstrndx].sh_size, 1, inputFile) != 0); + + Fairy_PrintSectionSizes(sectionTable, inputFile, fileHeader.e_shentsize * fileHeader.e_shnum, shstrtab); + + free(sectionTable); + free(shstrtab); +} diff --git a/tools/fado/lib/fairy/fairy_print.h b/tools/fado/lib/fairy/fairy_print.h new file mode 100644 index 0000000000..85061be223 --- /dev/null +++ b/tools/fado/lib/fairy/fairy_print.h @@ -0,0 +1,7 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include + +void Fairy_PrintSymbolTable(FILE* inputFile); +void Fairy_PrintRelocs(FILE* inputFile); +void Fairy_PrintSectionTable(FILE* inputFile); diff --git a/tools/fado/lib/vc_vector/.gitrepo b/tools/fado/lib/vc_vector/.gitrepo new file mode 100644 index 0000000000..7ab27b998a --- /dev/null +++ b/tools/fado/lib/vc_vector/.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:skogorev/vc_vector.git + branch = master + commit = 39108a4b0aeb904636514b37f418c590084220a7 + parent = 462bee5811d54659236ca51481d01b76c69a37a7 + method = merge + cmdver = 0.4.3 diff --git a/tools/fado/lib/vc_vector/.travis.yml b/tools/fado/lib/vc_vector/.travis.yml new file mode 100644 index 0000000000..f30dfb8e20 --- /dev/null +++ b/tools/fado/lib/vc_vector/.travis.yml @@ -0,0 +1,6 @@ +language: c +compiler: + - gcc + - clang +script: + - make && make test diff --git a/tools/fado/lib/vc_vector/LICENSE.md b/tools/fado/lib/vc_vector/LICENSE.md new file mode 100644 index 0000000000..05929e19d9 --- /dev/null +++ b/tools/fado/lib/vc_vector/LICENSE.md @@ -0,0 +1,21 @@ +#The MIT License (MIT) + +*Copyright (c) 2016 Skogorev Anton* + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/tools/fado/lib/vc_vector/Makefile b/tools/fado/lib/vc_vector/Makefile new file mode 100644 index 0000000000..129ee97e39 --- /dev/null +++ b/tools/fado/lib/vc_vector/Makefile @@ -0,0 +1,33 @@ +OUT_DIR := build +CFLAGS := -O2 -g -std=c99 -Wall -Wextra -Wpedantic -Werror + +SRCS := $(wildcard *.c) +OBJS := $(patsubst %.c,$(OUT_DIR)/%.o,$(SRCS)) + +LIB_NAME := vc-vector +SOBJ := $(OUT_DIR)/lib$(LIB_NAME).so + +.PHONY: all lib test clean + +all: lib + +lib: $(SOBJ) + +test: $(OUT_DIR)/test_runner + $(OUT_DIR)/test_runner + +clean: + rm -rf $(OUT_DIR) + +$(OUT_DIR): + mkdir -p $(OUT_DIR) + +$(SOBJ): vc_vector.c | $(OUT_DIR) + $(CC) $(CFLAGS) -shared -fPIC $< -o $@ + +$(OUT_DIR)/%.o: %.c | $(OUT_DIR) + $(CC) $(CFLAGS) -c $< -o $@ + +$(OUT_DIR)/test_runner: $(OBJS) | $(OUT_DIR) + $(CC) $^ -o $@ + diff --git a/tools/fado/lib/vc_vector/README.md b/tools/fado/lib/vc_vector/README.md new file mode 100644 index 0000000000..c8f8b2ae37 --- /dev/null +++ b/tools/fado/lib/vc_vector/README.md @@ -0,0 +1,92 @@ +# vc_vector +Fast simple C vector implementation + +[![Build Status: make && make test](https://travis-ci.org/skogorev/vc_vector.svg)](https://travis-ci.org/skogorev/vc_vector) + +## Usage + +### Basic +```c +#include "vc_vector.h" + +int main() { + // Creates an empty vector with the default reserved size + // and without custom deleter. Vector will contain 'int' + vc_vector* v = vc_vector_create(0, sizeof(int), NULL); + if (!v) { + return 1; + } + + const int count = 10; + for (int i = 0; i < count; ++i) { + // The function takes a pointer to the elements, + // but the vector will make a copy of the element + vc_vector_push_back(v, &i); + } + + // Print each vector element + for (void* i = vc_vector_begin(v); + i != vc_vector_end(v); + i = vc_vector_next(v, i)) { + printf("%u; ", *(int*)i); + } + + vc_vector_release(v); + return 0; +} +``` + +### Advanced +```c +#include "vc_vector.h" + +struct Item { + int val1; + int val2; +}; + +int main() { + const int n = 10; + + // Creates an empty vector with the reserved size for the 'n' elements + // and with custom deleter 'free'. Vector will contain pointers to 'Item' + vc_vector* v = vc_vector_create(n, sizeof(struct Node*), free); + if (!v) { + return 1; + } + + struct Item* item = NULL; + const int count = n + 1; + // Vector automatically increases the reserved size when 'n + 1' will be added + for (int i = 0; i < count; ++i) { + // Creating item + item = malloc(sizeof(struct Item)); + if (!item) { + continue; + } + + item->val1 = i; + item->val2 = 0; + + // Pushing to the end of the vector + if (!vc_vector_push_back(v, item)) { + // If the item was not pushed, you have to delete it + free(item); + } + } + + // ... + + // Calls custom deleter 'free' for all items + // and releases the vector + vc_vector_release(v); + return 0; +} +``` + +## Projects that use vc_vector +[kraken.io](https://kraken.io/) + +## License + +[MIT License](LICENSE.md) diff --git a/tools/fado/lib/vc_vector/vc_vector.c b/tools/fado/lib/vc_vector/vc_vector.c new file mode 100644 index 0000000000..3f677c242a --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector.c @@ -0,0 +1,329 @@ +#include "vc_vector.h" +#include +#include + +#define GROWTH_FACTOR 1.5 +#define DEFAULT_COUNT_OF_ELEMENTS 8 +#define MINIMUM_COUNT_OF_ELEMENTS 2 + +// ---------------------------------------------------------------------------- + +// vc_vector structure + +struct vc_vector { + size_t count; + size_t element_size; + size_t reserved_size; + char* data; + vc_vector_deleter* deleter; +}; + +// ---------------------------------------------------------------------------- + +// Auxiliary methods + +bool vc_vector_realloc(vc_vector* vector, size_t new_count) { + const size_t new_size = new_count * vector->element_size; + char* new_data = (char*)realloc(vector->data, new_size); + if (!new_data) { + return false; + } + + vector->reserved_size = new_size; + vector->data = new_data; + return true; +} + +// [first_index, last_index) +void vc_vector_call_deleter(vc_vector* vector, size_t first_index, size_t last_index) { + for (size_t i = first_index; i < last_index; ++i) { + vector->deleter(vc_vector_at(vector, i)); + } +} + +void vc_vector_call_deleter_all(vc_vector* vector) { + vc_vector_call_deleter(vector, 0, vc_vector_count(vector)); +} + +// ---------------------------------------------------------------------------- + +// Control + +vc_vector* vc_vector_create(size_t count_elements, size_t size_of_element, vc_vector_deleter* deleter) { + vc_vector* v = (vc_vector*)malloc(sizeof(vc_vector)); + if (v != NULL) { + v->data = NULL; + v->count = 0; + v->element_size = size_of_element; + v->deleter = deleter; + + if (count_elements < MINIMUM_COUNT_OF_ELEMENTS) { + count_elements = DEFAULT_COUNT_OF_ELEMENTS; + } + + if (size_of_element < 1 || + !vc_vector_realloc(v, count_elements)) { + free(v); + v = NULL; + } + } + + return v; +} + +vc_vector* vc_vector_create_copy(const vc_vector* vector) { + vc_vector* new_vector = vc_vector_create(vector->reserved_size / vector->count, + vector->element_size, + vector->deleter); + if (!new_vector) { + return new_vector; + } + + if (memcpy(vector->data, + new_vector->data, + new_vector->element_size * vector->count) == NULL) { + vc_vector_release(new_vector); + new_vector = NULL; + return new_vector; + } + + new_vector->count = vector->count; + return new_vector; +} + +void vc_vector_release(vc_vector* vector) { + if (vector->deleter != NULL) { + vc_vector_call_deleter_all(vector); + } + + if (vector->reserved_size != 0) { + free(vector->data); + } + + free(vector); +} + +bool vc_vector_is_equals(vc_vector* vector1, vc_vector* vector2) { + const size_t size_vector1 = vc_vector_size(vector1); + if (size_vector1 != vc_vector_size(vector2)) { + return false; + } + + return memcmp(vector1->data, vector2->data, size_vector1) == 0; +} + +float vc_vector_get_growth_factor() { + return GROWTH_FACTOR; +} + +size_t vc_vector_get_default_count_of_elements() { + return DEFAULT_COUNT_OF_ELEMENTS; +} + +size_t vc_vector_struct_size() { + return sizeof(vc_vector); +} + +// ---------------------------------------------------------------------------- + +// Element access + +void* vc_vector_at(vc_vector* vector, size_t index) { + return vector->data + index * vector->element_size; +} + +void* vc_vector_front(vc_vector* vector) { + return vector->data; +} + +void* vc_vector_back(vc_vector* vector) { + return vector->data + (vector->count - 1) * vector->element_size; +} + +void* vc_vector_data(vc_vector* vector) { + return vector->data; +} + +// ---------------------------------------------------------------------------- + +// Iterators + +void* vc_vector_begin(vc_vector* vector) { + return vector->data; +} + +void* vc_vector_end(vc_vector* vector) { + return vector->data + vector->element_size * vector->count; +} + +void* vc_vector_next(vc_vector* vector, void* i) { + return (char *)i + vector->element_size; +} + +// ---------------------------------------------------------------------------- + +// Capacity + +bool vc_vector_empty(vc_vector* vector) { + return vector->count == 0; +} + +size_t vc_vector_count(const vc_vector* vector) { + return vector->count; +} + +size_t vc_vector_size(const vc_vector* vector) { + return vector->count * vector->element_size; +} + +size_t vc_vector_max_count(const vc_vector* vector) { + return vector->reserved_size / vector->element_size; +} + +size_t vc_vector_max_size(const vc_vector* vector) { + return vector->reserved_size; +} + +bool vc_vector_reserve_count(vc_vector* vector, size_t new_count) { + if (new_count < vector->count) { + return false; + } + + size_t new_size = vector->element_size * new_count; + if (new_size == vector->reserved_size) { + return true; + } + + return vc_vector_realloc(vector, new_count); +} + +bool vc_vector_reserve_size(vc_vector* vector, size_t new_size) { + return vc_vector_reserve_count(vector, new_size / vector->element_size); +} + +// ---------------------------------------------------------------------------- + +// Modifiers + +void vc_vector_clear(vc_vector* vector) { + if (vector->deleter != NULL) { + vc_vector_call_deleter_all(vector); + } + + vector->count = 0; +} + +bool vc_vector_insert(vc_vector* vector, size_t index, const void* value) { + if (vc_vector_max_count(vector) < vector->count + 1) { + if (!vc_vector_realloc(vector, vc_vector_max_count(vector) * GROWTH_FACTOR)) { + return false; + } + } + + if (!memmove(vc_vector_at(vector, index + 1), + vc_vector_at(vector, index), + vector->element_size * (vector->count - index))) { + + return false; + } + + if (memcpy(vc_vector_at(vector, index), + value, + vector->element_size) == NULL) { + return false; + } + + ++vector->count; + return true; +} + +bool vc_vector_erase(vc_vector* vector, size_t index) { + if (vector->deleter != NULL) { + vector->deleter(vc_vector_at(vector, index)); + } + + if (!memmove(vc_vector_at(vector, index), + vc_vector_at(vector, index + 1), + vector->element_size * (vector->count - index))) { + return false; + } + + vector->count--; + return true; +} + +bool vc_vector_erase_range(vc_vector* vector, size_t first_index, size_t last_index) { + if (vector->deleter != NULL) { + vc_vector_call_deleter(vector, first_index, last_index); + } + + if (!memmove(vc_vector_at(vector, first_index), + vc_vector_at(vector, last_index), + vector->element_size * (vector->count - last_index))) { + return false; + } + + vector->count -= last_index - first_index; + return true; +} + +bool vc_vector_append(vc_vector* vector, const void* values, size_t count) { + const size_t count_new = count + vc_vector_count(vector); + + if (vc_vector_max_count(vector) < count_new) { + size_t max_count_to_reserved = vc_vector_max_count(vector) * GROWTH_FACTOR; + while (count_new > max_count_to_reserved) { + max_count_to_reserved *= GROWTH_FACTOR; + } + + if (!vc_vector_realloc(vector, max_count_to_reserved)) { + return false; + } + } + + if (memcpy(vector->data + vector->count * vector->element_size, + values, + vector->element_size * count) == NULL) { + return false; + } + + vector->count = count_new; + return true; +} + +bool vc_vector_push_back(vc_vector* vector, const void* value) { + if (!vc_vector_append(vector, value, 1)) { + return false; + } + + return true; +} + +bool vc_vector_pop_back(vc_vector* vector) { + if (vector->deleter != NULL) { + vector->deleter(vc_vector_back(vector)); + } + + vector->count--; + return true; +} + +bool vc_vector_replace(vc_vector* vector, size_t index, const void* value) { + if (vector->deleter != NULL) { + vector->deleter(vc_vector_at(vector, index)); + } + + return memcpy(vc_vector_at(vector, index), + value, + vector->element_size) != NULL; +} + +bool vc_vector_replace_multiple(vc_vector* vector, size_t index, const void* values, size_t count) { + if (vector->deleter != NULL) { + vc_vector_call_deleter(vector, index, index + count); + } + + return memcpy(vc_vector_at(vector, index), + values, + vector->element_size * count) != NULL; +} diff --git a/tools/fado/lib/vc_vector/vc_vector.h b/tools/fado/lib/vc_vector/vc_vector.h new file mode 100644 index 0000000000..2b1422c1a5 --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector.h @@ -0,0 +1,120 @@ +#ifndef VCVECTOR_H +#define VCVECTOR_H + +#include +#include + +typedef struct vc_vector vc_vector; +typedef void (vc_vector_deleter)(void *); + +// ---------------------------------------------------------------------------- +// Control +// ---------------------------------------------------------------------------- + +// Constructs an empty vector with an reserver size for count_elements. +vc_vector* vc_vector_create(size_t count_elements, size_t size_of_element, vc_vector_deleter* deleter); + +// Constructs a copy of an existing vector. +vc_vector* vc_vector_create_copy(const vc_vector* vector); + +// Releases the vector. +void vc_vector_release(vc_vector* vector); + +// Compares vector content +bool vc_vector_is_equals(vc_vector* vector1, vc_vector* vector2); + +// Returns constant value of the vector growth factor. +float vc_vector_get_growth_factor(); + +// Returns constant value of the vector default count of elements. +size_t vc_vector_get_default_count_of_elements(); + +// Returns constant value of the vector struct size. +size_t vc_vector_struct_size(); + +// ---------------------------------------------------------------------------- +// Element access +// ---------------------------------------------------------------------------- + +// Returns the item at index position in the vector. +void* vc_vector_at(vc_vector* vector, size_t index); + +// Returns the first item in the vector. +void* vc_vector_front(vc_vector* vector); + +// Returns the last item in the vector. +void* vc_vector_back(vc_vector* vector); + +// Returns a pointer to the data stored in the vector. The pointer can be used to access and modify the items in the vector. +void* vc_vector_data(vc_vector* vector); + +// ---------------------------------------------------------------------------- +// Iterators +// ---------------------------------------------------------------------------- + +// Returns a pointer to the first item in the vector. +void* vc_vector_begin(vc_vector* vector); + +// Returns a pointer to the imaginary item after the last item in the vector. +void* vc_vector_end(vc_vector* vector); + +// Returns a pointer to the next element of vector after 'i'. +void* vc_vector_next(vc_vector* vector, void* i); + +// ---------------------------------------------------------------------------- +// Capacity +// ---------------------------------------------------------------------------- + +// Returns true if the vector is empty; otherwise returns false. +bool vc_vector_empty(vc_vector* vector); + +// Returns the number of elements in the vector. +size_t vc_vector_count(const vc_vector* vector); + +// Returns the size (in bytes) of occurrences of value in the vector. +size_t vc_vector_size(const vc_vector* vector); + +// Returns the maximum number of elements that the vector can hold. +size_t vc_vector_max_count(const vc_vector* vector); + +// Returns the maximum size (in bytes) that the vector can hold. +size_t vc_vector_max_size(const vc_vector* vector); + +// Resizes the container so that it contains n elements. +bool vc_vector_reserve_count(vc_vector* vector, size_t new_count); + +// Resizes the container so that it contains new_size / element_size elements. +bool vc_vector_reserve_size(vc_vector* vector, size_t new_size); + +// ---------------------------------------------------------------------------- +// Modifiers +// ---------------------------------------------------------------------------- + +// Removes all elements from the vector (without reallocation). +void vc_vector_clear(vc_vector* vector); + +// The container is extended by inserting a new element at position. +bool vc_vector_insert(vc_vector* vector, size_t index, const void* value); + +// Removes from the vector a single element by 'index' +bool vc_vector_erase(vc_vector* vector, size_t index); + +// Removes from the vector a range of elements '[first_index, last_index)'. +bool vc_vector_erase_range(vc_vector* vector, size_t first_index, size_t last_index); + +// Inserts multiple values at the end of the vector. +bool vc_vector_append(vc_vector* vector, const void* values, size_t count); + +// Inserts value at the end of the vector. +bool vc_vector_push_back(vc_vector* vector, const void* value); + +// Removes the last item in the vector. +bool vc_vector_pop_back(vc_vector* vector); + +// Replace value by index in the vector. +bool vc_vector_replace(vc_vector* vector, size_t index, const void* value); + +// Replace multiple values by index in the vector. +bool vc_vector_replace_multiple(vc_vector* vector, size_t index, const void* values, size_t count); + +#endif // VCVECTOR_H diff --git a/tools/fado/lib/vc_vector/vc_vector_test.c b/tools/fado/lib/vc_vector/vc_vector_test.c new file mode 100644 index 0000000000..03a0544206 --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector_test.c @@ -0,0 +1,353 @@ +#include "vc_vector_test.h" +#include +#include +#include +#include "vc_vector.h" + +#define ASSERT_EQ(expected, actual) \ + do { \ + if ((expected) != (actual)) { \ + fprintf(stderr, \ + "Failed line %u. Expected: %"PRIuMAX". Actual: %"PRIuMAX".\n", \ + __LINE__, (uintmax_t)(expected), (uintmax_t)(actual)); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_NE(not_expected, actual) \ + do { \ + if ((not_expected) == (actual)) { \ + fprintf(stderr, \ + "Failed line %u. Unexpected actual value: %"PRIuMAX".\n", \ + __LINE__, (uintmax_t)(actual)); \ + abort(); \ + } \ + } while (0) + +#define ASSERT_TRUE(actual) ASSERT_EQ(true, (actual)) + +#define ASSERT_FALSE(actual) ASSERT_EQ(false, (actual)) + +#define PRINT_VECTOR(vector, type, format) \ + do { \ + for (void* i = vc_vector_begin(vector); \ + i != vc_vector_end(vector); \ + i = vc_vector_next(vector, i)) { \ + fprintf(stderr, format, *(type*)i); \ + } \ + fprintf(stderr, "\n"); \ + } while (0) + +#define PRINT_VECTOR_INT(vector) PRINT_VECTOR(vector, int, "%d; ") +#define PRINT_VECTOR_STR(vector) PRINT_VECTOR(vector, char *, "%s; ") + +char *mystrdup(const char *s) { + size_t size = strlen(s) + 1; + char *copy = malloc(size); + if (copy != NULL) + memcpy(copy, s, size); + return copy; +} + +// ---------------------------------------------------------------------------- + +void test_vc_vector_create() { + const size_t size_of_type = sizeof(int); + const size_t default_count_of_elements = vc_vector_get_default_count_of_elements(); + + // Creating vector with default count of elements + vc_vector* vector = vc_vector_create(0, size_of_type, NULL); + ASSERT_NE(NULL, vector); + ASSERT_EQ(0, vc_vector_count(vector)); + ASSERT_EQ(0, vc_vector_size(vector)); + ASSERT_EQ(default_count_of_elements, vc_vector_max_count(vector)); + ASSERT_EQ(size_of_type * default_count_of_elements, vc_vector_max_size(vector)); + vc_vector_release(vector); + + // Creating vector with custom count of elements + const size_t test_count_of_elements = 7; + vector = vc_vector_create(test_count_of_elements, size_of_type, NULL); + ASSERT_NE(NULL, vector); + ASSERT_EQ(0, vc_vector_count(vector)); + ASSERT_EQ(0, vc_vector_size(vector)); + ASSERT_EQ(test_count_of_elements, vc_vector_max_count(vector)); + ASSERT_EQ(size_of_type * test_count_of_elements, vc_vector_max_size(vector)); + vc_vector_release(vector); + + // Creating vector with zero size of single element + vector = vc_vector_create(0, 0, NULL); + ASSERT_EQ(NULL, vector); + + // Creating copy of vector + vector = vc_vector_create(0, size_of_type, NULL); + ASSERT_NE(NULL, vector); + for (int i = 0; (size_t)i < test_count_of_elements; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + vc_vector* vector_copy = vc_vector_create_copy(vector); + ASSERT_NE(NULL, vector_copy); + ASSERT_TRUE(vc_vector_is_equals(vector, vector_copy)); + + vc_vector_release(vector_copy); + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_element_access() { + const int test_num_start = 18; + const int test_num_end = 36; + const size_t size_of_type = sizeof(test_num_start); + + vc_vector* vector = vc_vector_create(0, size_of_type, NULL); + ASSERT_NE(0, vector); + for (int i = test_num_start; i <= test_num_end; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + ASSERT_EQ(test_num_start, *(int*)vc_vector_front(vector)); + ASSERT_EQ(test_num_start, *(int*)vc_vector_data(vector)); + ASSERT_EQ(test_num_end, *(int*)vc_vector_back(vector)); + + for (int i = test_num_start, j = 0; i <= test_num_end; ++i, ++j) { + ASSERT_EQ(i, *(int*)vc_vector_at(vector, j)); + } + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_iterators() { + vc_vector* vector = vc_vector_create(0, sizeof(int), NULL); + ASSERT_NE(NULL, vector); + + const size_t test_count_of_elements = 23; + for (int i = 0; (size_t)i < test_count_of_elements; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + int j = 0; + for (void* i = vc_vector_begin(vector); + i != vc_vector_end(vector); + i = vc_vector_next(vector, i), ++j) { + ASSERT_EQ(j, *(int*)i); + } + + ASSERT_EQ(test_count_of_elements, (size_t)j); + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_capacity() { + const size_t size_of_element = sizeof(int); + const float growth_factor = vc_vector_get_growth_factor(); + ASSERT_EQ(1.5, growth_factor); + + const size_t count_of_elements_initialized = 22; + const size_t max_size_of_vector_initialized = count_of_elements_initialized * size_of_element; + const size_t count_of_elements_ended = 23; + const size_t size_of_vector_ended = count_of_elements_ended * size_of_element; + const size_t max_count_of_vector_ended = count_of_elements_initialized * growth_factor; + const size_t max_size_of_vector_ended = max_count_of_vector_ended * size_of_element; + + vc_vector* vector = vc_vector_create(count_of_elements_initialized, size_of_element, NULL); + ASSERT_NE(NULL, vector); + + ASSERT_EQ(0, vc_vector_count(vector)); + ASSERT_TRUE(vc_vector_empty(vector)); + ASSERT_EQ(0, vc_vector_size(vector)); + ASSERT_EQ(count_of_elements_initialized, vc_vector_max_count(vector)); + ASSERT_EQ(max_size_of_vector_initialized, vc_vector_max_size(vector)); + + for (int i = 0; (size_t)i < count_of_elements_ended; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &i)); + } + + ASSERT_EQ(count_of_elements_ended, vc_vector_count(vector)); + ASSERT_FALSE(vc_vector_empty(vector)); + ASSERT_EQ(size_of_vector_ended, vc_vector_size(vector)); + ASSERT_EQ(max_count_of_vector_ended, vc_vector_max_count(vector)); + ASSERT_EQ(max_size_of_vector_ended, vc_vector_max_size(vector)); + + const size_t test_reserve_count_fail = 10; + ASSERT_FALSE(vc_vector_reserve_count(vector, test_reserve_count_fail)); + + const size_t test_reserve_count = 35; + ASSERT_TRUE(vc_vector_reserve_count(vector, test_reserve_count)); + ASSERT_EQ(test_reserve_count, vc_vector_max_count(vector)); + ASSERT_EQ(test_reserve_count * size_of_element, vc_vector_max_size(vector)); + + // Second time with the same value + ASSERT_TRUE(vc_vector_reserve_count(vector, test_reserve_count)); + ASSERT_EQ(test_reserve_count, vc_vector_max_count(vector)); + ASSERT_EQ(test_reserve_count * size_of_element, vc_vector_max_size(vector)); + + const size_t test_reserve_size = 123 * size_of_element; + ASSERT_TRUE(vc_vector_reserve_size(vector, test_reserve_size)); + ASSERT_EQ(test_reserve_size / size_of_element, vc_vector_max_count(vector)); + ASSERT_EQ(test_reserve_size, vc_vector_max_size(vector)); + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_modifiers() { + const int begin[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 + }; + const size_t size_of_element = sizeof(begin[0]); + const size_t count_of_elements = sizeof(begin) / size_of_element; + + // After deleting first, last and one middle elements + const int after_deleting_some_elements[] = { + /* 1, */ 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 11, */ 12, 13, 14, 15, 16, 17, 18, 19, /* 20 */ + }; + + // After deleting first 3 elemets from begin, 4 from middle and 3 from end + const int after_deleting_some_ranges[] = { + /* 1, 2, 3, */ 4, 5, 6, 7, 8, /* 9, 10, 11, 12, */ 13, 14, 15, 16, 17, /* 18, 19, 20 */ + }; + + vc_vector* vector = vc_vector_create(0, size_of_element, NULL); + ASSERT_NE(NULL, vector); + + // Append test + + ASSERT_TRUE(vc_vector_append(vector, begin, count_of_elements)); + + ASSERT_EQ(count_of_elements, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(begin[i], *(int*)vc_vector_at(vector, i)); + } + + // Pop back test + + while (vc_vector_count(vector) > 0) { + ASSERT_TRUE(vc_vector_pop_back(vector)); + } + + ASSERT_TRUE(vc_vector_empty(vector)); + + // Push back test + + for (size_t i = 0; i < count_of_elements; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &begin[i])); + } + + ASSERT_EQ(count_of_elements, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(begin[i], *(int*)vc_vector_at(vector, i)); + } + + // Erase test + + vc_vector_clear(vector); + ASSERT_TRUE(vc_vector_append(vector, begin, count_of_elements)); + + ASSERT_TRUE(vc_vector_erase(vector, 0)); + ASSERT_TRUE(vc_vector_erase(vector, vc_vector_count(vector) - 1)); + ASSERT_TRUE(vc_vector_erase(vector, vc_vector_count(vector) / 2)); + + ASSERT_EQ(sizeof(after_deleting_some_elements) / size_of_element, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(after_deleting_some_elements[i], *(int*)vc_vector_at(vector, i)); + } + + // Erase range test + + vc_vector_clear(vector); + ASSERT_TRUE(vc_vector_append(vector, begin, count_of_elements)); + + ASSERT_TRUE(vc_vector_erase_range(vector, 0, 3)); + ASSERT_TRUE(vc_vector_erase_range(vector, vc_vector_count(vector) - 3, vc_vector_count(vector))); + ASSERT_TRUE(vc_vector_erase_range(vector, vc_vector_count(vector) / 2 - 2, vc_vector_count(vector) / 2 + 2)); + + ASSERT_EQ(sizeof(after_deleting_some_ranges) / size_of_element, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(after_deleting_some_ranges[i], *(int*)vc_vector_at(vector, i)); + } + + // Insert test + + vc_vector_clear(vector); + for (size_t i = 1; i < count_of_elements - 1; ++i) { + ASSERT_TRUE(vc_vector_insert(vector, i - 1, &begin[i])); + } + + ASSERT_TRUE(vc_vector_insert(vector, 0, &begin[0])); + ASSERT_TRUE(vc_vector_insert(vector, vc_vector_count(vector), &begin[count_of_elements - 1])); + + ASSERT_EQ(count_of_elements, vc_vector_count(vector)); + for (size_t i = 0; i < vc_vector_count(vector); ++i) { + ASSERT_EQ(begin[i], *(int*)vc_vector_at(vector, i)); + } + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void test_vc_vector_strfreefunc(void *data) { + free(*(char **)data); +} + +void test_vc_vector_with_strfreefunc() { + // creates a vector of pointers to char, i.e. a vector of variable sized strings + vc_vector* vector = vc_vector_create(3, sizeof(char *), test_vc_vector_strfreefunc); + ASSERT_NE(NULL, vector); + + char *strs[] = { + mystrdup("abcde"), + mystrdup("edcba"), + mystrdup("1234554321"), + mystrdup("!@#$%"), + mystrdup("not empty string"), + mystrdup(""), + mystrdup("Hello World"), + mystrdup("xxxxx"), + mystrdup("yyyyy") + }; + + for (size_t i = 0; i < 3; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &strs[i])); + } + + ASSERT_EQ(3, vc_vector_count(vector)); + + for (size_t i = 3; i < 6; ++i) { + ASSERT_TRUE(vc_vector_insert(vector, i, &strs[i])); + } + + ASSERT_EQ(6, vc_vector_count(vector)); + vc_vector_clear(vector); // strs[0-6] were freed + ASSERT_EQ(0, vc_vector_count(vector)); + + for (size_t i = 6; i < 9; ++i) { + ASSERT_TRUE(vc_vector_push_back(vector, &strs[i])); + } + + ASSERT_EQ(3, vc_vector_count(vector)); + + vc_vector_release(vector); + + printf("%s passed.\n", __func__); +} + +void vc_vector_run_tests() { + test_vc_vector_create(); + test_vc_vector_element_access(); + test_vc_vector_iterators(); + test_vc_vector_capacity(); + test_vc_vector_modifiers(); + test_vc_vector_with_strfreefunc(); +} + +int main() { + vc_vector_run_tests(); + printf("Tests passed.\n"); + return 0; +} diff --git a/tools/fado/lib/vc_vector/vc_vector_test.h b/tools/fado/lib/vc_vector/vc_vector_test.h new file mode 100644 index 0000000000..9439ea3c61 --- /dev/null +++ b/tools/fado/lib/vc_vector/vc_vector_test.h @@ -0,0 +1,6 @@ +#ifndef VCVECTORTESTS_H +#define VCVECTORTESTS_H + +void vc_vector_run_tests(); + +#endif // VCVECTORTESTS_H diff --git a/tools/fado/src/fado.c b/tools/fado/src/fado.c new file mode 100644 index 0000000000..9edb394cd3 --- /dev/null +++ b/tools/fado/src/fado.c @@ -0,0 +1,310 @@ +/** + * Code specific to reading and outputting Zelda 64 relocations + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "fado.h" + +#include +#include +#include +#include +#include +#include +#include "fairy/fairy.h" +#include "macros.h" +#include "vc_vector/vc_vector.h" + +/* String-finding-related functions */ + +bool Fado_CheckInProgBitsSections(Elf32_Section section, vc_vector* progBitsSections) { + Elf32_Section* i; + VC_FOREACH(i, progBitsSections) { + if (*i == section) { + return true; + } + } + return false; +} + +/** + * For each input file, construct a vector of pointers to the starts of the strings defined in that file. + */ +void Fado_ConstructStringVectors(vc_vector** stringVectors, FairyFileInfo* fileInfo, int numFiles) { + int currentFile; + size_t currentSym; + + for (currentFile = 0; currentFile < numFiles; currentFile++) { + FairySym* symtab = fileInfo[currentFile].symtabInfo.sectionData; + + stringVectors[currentFile] = vc_vector_create(0x40, sizeof(char**), NULL); + + /* Build a vector of pointers to defined symbols' names */ + for (currentSym = 0; currentSym < fileInfo[currentFile].symtabInfo.sectionSize / sizeof(FairySym); + currentSym++) { + if ((symtab[currentSym].st_shndx != STN_UNDEF) && + Fado_CheckInProgBitsSections(symtab[currentSym].st_shndx, fileInfo[currentFile].progBitsSections)) { + /* Have to pass a double pointer so it copies the pointer instead of the start of the string */ + char* stringPtr = &fileInfo[currentFile].strtab[symtab[currentSym].st_name]; + assert(vc_vector_push_back(stringVectors[currentFile], &stringPtr)); + } + } + } +} + +bool Fado_FindSymbolNameInOtherFiles(const char* name, int thisFile, vc_vector** stringVectors, int numFiles) { + int currentFile; + char** currentString; + + for (currentFile = 0; currentFile < numFiles; currentFile++) { + if (currentFile == thisFile) { + continue; + } + VC_FOREACH(currentString, stringVectors[currentFile]) { + if (strcmp(name, *currentString) == 0) { + FAIRY_DEBUG_PRINTF("Match found for %s\n", name); + return true; + } + } + } + FAIRY_DEBUG_PRINTF("No match found for %s\n", name); + return false; +} + +void Fado_DestroyStringVectors(vc_vector** stringVectors, int numFiles) { + int currentFile; + for (currentFile = 0; currentFile < numFiles; currentFile++) { + vc_vector_release(stringVectors[currentFile]); + } + free(stringVectors); +} + +typedef struct { + size_t symbolIndex; + int file; + uint32_t relocWord; +} FadoRelocInfo; + +/* Construct the Zelda64ovl-compatible reloc word from an ELF reloc */ +FadoRelocInfo Fado_MakeReloc(int file, FairySection section, FairyRel* data) { + FadoRelocInfo relocInfo = { 0 }; + uint32_t sectionPrefix = 0; + + relocInfo.symbolIndex = ELF32_R_SYM(data->r_info); + relocInfo.file = file; + + switch (section) { + case FAIRY_SECTION_TEXT: + sectionPrefix = 1; + break; + + case FAIRY_SECTION_DATA: + sectionPrefix = 2; + break; + + case FAIRY_SECTION_RODATA: + sectionPrefix = 3; + break; + + default: + fprintf(stderr, "warning: Relocation section is invalid.\n"); + break; + } + relocInfo.relocWord = + ((sectionPrefix & 3) << 0x1E) | (ELF32_R_TYPE(data->r_info) << 0x18) | (data->r_offset & 0xFFFFFF); + + return relocInfo; +} + +static const FairyDefineString relSectionNames[] = { + FAIRY_DEF_STRING(FAIRY_SECTION_, TEXT), + FAIRY_DEF_STRING(FAIRY_SECTION_, DATA), + FAIRY_DEF_STRING(FAIRY_SECTION_, RODATA), + { 0 }, +}; + +/* Taken from elf.h */ +static const FairyDefineString relTypeNames[] = { + FAIRY_DEF_STRING(, R_MIPS_NONE), /* No reloc */ + FAIRY_DEF_STRING(, R_MIPS_16), /* Direct 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_32), /* Direct 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_REL32), /* PC relative 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_26), /* Direct 26 bit shifted */ + FAIRY_DEF_STRING(, R_MIPS_HI16), /* High 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_LO16), /* Low 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_GPREL16), /* GP relative 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_LITERAL), /* 16 bit literal entry */ + FAIRY_DEF_STRING(, R_MIPS_GOT16), /* 16 bit GOT entry */ + FAIRY_DEF_STRING(, R_MIPS_PC16), /* PC relative 16 bit */ + FAIRY_DEF_STRING(, R_MIPS_CALL16), /* 16 bit GOT entry for function */ + FAIRY_DEF_STRING(, R_MIPS_GPREL32), /* GP relative 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_SHIFT5), + FAIRY_DEF_STRING(, R_MIPS_SHIFT6), + FAIRY_DEF_STRING(, R_MIPS_64), + FAIRY_DEF_STRING(, R_MIPS_GOT_DISP), + FAIRY_DEF_STRING(, R_MIPS_GOT_PAGE), + FAIRY_DEF_STRING(, R_MIPS_GOT_OFST), + FAIRY_DEF_STRING(, R_MIPS_GOT_HI16), + FAIRY_DEF_STRING(, R_MIPS_GOT_LO16), + FAIRY_DEF_STRING(, R_MIPS_SUB), + FAIRY_DEF_STRING(, R_MIPS_INSERT_A), + FAIRY_DEF_STRING(, R_MIPS_INSERT_B), + FAIRY_DEF_STRING(, R_MIPS_DELETE), + FAIRY_DEF_STRING(, R_MIPS_HIGHER), + FAIRY_DEF_STRING(, R_MIPS_HIGHEST), + FAIRY_DEF_STRING(, R_MIPS_CALL_HI16), + FAIRY_DEF_STRING(, R_MIPS_CALL_LO16), + FAIRY_DEF_STRING(, R_MIPS_SCN_DISP), + FAIRY_DEF_STRING(, R_MIPS_REL16), + FAIRY_DEF_STRING(, R_MIPS_ADD_IMMEDIATE), + FAIRY_DEF_STRING(, R_MIPS_PJUMP), + FAIRY_DEF_STRING(, R_MIPS_RELGOT), + FAIRY_DEF_STRING(, R_MIPS_JALR), + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPMOD32), /* Module number 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL32), /* Module-relative offset 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPMOD64), /* Module number 64 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL64), /* Module-relative offset 64 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_GD), /* 16 bit GOT offset for GD */ + FAIRY_DEF_STRING(, R_MIPS_TLS_LDM), /* 16 bit GOT offset for LDM */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL_HI16), /* Module-relative offset, high 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_TLS_DTPREL_LO16), /* Module-relative offset, low 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_TLS_GOTTPREL), /* 16 bit GOT offset for IE */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL32), /* TP-relative offset, 32 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL64), /* TP-relative offset, 64 bit */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL_HI16), /* TP-relative offset, high 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_TLS_TPREL_LO16), /* TP-relative offset, low 16 bits */ + FAIRY_DEF_STRING(, R_MIPS_GLOB_DAT), + FAIRY_DEF_STRING(, R_MIPS_COPY), + FAIRY_DEF_STRING(, R_MIPS_JUMP_SLOT), + FAIRY_DEF_STRING(, R_MIPS_NUM), +}; + +/** + * Find all the necessary relocations to retain (those defined in any input file), and print them in the appropriate + * format. + */ +void Fado_Relocs(FILE* outputFile, int inputFilesCount, FILE** inputFiles, const char* ovlName) { + /* General information structs */ + FairyFileInfo* fileInfos = malloc(inputFilesCount * sizeof(FairyFileInfo)); + + /* Symbol tables for each file */ + FairySym** symtabs = malloc(inputFilesCount * sizeof(FairySym*)); + + /* Lists of names of symbols defined in files of the overlay */ + vc_vector** stringVectors = malloc(inputFilesCount * sizeof(vc_vector*)); + + /* The relocs in the format we will print */ + vc_vector* relocList[FAIRY_SECTION_OTHER]; /* Maximum number of reloc sections */ + + /* Offset of current file's current section into the overlay's whole section */ + uint32_t sectionOffset[FAIRY_SECTION_OTHER] = { 0 }; + + /* Total number of relocs */ + uint32_t relocCount = 0; + + /* iterators */ + int currentFile; + FairySection section; + size_t relocIndex; + + for (currentFile = 0; currentFile < inputFilesCount; currentFile++) { + FAIRY_INFO_PRINTF("Begin initialising file %d info.\n", currentFile); + Fairy_InitFile(&fileInfos[currentFile], inputFiles[currentFile]); + FAIRY_INFO_PRINTF("Initialising file %d info complete.\n", currentFile); + + symtabs[currentFile] = fileInfos[currentFile].symtabInfo.sectionData; + } + + Fado_ConstructStringVectors(stringVectors, fileInfos, inputFilesCount); + FAIRY_INFO_PRINTF("%s", "symtabs set\n"); + + /* Construct relocList of all relevant relocs */ + for (section = FAIRY_SECTION_TEXT; section < FAIRY_SECTION_OTHER; section++) { + relocList[section] = vc_vector_create(0x100, sizeof(FadoRelocInfo), NULL); + + for (currentFile = 0; currentFile < inputFilesCount; currentFile++) { + FairyRel* relSection = fileInfos[currentFile].relocTablesInfo[section].sectionData; + if (relSection != NULL) { + + for (relocIndex = 0; + relocIndex < fileInfos[currentFile].relocTablesInfo[section].sectionSize / sizeof(FairyRel); + relocIndex++) { + FadoRelocInfo currentReloc = Fado_MakeReloc(currentFile, section, &relSection[relocIndex]); + + if ((symtabs[currentFile][currentReloc.symbolIndex].st_shndx != STN_UNDEF) || + Fado_FindSymbolNameInOtherFiles( + &fileInfos[currentFile].strtab[symtabs[currentFile][currentReloc.symbolIndex].st_name], + currentFile, stringVectors, inputFilesCount)) { + + currentReloc.relocWord += sectionOffset[section]; + FAIRY_DEBUG_PRINTF("current section offset: %d\n", sectionOffset[section]); + vc_vector_push_back(relocList[section], ¤tReloc); + relocCount++; + } + } + } else { + FAIRY_INFO_PRINTF("%s", "Ignoring empty reloc section\n"); + } + + sectionOffset[section] += fileInfos[currentFile].progBitsSizes[section]; + FAIRY_INFO_PRINTF("section offset: %d\n", sectionOffset[section]); + } + } + + { + /* Write header */ + fprintf(outputFile, ".section .ovl\n"); + fprintf(outputFile, "# %sOverlayInfo\n", ovlName); + fprintf(outputFile, ".word _%sSegmentTextSize\n", ovlName); + fprintf(outputFile, ".word _%sSegmentDataSize\n", ovlName); + fprintf(outputFile, ".word _%sSegmentRoDataSize\n", ovlName); + fprintf(outputFile, ".word _%sSegmentBssSize\n", ovlName); + + fprintf(outputFile, "\n.word %d # relocCount\n", relocCount); + + /* Write reloc table */ + for (section = FAIRY_SECTION_TEXT; section < FAIRY_SECTION_OTHER; section++) { + if (vc_vector_count(relocList[section]) == 0) { + FAIRY_INFO_PRINTF("%s", "Ignoring empty reloc section\n"); + continue; + } + + fprintf(outputFile, "\n# %s RELOCS\n", Fairy_StringFromDefine(relSectionNames, section)); + + { + FadoRelocInfo* currentReloc; + VC_FOREACH(currentReloc, relocList[section]) { + fprintf(outputFile, ".word 0x%X # %-11s 0x%06X %s\n", currentReloc->relocWord, + Fairy_StringFromDefine(relTypeNames, (currentReloc->relocWord >> 0x18) & 0x3F), + currentReloc->relocWord & 0xFFFFFF, + Fairy_GetSymbolName(symtabs[currentReloc->file], fileInfos[currentReloc->file].strtab, + currentReloc->symbolIndex)); + } + } + } + + /* print pads and section size */ + for (relocCount += 5; ((relocCount + 1) & 3) != 0; relocCount++) { + fprintf(outputFile, ".word 0\n"); + } + fprintf(outputFile, "\n.word 0x%08X # %sOverlayInfoOffset\n", 4 * (relocCount + 1), ovlName); + } + + for (currentFile = 0; currentFile < inputFilesCount; currentFile++) { + Fairy_DestroyFile(&fileInfos[currentFile]); + FAIRY_INFO_PRINTF("Freed file %d\n", currentFile); + } + + for (section = FAIRY_SECTION_TEXT; section < FAIRY_SECTION_OTHER; section++) { + if (relocList[section] != NULL) { + vc_vector_release(relocList[section]); + } + FAIRY_INFO_PRINTF("Freed relocList[%d]\n", section); + } + + Fado_DestroyStringVectors(stringVectors, inputFilesCount); + FAIRY_INFO_PRINTF("%s", "Freed string vectors\n"); + free(symtabs); + FAIRY_INFO_PRINTF("%s", "Freed symtabs\n"); + free(fileInfos); +} diff --git a/tools/fado/src/help.c b/tools/fado/src/help.c new file mode 100644 index 0000000000..ddb9939a16 --- /dev/null +++ b/tools/fado/src/help.c @@ -0,0 +1,162 @@ +/** + * Getopt-compatible printing of formatted help. + */ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include "help.h" + +#include +#include +#include +#include +#include +#include + +#include "macros.h" + +/* Values of the variables used by Help_PrintHelp. Defaults are taken from common terminal programs like grep */ +size_t helpTextWidth = 80; +size_t helpDtIndent = 2; +size_t helpDdIndent = 25; + +/** + * Prints a paragraph, word wrapped to helpTextWidth, with a hanging indent. initialColumn is used to determine how wide + * the first line should be, while indentFirstLine should be true if there is no previous text on the line (an ordinary + * paragraph), and false if there is (e.g. as a description list description) + */ +void Help_PrintFlowAndIndent(const char* string, size_t initialColumn, size_t textWidth, size_t hangingIndent, + bool indentFirstLine) { + size_t column = initialColumn; + size_t index = 0; + size_t inLength = strlen(string); + size_t lookAhead; + bool shouldBreak; + + assert(initialColumn < textWidth); + assert(hangingIndent < textWidth); + + if (indentFirstLine) { + printf("%*s", (int)initialColumn, ""); + } + + for (; index <= inLength; index++) { + shouldBreak = 0; + + if (column == textWidth) { + printf("%c\n%*s", string[index], (int)hangingIndent, ""); + column = hangingIndent; + continue; + } + + column++; + + switch (string[index]) { + case '\0': + return; + + case ' ': + if (column == hangingIndent) { + continue; + } + + for (lookAhead = 0; lookAhead <= textWidth - column; lookAhead++) { + // printf("%c\n", src[index + lookAhead]); + if (string[index + lookAhead + 1] == ' ' || string[index + lookAhead + 1] == '\0') { + putchar(' '); + shouldBreak = 1; + break; + } + } + if (shouldBreak) { /* Damn shared keywords. */ + break; + } + case '\n': + printf("\n%*s", (int)hangingIndent, ""); + column = hangingIndent; + break; + + default: + putchar(string[index]); + break; + } + } +} + +/** + * Prints help in the form + * ``` + * prologue (word wrapped) + * + * Positional arguments + * arg1 Description (word + * wrapped) + * arg2 Description (word + * wrapped) + * + * Options + * -a --long-name=ARG Description (word + * wrapped) + * + * epilogue (word wrapped) + * ``` + * where the positional arguments are described using the posArgInfo array, and options are fed using the OptInfo array, + * which should both be null-terminated. posArgCount/optCount is the actual number of positional arguments/options: it + * is used to guarantee no garbage is printed even if the user has not null-terminated the array. (optCount is required + * for constructing the getopt option array anyway.) + */ +void Help_PrintHelp(const char* prologue, size_t posArgCount, const PosArgInfo* posArgInfo, size_t optCount, + const OptInfo* optInfo, const char* epilogue) { + size_t i; + size_t dtLength; + int padding; + + Help_PrintFlowAndIndent(prologue, 0, helpTextWidth, 0, false); + + if (posArgCount != 0) { + printf("\nPositional Argument\n"); + for (i = 0; i < optCount; i++) { + if (posArgInfo[i].helpArg == 0) { + break; + } + + dtLength = helpDtIndent + strlen(posArgInfo[i].helpArg); + + padding = helpDdIndent - dtLength - 2; + printf("%*s%s%*s ", (int)helpDtIndent, "", posArgInfo[i].helpArg, CLAMP_MIN(padding, 0), ""); + + Help_PrintFlowAndIndent(posArgInfo[i].helpMsg, CLAMP_MIN(dtLength + 2, helpDdIndent), helpTextWidth, + helpDdIndent, false); + printf("\n"); + } + } + + if (optCount != 0) { + printf("\nOptions\n"); + + for (i = 0; i < optCount; i++) { + if (optInfo[i].longOpt.val == 0) { + break; + } + + dtLength = helpDtIndent + 6 + strlen(optInfo[i].longOpt.name); + + if (optInfo[i].helpArg == NULL) { + padding = helpDdIndent - dtLength - 2; + printf("%*s-%c, --%s%*s ", (int)helpDtIndent, "", optInfo[i].longOpt.val, optInfo[i].longOpt.name, + CLAMP_MIN(padding, 0), ""); + } else { + dtLength += 1 + strlen(optInfo[i].helpArg); + padding = helpDdIndent - dtLength - 2; + printf("%*s-%c, --%s=%s%*s ", (int)helpDtIndent, "", optInfo[i].longOpt.val, optInfo[i].longOpt.name, + optInfo[i].helpArg, CLAMP_MIN(padding, 0), ""); + } + Help_PrintFlowAndIndent(optInfo[i].helpMsg, CLAMP_MIN(dtLength + 2, helpDdIndent), helpTextWidth, + helpDdIndent, false); + printf("\n"); + } + } + + printf("\n"); + Help_PrintFlowAndIndent(epilogue, 0, helpTextWidth, 0, false); + printf("\n"); +} diff --git a/tools/fado/src/main.c b/tools/fado/src/main.c new file mode 100644 index 0000000000..18347651a4 --- /dev/null +++ b/tools/fado/src/main.c @@ -0,0 +1,229 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +#include +#include +#include +#include +#include + +#include "macros.h" +#include "fairy/fairy.h" +#include "fado.h" +#include "help.h" +#include "mido.h" +#include "vc_vector/vc_vector.h" + +#include "version.inc" + +void PrintVersion() { + printf("Fado (Fairy-Assisted relocations for Decompiled Overlays), version %s\n", versionNumber); + printf("Copyright (C) 2021 Elliptic Ellipsis\n"); + printf("%s\n", credits); + printf("Repository available at %s.\n", repo); +} + +#if defined _WIN32 || defined __CYGWIN__ +#define PATH_SEPARATOR '\\' +#else +#define PATH_SEPARATOR '/' +#endif + +/** + * (Bad) filename-parsing idea to get the overlay name from the filename. Output must be freed separately. + */ +char* GetOverlayNameFromFilename(const char* src) { + char* ret; + const char* ptr; + const char* start = src; + const char* end = src; + + for (ptr = src; *ptr != '\0'; ptr++) { + if (*ptr == PATH_SEPARATOR) { + start = end + 1; + end = ptr; + } + } + + if (end == src) { + return NULL; + } + + ret = malloc((end - start + 1) * sizeof(char)); + memcpy(ret, start, end - start); + ret[end - start] = '\0'; + + return ret; +} + +#define OPTSTR "M:n:o:v:hV" +#define USAGE_STRING "Usage: %s [-hV] [-n name] [-o output_file] [-v level] input_files ...\n" + +#define HELP_PROLOGUE \ + "Fado (Fairy-Assisted relocations for Decompiled Overlays\n" \ + "Extract relocations from object files and convert them into the format required by Zelda 64 overlays.\n" +#define HELP_EPILOGUE repo + +// clang-format off +static const PosArgInfo posArgInfo[] = { + { "INPUT_FILE", "Every positional argument is an input file, and there should be at least one input file. All inputs are relocatable .o (object) ELF files" }, + { NULL, NULL } +}; + +static const OptInfo optInfo[] = { + { { "make-dependency", required_argument, NULL, 'M' }, "FILE", "Write the output file's Makefile dependencies to FILE" }, + { { "name", required_argument, NULL, 'n' }, "NAME", "Use NAME as the overlay name. Will use the deepest folder name in the input file's path if not specified" }, + { { "output-file", required_argument, NULL, 'o' }, "FILE", "Output to FILE. Will use stdout if none is specified" }, + { { "verbosity", required_argument, NULL, 'v' }, "N", "Verbosity level, one of 0 (None, default), 1 (Info), 2 (Debug)" }, + + { { "help", no_argument, NULL, 'h' }, NULL, "Display this message and exit" }, + { { "version", no_argument, NULL, 'V' }, NULL, "Display version information" }, + + { { NULL, 0, NULL, '\0' }, NULL, NULL }, +}; +// clang-format on + +static size_t posArgCount = ARRAY_COUNT(optInfo); +static size_t optCount = ARRAY_COUNT(optInfo); +static struct option longOptions[ARRAY_COUNT(optInfo)]; + +void ConstructLongOpts() { + size_t i; + + for (i = 0; i < optCount; i++) { + longOptions[i] = optInfo[i].longOpt; + } +} + +int main(int argc, char** argv) { + int opt; + int inputFilesCount; + FILE** inputFiles; + FILE* outputFile = stdout; + char* outputFileName; + char* dependencyFileName = NULL; + char* ovlName = NULL; + + ConstructLongOpts(); + + if (argc < 2) { + printf(USAGE_STRING, argv[0]); + fprintf(stderr, "No input file specified\n"); + return EXIT_FAILURE; + } + + while (true) { + int optionIndex = 0; + + if ((opt = getopt_long(argc, argv, OPTSTR, longOptions, &optionIndex)) == -1) { + break; + } + + switch (opt) { + case 'M': + dependencyFileName = optarg; + break; + + case 'n': + ovlName = optarg; + break; + + case 'o': + outputFileName = optarg; + outputFile = fopen(optarg, "wb"); + if (outputFile == NULL) { + fprintf(stderr, "error: unable to open output file '%s' for writing", optarg); + return EXIT_FAILURE; + } + break; + + case 'v': + if (sscanf(optarg, "%u", &gVerbosity) == 0) { + fprintf(stderr, "warning: verbosity argument '%s' should be a nonnegative decimal integer", optarg); + } + break; + + case 'h': + printf(USAGE_STRING, argv[0]); + Help_PrintHelp(HELP_PROLOGUE, posArgCount, posArgInfo, optCount, optInfo, HELP_EPILOGUE); + return EXIT_FAILURE; + + case 'V': + PrintVersion(); + return EXIT_FAILURE; + + default: + fprintf(stderr, "?? getopt returned character code 0x%X ??\n", opt); + break; + } + } + + FAIRY_INFO_PRINTF("%s", "Options processed\n"); + + { + int i; + + inputFilesCount = argc - optind; + if (inputFilesCount == 0) { + fprintf(stderr, "No input files specified. Exiting.\n"); + return EXIT_FAILURE; + } + + inputFiles = malloc(inputFilesCount * sizeof(FILE*)); + for (i = 0; i < inputFilesCount; i++) { + FAIRY_INFO_PRINTF("Using input file %s\n", argv[optind + i]); + inputFiles[i] = fopen(argv[optind + i], "rb"); + if (inputFiles[i] == NULL) { + fprintf(stderr, "error: unable to open input file '%s' for reading", argv[optind + i]); + return EXIT_FAILURE; + } + } + + FAIRY_INFO_PRINTF("Found %d input file%s\n", inputFilesCount, (inputFilesCount == 1 ? "" : "s")); + + if (ovlName == NULL) { // If a name has not been set using an arg + ovlName = GetOverlayNameFromFilename(argv[optind]); + Fado_Relocs(outputFile, inputFilesCount, inputFiles, ovlName); + free(ovlName); + } else { + Fado_Relocs(outputFile, inputFilesCount, inputFiles, ovlName); + } + + for (i = 0; i < inputFilesCount; i++) { + fclose(inputFiles[i]); + } + free(inputFiles); + if (outputFile != stdout) { + fclose(outputFile); + } + } + + if (dependencyFileName != NULL) { + int fileNameLength = strlen(outputFileName); + char* objectFile = malloc((strlen(outputFileName) + 1) * sizeof(char)); + vc_vector* inputFilesVector = vc_vector_create(inputFilesCount, sizeof(char*), NULL); + char* extensionStart; + FILE* dependencyFile = fopen(dependencyFileName, "w"); + + if (dependencyFile == NULL) { + fprintf(stderr, "error: unable to open dependency file '%s' for writing", dependencyFileName); + return EXIT_FAILURE; + } + + strcpy(objectFile, outputFileName); + extensionStart = strrchr(objectFile, '.'); + if (extensionStart == objectFile + fileNameLength) { + fprintf(stderr, "error: file name should not end in a '.'"); + return EXIT_FAILURE; + } + strcpy(extensionStart, ".o"); + vc_vector_append(inputFilesVector, &argv[optind], inputFilesCount); + + Mido_WriteDependencyFile(dependencyFile, objectFile, inputFilesVector); + + free(objectFile); + vc_vector_release(inputFilesVector); + fclose(dependencyFile); + } + + return EXIT_SUCCESS; +} diff --git a/tools/fado/src/mido.c b/tools/fado/src/mido.c new file mode 100644 index 0000000000..bc5f3ed8a0 --- /dev/null +++ b/tools/fado/src/mido.c @@ -0,0 +1,20 @@ +#include "mido.h" + +#include +#include "macros.h" +#include "vc_vector/vc_vector.h" + +int Mido_WriteDependencyFile(FILE* dependencyFile, const char* relocFile, vc_vector* inputFilesVector) { + char** inputFile; + + fprintf(dependencyFile, "%s:", relocFile); + + VC_FOREACH(inputFile, inputFilesVector) { + fprintf(dependencyFile, " %s", *inputFile); + } + fputs("\n\n", dependencyFile); + VC_FOREACH(inputFile, inputFilesVector) { + fprintf(dependencyFile, "%s:\n\n", *inputFile); + } + return 0; +} diff --git a/tools/fado/src/version.inc b/tools/fado/src/version.inc new file mode 100644 index 0000000000..2b2938d352 --- /dev/null +++ b/tools/fado/src/version.inc @@ -0,0 +1,5 @@ +/* Copyright (C) 2021 Elliptic Ellipsis */ +/* SPDX-License-Identifier: AGPL-3.0-only */ +const char versionNumber[] = "1.1.1"; +const char credits[] = "Written by Elliptic Ellipsis\n Special Thanks: AngheloAlf"; +const char repo[] = "https://github.com/EllipticEllipsis/fado/"; diff --git a/tools/find_unused_asm.sh b/tools/find_unused_asm.sh index 56009ed21b..9c483d0d04 100755 --- a/tools/find_unused_asm.sh +++ b/tools/find_unused_asm.sh @@ -23,18 +23,18 @@ rm old_list.txt cur_list.txt old_data_list.txt data_list.txt list.txt if [ "$1" = "-d" ] then - if [ -s diff.txt ] - then - rm $(cat diff.txt) - fi - rm diff.txt + if [ -s diff.txt ] + then + rm $(cat diff.txt) + fi + rm diff.txt else - if [ -s diff.txt ] - then - cat diff.txt - rm diff.txt - exit 55 - else - rm diff.txt - fi + if [ -s diff.txt ] + then + cat diff.txt + rm diff.txt + exit 55 + else + rm diff.txt + fi fi diff --git a/tools/fix_data_stuff.py b/tools/fix_data_stuff.py index d5c2863fba..17565e7cd6 100644 --- a/tools/fix_data_stuff.py +++ b/tools/fix_data_stuff.py @@ -45,9 +45,9 @@ def main(): spec_text = spec_file.read() spec_text_replaced = re.sub(".*ovl_.*\.o.*\n", handle_actor_line, spec_text) - + with open(root_dir + "spec", "w", newline="\n") as spec_file: spec_file.write(spec_text_replaced) -main() \ No newline at end of file +main() diff --git a/tools/format_s_files.py b/tools/format_s_files.py index ecac74f43d..a0b7b6bf3d 100644 --- a/tools/format_s_files.py +++ b/tools/format_s_files.py @@ -49,7 +49,7 @@ def remove_balign_after_float(file_text): def format_file(file_path): with open(file_path) as f: orig_file_text = f.read() - + file_text = orig_file_text # Condense 2+ empty lines to 1 diff --git a/tools/get_actor_sizes.py b/tools/get_actor_sizes.py index 896030e297..7d62387e10 100755 --- a/tools/get_actor_sizes.py +++ b/tools/get_actor_sizes.py @@ -45,11 +45,11 @@ def count_non_matching(): actor_funcs[f_name] = file_size overlays[actor_dir] = { - "summary": (num_files, max_size, total_size, + "summary": (num_files, max_size, total_size, total_size / num_files), "funcs": actor_funcs } - + return overlays @@ -60,7 +60,7 @@ def count_builded_funcs_and_instructions(f_path): f_lines = "" with open(f_path) as f: f_lines = f.readlines() - + current = "" funcs = {} for line in f_lines: @@ -101,7 +101,7 @@ def count_build(): file_path = os.path.join(ovl_path, f_name) funcs = count_builded_funcs_and_instructions(file_path) - + if len(funcs) > 0: num_files += len(funcs) # round up the file size to a multiple of four. @@ -111,7 +111,7 @@ def count_build(): actor_funcs = {**actor_funcs, **funcs} overlays[actor_dir] = { - "summary": (num_files, max_size, total_size, + "summary": (num_files, max_size, total_size, total_size / num_files), "funcs": actor_funcs } diff --git a/tools/ichaindis.py b/tools/ichaindis.py index 50d909972a..e20fd6e5af 100755 --- a/tools/ichaindis.py +++ b/tools/ichaindis.py @@ -45,7 +45,7 @@ def get_actor_var_names(): if "}" in line: # Reached the end of the actor struct so break out break - + # Parse out the memory address (from the comment) and the variable name regex = r'.*\/\* (.*) \*\/\s+(struct)?\s*.+\s+(.+);.*' actor_var_info = re.match(regex, line) @@ -66,7 +66,7 @@ def main(): parser.add_argument('offset', help='ROM offset or symbol of an InitChain') parser.add_argument('--names', action="store_true", help='Retrieve variable names from the actor struct') args = parser.parse_args() - + # Get the ROM address, if the offset is already a ROM address it will just be returned. args.offset = get_rom_address(args.offset) @@ -101,7 +101,7 @@ def main(): var_name = actor_variable_names[var_name] else: var_name = "unk_" + var_name - + print(' {0}({1}, {2}, {3}),'.format(ICHAIN_MACROS[t], var_name, value, ('ICHAIN_CONTINUE' if cont == 1 else 'ICHAIN_STOP'))) if cont == 0: break diff --git a/tools/ido_recomp/linux/5.3/as1 b/tools/ido_recomp/linux/5.3/as1 index 17ff2aa7c1..41c2545afb 100755 Binary files a/tools/ido_recomp/linux/5.3/as1 and b/tools/ido_recomp/linux/5.3/as1 differ diff --git a/tools/ido_recomp/linux/5.3/cc b/tools/ido_recomp/linux/5.3/cc index 6dbb85eb10..3dcc537985 100755 Binary files a/tools/ido_recomp/linux/5.3/cc and b/tools/ido_recomp/linux/5.3/cc differ diff --git a/tools/ido_recomp/linux/5.3/cfe b/tools/ido_recomp/linux/5.3/cfe index d742f7b2ed..e9594fafcb 100755 Binary files a/tools/ido_recomp/linux/5.3/cfe and b/tools/ido_recomp/linux/5.3/cfe differ diff --git a/tools/ido_recomp/linux/5.3/ugen b/tools/ido_recomp/linux/5.3/ugen index 692086f0ca..b2b662f1d3 100755 Binary files a/tools/ido_recomp/linux/5.3/ugen and b/tools/ido_recomp/linux/5.3/ugen differ diff --git a/tools/ido_recomp/linux/5.3/ujoin b/tools/ido_recomp/linux/5.3/ujoin new file mode 100755 index 0000000000..f9c90b8bec Binary files /dev/null and b/tools/ido_recomp/linux/5.3/ujoin differ diff --git a/tools/ido_recomp/linux/5.3/uld b/tools/ido_recomp/linux/5.3/uld new file mode 100755 index 0000000000..f227222bce Binary files /dev/null and b/tools/ido_recomp/linux/5.3/uld differ diff --git a/tools/ido_recomp/linux/5.3/umerge b/tools/ido_recomp/linux/5.3/umerge new file mode 100755 index 0000000000..00a8281d23 Binary files /dev/null and b/tools/ido_recomp/linux/5.3/umerge differ diff --git a/tools/ido_recomp/linux/5.3/uopt b/tools/ido_recomp/linux/5.3/uopt index 49558be9f8..5afe7a11c1 100755 Binary files a/tools/ido_recomp/linux/5.3/uopt and b/tools/ido_recomp/linux/5.3/uopt differ diff --git a/tools/ido_recomp/linux/5.3/usplit b/tools/ido_recomp/linux/5.3/usplit new file mode 100755 index 0000000000..a1c5ebad62 Binary files /dev/null and b/tools/ido_recomp/linux/5.3/usplit differ diff --git a/tools/ido_recomp/linux/7.1/as1 b/tools/ido_recomp/linux/7.1/as1 index a7bb3adc37..01dbc6f6b4 100755 Binary files a/tools/ido_recomp/linux/7.1/as1 and b/tools/ido_recomp/linux/7.1/as1 differ diff --git a/tools/ido_recomp/linux/7.1/cc b/tools/ido_recomp/linux/7.1/cc index e926b545e1..a7f06afa8a 100755 Binary files a/tools/ido_recomp/linux/7.1/cc and b/tools/ido_recomp/linux/7.1/cc differ diff --git a/tools/ido_recomp/linux/7.1/cfe b/tools/ido_recomp/linux/7.1/cfe index 3a3e983131..2c6767e69d 100755 Binary files a/tools/ido_recomp/linux/7.1/cfe and b/tools/ido_recomp/linux/7.1/cfe differ diff --git a/tools/ido_recomp/linux/7.1/ugen b/tools/ido_recomp/linux/7.1/ugen index e8e875635a..f5c1a2e20c 100755 Binary files a/tools/ido_recomp/linux/7.1/ugen and b/tools/ido_recomp/linux/7.1/ugen differ diff --git a/tools/ido_recomp/linux/7.1/umerge b/tools/ido_recomp/linux/7.1/umerge new file mode 100755 index 0000000000..b0c8c1778b Binary files /dev/null and b/tools/ido_recomp/linux/7.1/umerge differ diff --git a/tools/ido_recomp/linux/7.1/uopt b/tools/ido_recomp/linux/7.1/uopt index fd93d2dc5e..ecf7eab725 100755 Binary files a/tools/ido_recomp/linux/7.1/uopt and b/tools/ido_recomp/linux/7.1/uopt differ diff --git a/tools/ido_recomp/macos/5.3/as1 b/tools/ido_recomp/macos/5.3/as1 index 692fe600c2..0a74078e1c 100755 Binary files a/tools/ido_recomp/macos/5.3/as1 and b/tools/ido_recomp/macos/5.3/as1 differ diff --git a/tools/ido_recomp/macos/5.3/cc b/tools/ido_recomp/macos/5.3/cc index 90ffc74096..5b2a9aa861 100755 Binary files a/tools/ido_recomp/macos/5.3/cc and b/tools/ido_recomp/macos/5.3/cc differ diff --git a/tools/ido_recomp/macos/5.3/cfe b/tools/ido_recomp/macos/5.3/cfe index 753be0d6c7..74a4e9e7c8 100755 Binary files a/tools/ido_recomp/macos/5.3/cfe and b/tools/ido_recomp/macos/5.3/cfe differ diff --git a/tools/ido_recomp/macos/5.3/ugen b/tools/ido_recomp/macos/5.3/ugen index c7020aa493..023e6ebdea 100755 Binary files a/tools/ido_recomp/macos/5.3/ugen and b/tools/ido_recomp/macos/5.3/ugen differ diff --git a/tools/ido_recomp/macos/5.3/ujoin b/tools/ido_recomp/macos/5.3/ujoin new file mode 100755 index 0000000000..2411b4ebec Binary files /dev/null and b/tools/ido_recomp/macos/5.3/ujoin differ diff --git a/tools/ido_recomp/macos/5.3/uld b/tools/ido_recomp/macos/5.3/uld new file mode 100755 index 0000000000..df20250996 Binary files /dev/null and b/tools/ido_recomp/macos/5.3/uld differ diff --git a/tools/ido_recomp/macos/5.3/umerge b/tools/ido_recomp/macos/5.3/umerge new file mode 100755 index 0000000000..b85c401b8d Binary files /dev/null and b/tools/ido_recomp/macos/5.3/umerge differ diff --git a/tools/ido_recomp/macos/5.3/uopt b/tools/ido_recomp/macos/5.3/uopt index e23f6beda8..d9c8ae87b9 100755 Binary files a/tools/ido_recomp/macos/5.3/uopt and b/tools/ido_recomp/macos/5.3/uopt differ diff --git a/tools/ido_recomp/macos/5.3/usplit b/tools/ido_recomp/macos/5.3/usplit new file mode 100755 index 0000000000..7b1fd2af30 Binary files /dev/null and b/tools/ido_recomp/macos/5.3/usplit differ diff --git a/tools/ido_recomp/macos/7.1/as1 b/tools/ido_recomp/macos/7.1/as1 index 358712e331..63159ca666 100755 Binary files a/tools/ido_recomp/macos/7.1/as1 and b/tools/ido_recomp/macos/7.1/as1 differ diff --git a/tools/ido_recomp/macos/7.1/cc b/tools/ido_recomp/macos/7.1/cc index fb68103471..bbd9f49a4f 100755 Binary files a/tools/ido_recomp/macos/7.1/cc and b/tools/ido_recomp/macos/7.1/cc differ diff --git a/tools/ido_recomp/macos/7.1/cfe b/tools/ido_recomp/macos/7.1/cfe index 1e13228628..1e3cb80c3f 100755 Binary files a/tools/ido_recomp/macos/7.1/cfe and b/tools/ido_recomp/macos/7.1/cfe differ diff --git a/tools/ido_recomp/macos/7.1/ugen b/tools/ido_recomp/macos/7.1/ugen index fe90904a43..89f50ec865 100755 Binary files a/tools/ido_recomp/macos/7.1/ugen and b/tools/ido_recomp/macos/7.1/ugen differ diff --git a/tools/ido_recomp/macos/7.1/umerge b/tools/ido_recomp/macos/7.1/umerge new file mode 100755 index 0000000000..e52b6d1025 Binary files /dev/null and b/tools/ido_recomp/macos/7.1/umerge differ diff --git a/tools/ido_recomp/macos/7.1/uopt b/tools/ido_recomp/macos/7.1/uopt index bb68f5d53a..60378f8b2c 100755 Binary files a/tools/ido_recomp/macos/7.1/uopt and b/tools/ido_recomp/macos/7.1/uopt differ diff --git a/tools/migrate-rodata.py b/tools/migrate-rodata.py index e0ed1cc81b..0b5c9e2713 100644 --- a/tools/migrate-rodata.py +++ b/tools/migrate-rodata.py @@ -103,7 +103,7 @@ def is_rodata(r): """ For given asm and rodata files, build a rodata section for the asm file """ -def build_rodata(asm, rodata): +def build_rodata(asm, rodata): contained_syms = [s for s in asm_syms(asm) if s in rodata_syms(rodata)] contained_blocks = [b for b in rodata_blocks(rodata) if rodata_sym(b) in contained_syms] # TODO include arrays in rodata_list @@ -188,7 +188,7 @@ Processes each individual file data\code\ """ def process_file(filename, identifier, delete_rodata): - folder_path = "asm" + sep + "non_matchings" + sep + ("code" + sep if identifier=="code" else "overlays" + sep + identifier.lower() + sep + "ovl_") + filename + sep + folder_path = "asm" + sep + "non_matchings" + sep + ("code" + sep if identifier=="code" else "overlays" + sep + identifier.lower() + sep + "ovl_") + filename + sep rodata_path = "data" + sep + (sep if identifier=="code" else "overlays" + sep + identifier.lower() + sep + "z_") + filename.lower() + ".rodata.s" if filename == "player": folder_path = "asm" + sep + "non_matchings" + sep + "overlays" + sep + "actors" + sep + "ovl_player_actor" + sep @@ -227,7 +227,7 @@ def process_files(filenames, identifier, spechandle, delete_rodata): files = filenames.split(",") for f in files: process_file(f, identifier, delete_rodata) - else: + else: process_file(filenames, identifier, delete_rodata) if spechandle.lower() == "delete": modify_spec(filenames, identifier, True) @@ -294,4 +294,3 @@ run(False) # command = "echo >> src/overlays/effects/ovl_" + effects[i] + "/z_" + effects[i].lower() + ".c" # os.system(command) # purpose of this is to "modify" each C file in order to prevent undefined symbol errors. # # the new line will be removed by format.sh - diff --git a/tools/mkdmadata.c b/tools/mkdmadata.c index 134cdd316a..79fb7d44fc 100644 --- a/tools/mkdmadata.c +++ b/tools/mkdmadata.c @@ -34,7 +34,7 @@ int main(int argc, char **argv) FILE *dmaout; void *spec; size_t size; - + if (argc != 3) { usage(argv[0]); @@ -49,6 +49,7 @@ int main(int argc, char **argv) util_fatal_error("failed to open file '%s' for writing", argv[2]); write_dmadata_table(dmaout); fclose(dmaout); + free_rom_spec(g_segments, g_segmentsCount); free(spec); return 0; diff --git a/tools/mkldscript.c b/tools/mkldscript.c index c8424f8223..2239e864e2 100644 --- a/tools/mkldscript.c +++ b/tools/mkldscript.c @@ -88,7 +88,7 @@ static void write_ld_script(FILE *fout) fprintf(fout, " _%sSegmentDataEnd = .;\n", seg->name); fprintf(fout, " _%sSegmentDataSize = ABSOLUTE( _%sSegmentDataEnd - _%sSegmentDataStart );\n", seg->name, seg->name, seg->name); - + fprintf(fout, " _%sSegmentRoDataStart = .;\n", seg->name); for (j = 0; j < seg->includesCount; j++) @@ -135,7 +135,7 @@ static void write_ld_script(FILE *fout) if (seg->fields & (1 << STMT_increment)) fprintf(fout, " . += 0x%08X;\n", seg->increment); - + fputs(" }\n", fout); //fprintf(fout, " _RomSize += ( _%sSegmentDataEnd - _%sSegmentTextStart );\n", seg->name, seg->name); @@ -227,6 +227,7 @@ int main(int argc, char **argv) write_ld_script(ldout); fclose(ldout); + free_rom_spec(g_segments, g_segmentsCount); free(spec); return 0; diff --git a/tools/msgdis.py b/tools/msgdis.py index 091b16ec0d..823da66705 100644 --- a/tools/msgdis.py +++ b/tools/msgdis.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 -# +# # message_data_static disassembler/decompiler -# +# import re, struct from os import path @@ -129,11 +129,11 @@ colors = { highscores = { 0x00 : "HS_HORSE_ARCHERY", - 0x01 : "HS_POE_POINTS", - 0x02 : "HS_LARGEST_FISH", - 0x03 : "HS_HORSE_RACE", - 0x04 : "HS_MARATHON", - 0x06 : "HS_DAMPE_RACE", + 0x01 : "HS_POE_POINTS", + 0x02 : "HS_LARGEST_FISH", + 0x03 : "HS_HORSE_RACE", + 0x04 : "HS_MARATHON", + 0x06 : "HS_DAMPE_RACE", } def format_char(byte): @@ -195,7 +195,7 @@ def decode(read_bytes, box_type): if byte == ord(ctrl): name = control_codes[ctrl] # single bytes - if (name == "COLOR" or name == "SHIFT" or name == "BOX_BREAK_DELAYED" or + if (name == "COLOR" or name == "SHIFT" or name == "BOX_BREAK_DELAYED" or name == "FADE" or name == "ITEM_ICON" or name == "TEXT_SPEED" or name == "HIGHSCORE"): buf.append("\" " + name + "(") @@ -340,7 +340,7 @@ def dump_all_text(): with open("baserom/ger_message_data_static","rb") as infile: infile.seek(ger_offset) ger_text = fixup_message(decode(infile.read(ger_length), entry[1]).replace("\x00","",-1)) - + fra_offset = segmented_to_physical(entry[5]) fra_length = next_entry[5] - entry[5] with open("baserom/fra_message_data_static","rb") as infile: diff --git a/tools/n64chksum.h b/tools/n64chksum.h index 0ca13a819b..f5b73be49c 100644 --- a/tools/n64chksum.h +++ b/tools/n64chksum.h @@ -1,5 +1,7 @@ -#ifndef _N64CHKSUM_H_ -#define _N64CHKSUM_H_ +#ifndef N64CHKSUM_H +#define N64CHKSUM_H + +#include bool n64chksum_calculate(const uint8_t *romData, int cicType, uint32_t *chksum); diff --git a/tools/namefixer.py b/tools/namefixer.py index 6f4761bcd2..8edb4b7910 100755 --- a/tools/namefixer.py +++ b/tools/namefixer.py @@ -157,9 +157,17 @@ wordReplace = { "ACTIVE_CAM": "GET_ACTIVE_CAM(globalCtx)", "SkinMatrix_SetRotateRPY": "SkinMatrix_SetRotateZYX", "SkinMatrix_SetScaleRotateYRPTranslate": "SkinMatrix_SetScaleRotateYXZTranslate", + "SkinMatrix_SetScaleRotateYXZTranslate": "SkinMatrix_SetTranslateRotateYXZScale", "SkinMatrix_SetRotateRPYTranslate": "SkinMatrix_SetRotateZYXTranslate", + "SkinMatrix_SetRotateZYXTranslate": "SkinMatrix_SetTranslateRotateZYX", "Matrix_RotateRPY": "Matrix_RotateZYX", "Matrix_JointPosition": "Matrix_TranslateRotateZYX", + "func_800D1694": "Matrix_SetTranslateRotateYXZ", + "func_800D1FD4": "Matrix_ReplaceRotation", + "func_800A7EC0": "SkinMatrix_SetRotateAxis", + "func_800D2A34": "Matrix_SetTranslateUniformScaleMtxF", + "func_800D2A98": "Matrix_SetTranslateUniformScaleMtx", + "func_800D2CEC": "Matrix_SetTranslateScaleMtx2", } # [a-zA-Z0-9_] diff --git a/tools/overlayhelpers/filemap.py b/tools/overlayhelpers/filemap.py index c406fdfed3..58dd7e0e40 100644 --- a/tools/overlayhelpers/filemap.py +++ b/tools/overlayhelpers/filemap.py @@ -36,7 +36,7 @@ def CreateAddrLookup(dict, recs, tracer): print(length) recs.append((recs[length-1][1], None, None)) recs = sorted(recs, key=lambda x: x[0], reverse=True) - + for i in range(length): if recs[i][0] != recs[i+1][1]: if tracer != "ra" or recs[i][0] != recs[i+1][1] + 0xFFF & -0x1000: @@ -51,7 +51,7 @@ def CreateTable(): vrecs = [] rrecs = [] vrecs.append((PVA(0x80157D90), PVA(0x80800000), None)) - + dict = { "va" : {}, "ra" : {}, @@ -67,14 +67,14 @@ def CreateTable(): vrecs.append(vrec) dict["ft"][li[7]] = (rrec[0], rrec[1]) file = None - + with open("filetable2.txt", "r") as file: for line in file: li = line.rstrip().split('\t') rrec = (int(li[2],16), int(li[3],16), li[5]) rrecs.append(rrec) dict["ft"][li[5]] = (rrec[0], rrec[1]) - + CreateAddrLookup(dict["va"], vrecs, "va") CreateAddrLookup(dict["ra"], rrecs, "ra") @@ -85,7 +85,7 @@ def AddressLookup(lookupTable, addr): start = 0; end = 0; key = None; - + for k, v in lookupTable.items(): if addr >= k: start = k @@ -93,13 +93,13 @@ def AddressLookup(lookupTable, addr): break end = k return (key, start, end) - + def GetFromVRam(addr): key, vramStart, vramEnd = AddressLookup(table["va"], PVA(addr)) - + if key is None: return None - + ftl = table["ft"][key] vrom = AddrRange(ftl[0], ftl[1]) vram = AddrRange(UVA(vramStart), UVA(vramEnd)) @@ -107,13 +107,13 @@ def GetFromVRam(addr): offset = addr - vram.start return FileResult(key, vrom, vram, offset) - + def GetFromRom(addr): key, romStart, romEnd = AddressLookup(table["ra"], addr) - + if key is None: return None - + vrom = AddrRange(romStart, romEnd) offset = addr - vrom.start diff --git a/tools/overlayhelpers/lmapmark.py b/tools/overlayhelpers/lmapmark.py index 3b5c9ddc25..5075bcae83 100644 --- a/tools/overlayhelpers/lmapmark.py +++ b/tools/overlayhelpers/lmapmark.py @@ -69,7 +69,7 @@ def IND(n): scriptDir = os.path.dirname(os.path.realpath(__file__)) -repo = scriptDir + os.sep + ".." + os.sep + ".." +repo = scriptDir + os.sep + ".." + os.sep + ".." kaleido_scope_data = [] diff --git a/tools/overlayhelpers/mapmark.py b/tools/overlayhelpers/mapmark.py index 8cc91ae771..8f0186bf9f 100644 --- a/tools/overlayhelpers/mapmark.py +++ b/tools/overlayhelpers/mapmark.py @@ -110,7 +110,7 @@ for i in range(NUM_SCENES): cstr = HEADER for scenemap in scenemaps: - cstr += f"MapMarkData {GetDungeonSymbol(scenemap[0])}[] = {{\n" + cstr += f"MapMarkData {GetDungeonSymbol(scenemap[0])}[] = {{\n" for mapId, map in enumerate(scenemap[1]): cstr += IND(1) + f"// {GetDungeonName(scenemap[0])} minimap {mapId}\n" cstr += IND(1) + "{\n" @@ -130,7 +130,7 @@ for scenemap in scenemaps: cstr += "MapMarkData* gMapMarkDataTable[] = {\n" for scenemap in scenemaps: - cstr += f" {GetDungeonSymbol(scenemap[0])},\n" + cstr += f" {GetDungeonSymbol(scenemap[0])},\n" cstr += "};\n" with open(sys.argv[1], "w") as file: diff --git a/tools/regconvert.py b/tools/regconvert.py index 48132422dc..747b6a8473 100755 --- a/tools/regconvert.py +++ b/tools/regconvert.py @@ -42,7 +42,7 @@ def read_file(filename): file_contents = file_contents[end:] match = pattern.search(file_contents) - + parsed_contents += file_contents return parsed_contents @@ -81,7 +81,7 @@ def main(): else: write_file(filename, contents) else: - index = parse_number(args.index, args.hex) + index = parse_number(args.index, args.hex) if args.offset: offset = index if not check_valid_offset(offset): diff --git a/tools/reloc_prereq.c b/tools/reloc_prereq.c new file mode 100644 index 0000000000..ea117f12ef --- /dev/null +++ b/tools/reloc_prereq.c @@ -0,0 +1,89 @@ +#include +#include +#include +#include + +#include "spec.h" +#include "util.h" + +void print_usage(char* prog_name) { + printf("USAGE: %s SPEC OVERLAY_SEGMENT_NAME\n" + "Search the preprocessed SPEC for an overlay segment name, \n" + "e.g. \"ovl_En_Firefly\", and return a space-separated list of the files it\n" + "includes. The relocation file must be the last include in the segment\n" + "OVERLAY_SEGMENT_NAME, and have the filename \"OVERLAY_SEGMENT_NAME_reloc.o\",\n" + "but can be in a different directory from the other files.\n", + prog_name); +} + +int main(int argc, char** argv) { + char* spec_path; + char* overlay_name; + char* spec; + size_t size; + Segment segment; + int exit_status = 0; + bool segmentFound = false; + + if (argc != 3) { + print_usage(argv[0]); + return 1; + } + + spec_path = argv[1]; + overlay_name = argv[2]; + + // printf("spec path: %s\n", spec_path); + // printf("overlay name: %s\n", overlay_name); + + spec = util_read_whole_file(spec_path, &size); + segmentFound = get_single_segment_by_name(&segment, spec, overlay_name); + + if (!segmentFound) { + fprintf(stderr, ERRMSG_START "no segment \"%s\" found\n" ERRMSG_END, overlay_name); + goto error_out; + } + + { + size_t overlay_name_length; + const char* reloc_suffix = "_reloc.o"; + char* expected_filename; + + /* Relocation file must be the last `include` (so .ovl section is linked last) */ + if (strstr(segment.includes[segment.includesCount - 1].fpath, reloc_suffix) == NULL) { + fprintf(stderr, ERRMSG_START "last include in overlay segment \"%s\" is not a `%s` file\n" ERRMSG_END, + overlay_name, reloc_suffix); + goto error_out; + } + + overlay_name_length = strlen(overlay_name); + expected_filename = malloc(overlay_name_length + strlen(reloc_suffix) + 1); + strcpy(expected_filename, overlay_name); + strcat(expected_filename, reloc_suffix); + + if (strstr(segment.includes[segment.includesCount - 1].fpath, expected_filename) == NULL) { + fprintf(stderr, ERRMSG_START "Relocation file \"%s\" should have filename \"%s\"\n" ERRMSG_END, + segment.includes[segment.includesCount - 1].fpath, expected_filename); + goto error_out; + } + free(expected_filename); + } + { + int i; + /* Skip `_reloc.o` include */ + for (i = 0; i < segment.includesCount - 1; i++) { + printf("%s ", segment.includes[i].fpath); + } + putchar('\n'); + } + + if (0) { + error_out: + exit_status = 1; + } + + free_single_segment_elements(&segment); + free(spec); + + return exit_status; +} diff --git a/tools/spec.c b/tools/spec.c index 06e0f6a808..6a901a8300 100644 --- a/tools/spec.c +++ b/tools/spec.c @@ -140,6 +140,101 @@ static const char *const stmtNames[] = [STMT_pad_text] = "pad_text", }; +STMTId get_stmt_id_by_stmt_name(const char *stmtName, int lineNum) { + STMTId stmt; + + for (stmt = 0; stmt < ARRAY_COUNT(stmtNames); stmt++) { + if (strcmp(stmtName, stmtNames[stmt]) == 0) + return stmt; + } + util_fatal_error("line %i: unknown statement '%s'", lineNum, stmtName); + return -1; +} + +bool parse_segment_statement(struct Segment *currSeg, STMTId stmt, char* args, int lineNum) { + // ensure no duplicates (except for 'include' or 'pad_text') + if (stmt != STMT_include && stmt != STMT_include_data_with_rodata && stmt != STMT_pad_text && + (currSeg->fields & (1 << stmt))) + util_fatal_error("line %i: duplicate '%s' statement", lineNum, stmtNames[stmt]); + + currSeg->fields |= 1 << stmt; + + // statements valid within a segment definition + switch (stmt) + { + case STMT_beginseg: + util_fatal_error("line %i: '%s' inside of a segment definition", lineNum, stmtNames[stmt]); + break; + case STMT_endseg: + // verify segment data + if (currSeg->name == NULL) + util_fatal_error("line %i: no name specified for segment", lineNum); + if (currSeg->includesCount == 0) + util_fatal_error("line %i: no includes specified for segment", lineNum); + return true; + break; + case STMT_name: + if (!parse_quoted_string(args, &currSeg->name)) + util_fatal_error("line %i: invalid name", lineNum); + break; + case STMT_after: + if (!parse_quoted_string(args, &currSeg->after)) + util_fatal_error("line %i: invalid name for 'after'", lineNum); + break; + case STMT_address: + if (!parse_number(args, &currSeg->address)) + util_fatal_error("line %i: expected number after 'address'", lineNum); + break; + case STMT_number: + if (!parse_number(args, &currSeg->number)) + util_fatal_error("line %i: expected number after 'number'", lineNum); + break; + case STMT_flags: + if (!parse_flags(args, &currSeg->flags)) + util_fatal_error("line %i: invalid flags", lineNum); + break; + case STMT_align: + if (!parse_number(args, &currSeg->align)) + util_fatal_error("line %i: expected number after 'align'", lineNum); + if (!is_pow_of_2(currSeg->align)) + util_fatal_error("line %i: alignment is not a power of two", lineNum); + break; + case STMT_romalign: + if (!parse_number(args, &currSeg->romalign)) + util_fatal_error("line %i: expected number after 'romalign'", lineNum); + if (!is_pow_of_2(currSeg->romalign)) + util_fatal_error("line %i: alignment is not a power of two", lineNum); + break; + case STMT_include: + case STMT_include_data_with_rodata: + currSeg->includesCount++; + currSeg->includes = realloc(currSeg->includes, currSeg->includesCount * sizeof(*currSeg->includes)); + + if (!parse_quoted_string(args, &currSeg->includes[currSeg->includesCount - 1].fpath)) + util_fatal_error("line %i: invalid filename", lineNum); + + currSeg->includes[currSeg->includesCount - 1].linkerPadding = 0; + currSeg->includes[currSeg->includesCount - 1].dataWithRodata = (stmt == STMT_include_data_with_rodata); + break; + case STMT_increment: + if (!parse_number(args, &currSeg->increment)) + util_fatal_error("line %i: expected number after 'increment'", lineNum); + break; + case STMT_pad_text: + currSeg->includes[currSeg->includesCount - 1].linkerPadding += 0x10; + break; + default: + fprintf(stderr, "warning: '%s' is not implemented\n", stmtNames[stmt]); + break; + } + return false; +} + +/** + * `segments` should be freed with `free_rom_spec` after use. + * Will write to the contents of `spec` to introduce string terminating '\0's. + * `segments` also contains pointers to inside `spec`, so `spec` should not be freed before `segments` + */ void parse_rom_spec(char *spec, struct Segment **segments, int *segment_count) { int lineNum = 1; @@ -161,90 +256,13 @@ void parse_rom_spec(char *spec, struct Segment **segments, int *segment_count) if (line[0] != 0 && stmtName[0] != 0) { char *args = token_split(stmtName); - unsigned int stmt; - - for (stmt = 0; stmt < ARRAY_COUNT(stmtNames); stmt++) - if (strcmp(stmtName, stmtNames[stmt]) == 0) - goto got_stmt; - util_fatal_error("line %i: unknown statement '%s'", lineNum, stmtName); - got_stmt: + STMTId stmt = get_stmt_id_by_stmt_name(stmtName, lineNum); if (currSeg != NULL) { - // ensure no duplicates (except for 'include' or 'pad_text') - if (stmt != STMT_include && stmt != STMT_include_data_with_rodata && stmt != STMT_pad_text && - (currSeg->fields & (1 << stmt))) - util_fatal_error("line %i: duplicate '%s' statement", lineNum, stmtName); - - currSeg->fields |= 1 << stmt; - - // statements valid within a segment definition - switch (stmt) - { - case STMT_beginseg: - util_fatal_error("line %i: '%s' inside of a segment definition", lineNum, stmtName); - break; - case STMT_endseg: - // verify segment data - if (currSeg->name == NULL) - util_fatal_error("line %i: no name specified for segment", lineNum); - if (currSeg->includesCount == 0) - util_fatal_error("line %i: no includes specified for segment", lineNum); + bool segmentEnded = parse_segment_statement(currSeg, stmt, args, lineNum); + if (segmentEnded) { currSeg = NULL; - break; - case STMT_name: - if (!parse_quoted_string(args, &currSeg->name)) - util_fatal_error("line %i: invalid name", lineNum); - break; - case STMT_after: - if (!parse_quoted_string(args, &currSeg->after)) - util_fatal_error("line %i: invalid name for 'after'", lineNum); - break; - case STMT_address: - if (!parse_number(args, &currSeg->address)) - util_fatal_error("line %i: expected number after 'address'", lineNum); - break; - case STMT_number: - if (!parse_number(args, &currSeg->number)) - util_fatal_error("line %i: expected number after 'number'", lineNum); - break; - case STMT_flags: - if (!parse_flags(args, &currSeg->flags)) - util_fatal_error("line %i: invalid flags", lineNum); - break; - case STMT_align: - if (!parse_number(args, &currSeg->align)) - util_fatal_error("line %i: expected number after 'align'", lineNum); - if (!is_pow_of_2(currSeg->align)) - util_fatal_error("line %i: alignment is not a power of two", lineNum); - break; - case STMT_romalign: - if (!parse_number(args, &currSeg->romalign)) - util_fatal_error("line %i: expected number after 'romalign'", lineNum); - if (!is_pow_of_2(currSeg->romalign)) - util_fatal_error("line %i: alignment is not a power of two", lineNum); - break; - case STMT_include: - case STMT_include_data_with_rodata: - currSeg->includesCount++; - currSeg->includes = realloc(currSeg->includes, currSeg->includesCount * sizeof(*currSeg->includes)); - - if (!parse_quoted_string(args, &currSeg->includes[currSeg->includesCount - 1].fpath)) - util_fatal_error("line %i: invalid filename", lineNum); - - currSeg->includes[currSeg->includesCount - 1].linkerPadding = 0; - currSeg->includes[currSeg->includesCount - 1].dataWithRodata = (stmt == STMT_include_data_with_rodata); - break; - case STMT_increment: - if (!parse_number(args, &currSeg->increment)) - util_fatal_error("line %i: expected number after 'increment'", lineNum); - break; - case STMT_pad_text: - currSeg->includes[currSeg->includesCount - 1].linkerPadding += 0x10; - break; - default: - fprintf(stderr, "warning: '%s' is not implemented\n", stmtName); - break; } } else @@ -271,6 +289,70 @@ void parse_rom_spec(char *spec, struct Segment **segments, int *segment_count) } } +/** + * @brief Parses the spec, looking only for the segment with the name `segmentName`. + * Returns true if the segment was found, false otherwise + * + * @param[out] dstSegment The Segment to be filled. Will only contain the data of the searched segment, or garbage if the segment was not found. dstSegment must be previously allocated, a stack variable is recommended + * @param[in,out] spec A null-terminated string containing the whole spec file. This string will be modified by this function + * @param[in] segmentName The name of the segment being searched + */ +bool get_single_segment_by_name(struct Segment* dstSegment, char *spec, const char *segmentName) { + bool insideSegment = false; + int lineNum = 1; + char *line = spec; + + memset(dstSegment, 0, sizeof(struct Segment)); + + // iterate over lines + while (line[0] != '\0') { + char *nextLine = line_split(line); + char* stmtName = skip_whitespace(line); + + if (stmtName[0] != '\0') { + char *args = token_split(stmtName); + STMTId stmt = get_stmt_id_by_stmt_name(stmtName, lineNum); + + if (insideSegment) { + bool segmentEnded = parse_segment_statement(dstSegment, stmt, args, lineNum); + + if (stmt == STMT_name) { + if (strcmp(segmentName, dstSegment->name) != 0) { + // Not the segment we are looking for + insideSegment = false; + } + } else if (segmentEnded) { + return true; + } + } else { + if (stmt == STMT_beginseg) { + insideSegment = true; + if (dstSegment->includes != NULL) { + free(dstSegment->includes); + } + memset(dstSegment, 0, sizeof(struct Segment)); + } + } + } + + line = nextLine; + lineNum++; + } + + return false; +} + +/** + * @brief Frees the elements of the passed Segment. Will not free the pointer itself + * + * @param segment + */ +void free_single_segment_elements(struct Segment *segment) { + if (segment->includes != NULL) { + free(segment->includes); + } +} + void free_rom_spec(struct Segment *segments, int segment_count) { int i; diff --git a/tools/spec.h b/tools/spec.h index 9f2164fd7b..f87f83ec80 100644 --- a/tools/spec.h +++ b/tools/spec.h @@ -1,8 +1,10 @@ -#ifndef _SPEC_H_ -#define _SPEC_H_ +#ifndef SPEC_H +#define SPEC_H -enum -{ +#include +#include + +typedef enum { STMT_address, STMT_after, STMT_align, @@ -18,27 +20,24 @@ enum STMT_stack, STMT_increment, STMT_pad_text, -}; +} STMTId; -enum -{ +enum { FLAG_BOOT = (1 << 0), FLAG_OBJECT = (1 << 1), FLAG_RAW = (1 << 2), }; -struct Include -{ - char *fpath; +struct Include { + char* fpath; int linkerPadding; uint8_t dataWithRodata; }; -struct Segment -{ +typedef struct Segment { uint32_t fields; - char *name; - char *after; + char* name; + char* after; uint32_t flags; uint32_t address; uint32_t stack; @@ -47,12 +46,16 @@ struct Segment uint32_t increment; uint32_t entry; uint32_t number; - struct Include *includes; + struct Include* includes; int includesCount; -}; +} Segment; -void parse_rom_spec(char *spec, struct Segment **segments, int *segment_count); +void parse_rom_spec(char* spec, struct Segment** segments, int* segment_count); -void free_rom_spec(struct Segment *segments, int segment_count); +bool get_single_segment_by_name(struct Segment* dstSegment, char *spec, const char *segmentName); + +void free_single_segment_elements(struct Segment *segment); + +void free_rom_spec(struct Segment* segments, int segment_count); #endif diff --git a/tools/specprocess.py b/tools/specprocess.py index 234ea4bd29..082c21f24d 100644 --- a/tools/specprocess.py +++ b/tools/specprocess.py @@ -52,4 +52,4 @@ for i in range(0, len(specLines)): specOut = open("build/spec_preproc", "w"); specOut.writelines(specLines); -specOut.close(); \ No newline at end of file +specOut.close(); diff --git a/tools/split_out_overlay_funcs.py b/tools/split_out_overlay_funcs.py index 691763bc23..c95457ac7a 100644 --- a/tools/split_out_overlay_funcs.py +++ b/tools/split_out_overlay_funcs.py @@ -23,7 +23,7 @@ def handle_file(asm_root, asm_file, c_file_path): file_path = os.path.join(asm_root, asm_file) with open(file_path) as f: file_lines = f.readlines() - + new_files = [] num_rodata = 0 for i, line in enumerate(file_lines): @@ -53,10 +53,10 @@ def handle_file(asm_root, asm_file, c_file_path): new_file_lines = file_lines[new_file[0]:new_files[i+1][0]] else: new_file_lines = file_lines[new_file[0]:] - + with open(os.path.join(asm_root, new_file[1]), mode="w", newline="\n") as out_file: out_file.writelines(new_file_lines) - + os.remove(c_file_path) pragma_begin = "#pragma GLOBAL_ASM(\"" + asm_root.split("../")[1] + "/" diff --git a/tools/util.c b/tools/util.c index e826906cd3..824e089e07 100644 --- a/tools/util.c +++ b/tools/util.c @@ -12,18 +12,18 @@ void util_fatal_error(const char *msgfmt, ...) { va_list args; - fputs("error: ", stderr); + fputs(ERRMSG_START, stderr); va_start(args, msgfmt); vfprintf(stderr, msgfmt, args); va_end(args); - fputc('\n', stderr); + fputs(ERRMSG_END "\n", stderr); exit(1); } -// reads a whole file into memory, and returns a pointer to the data +// reads a whole file into memory, and returns a malloc'd pointer to the data. void *util_read_whole_file(const char *filename, size_t *pSize) { FILE *file = fopen(filename, "rb"); @@ -59,13 +59,13 @@ void *util_read_whole_file(const char *filename, size_t *pSize) void util_write_whole_file(const char *filename, const void *data, size_t size) { FILE *file = fopen(filename, "wb"); - + if (file == NULL) util_fatal_error("failed to open file '%s' for writing: %s", filename, strerror(errno)); if (fwrite(data, size, 1, file) != 1) util_fatal_error("error writing to file '%s': %s", filename, strerror(errno)); - + fclose(file); } diff --git a/tools/util.h b/tools/util.h index e34800a193..ed692bf53d 100644 --- a/tools/util.h +++ b/tools/util.h @@ -1,5 +1,12 @@ -#ifndef _UTIL_H_ -#define _UTIL_H_ +#ifndef UTIL_H +#define UTIL_H + +#include +#include +#include + +#define ERRMSG_START "\x1b[91merror\x1b[97m: " +#define ERRMSG_END "\x1b[0m" #ifdef __GNUC__ __attribute__((format(printf, 1, 2), noreturn)) diff --git a/tools/vt_fmt.py b/tools/vt_fmt.py index f278f826c9..e0929ff8be 100755 --- a/tools/vt_fmt.py +++ b/tools/vt_fmt.py @@ -15,8 +15,6 @@ COLORS = [ 'PURPLE', 'CYAN', 'WHITE', - 'LIGHTGRAY', - 'DARKGRAY', ] def re_match(exp, text): @@ -39,11 +37,11 @@ def vt_fmt(text): code = text[i:text.find('m', i)] i += len(code) - if re_match('^4[0-9];3[0-9]$', code): + if re_match('^4[0-7];3[0-7]$', code): chars += 'VT_COL(' + COLORS[int(code[1])] + ', ' + COLORS[int(code[4])] + ')' - elif re_match('^4[0-9]$', code): + elif re_match('^4[0-7]$', code): chars += 'VT_BGCOL(' + COLORS[int(code[1])] + ')' - elif re_match('^3[0-9]$', code): + elif re_match('^3[0-7]$', code): chars += 'VT_FGCOL(' + COLORS[int(code[1])] + ')' elif len(code) == 0: chars += 'VT_RST' @@ -59,7 +57,7 @@ def vt_fmt(text): i += 1 - + if curLiteral: chars += '\"' @@ -70,7 +68,7 @@ def main(): parser = argparse.ArgumentParser(description='Properly formats VT macros') parser.add_argument('string', help='String to format') args = parser.parse_args() - + print(vt_fmt(args.string)) diff --git a/tools/vtxdis.c b/tools/vtxdis.c index 495d7cea9d..86a8d0b2a4 100644 --- a/tools/vtxdis.c +++ b/tools/vtxdis.c @@ -37,7 +37,7 @@ static const struct option cmdline_opts[] = { static uint32_t parse_int(const char *num){ uint32_t ret; char outnum[21]; - + if(strlen(num) > 2 && num[0] == '0' && (num[1] == 'x' || num[1] == 'X')) { strncpy(outnum, &num[2], 20); sscanf(outnum, "%"SCNx32, &ret); diff --git a/undefined_syms.txt b/undefined_syms.txt index 9dd0496ead..8f48e9e1bc 100644 --- a/undefined_syms.txt +++ b/undefined_syms.txt @@ -50,31 +50,9 @@ D_A4800004 = 0xA4800004; // SI_PIF_ADDR_RD64B_REG D_A4800010 = 0xA4800010; // SI_PIF_ADDR_WR64B_REG D_A4800018 = 0xA4800018; // SI_STATUS_REG -// until ZAPD can handle non-aligned textures, -// we can't use the built assets tied to some symbols -gKm1Skel = 0x060000F0; -gKw1Skel = 0x060000F0; -object_ahg_Skel_0000F0 = 0x060000F0; -object_bji_Skel_0000F0 = 0x060000F0; -object_boj_Skel_0000F0 = 0x060000F0; - -// z_player_lib -D_06025218 = 0x06025218; -D_060252D8 = 0x060252D8; -D_06025438 = 0x06025438; -D_06025598 = 0x06025598; -D_06025658 = 0x06025658; -D_060257B8 = 0x060257B8; -D_0602A738 = 0x0602A738; -D_0602CB48 = 0x0602CB48; - // z_kankyo, z_demo_kankyo, z_en_viewer, z_object_kankyo, z_eff_ss_dead_dd D_01000000 = 0x01000000; -// z_arms_hook -D_0602B288 = 0x0602B288; -D_0602AFF0 = 0x0602AFF0; - // code_800AD920 D_0E000000 = 0x0E000000;