{"id":22295856,"url":"https://github.com/meithecatte/mips-quine","last_synced_at":"2025-03-25T22:34:11.204Z","repository":{"id":173771528,"uuid":"651271984","full_name":"meithecatte/mips-quine","owner":"meithecatte","description":"MIPS Quine that disassembles its own code and parses its own ELF symbol table","archived":false,"fork":false,"pushed_at":"2023-06-08T22:20:09.000Z","size":16,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-30T19:49:13.172Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Assembly","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/meithecatte.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-06-08T22:17:48.000Z","updated_at":"2024-07-05T13:12:35.000Z","dependencies_parsed_at":null,"dependency_job_id":"359098e1-5282-408d-a17f-68437356261e","html_url":"https://github.com/meithecatte/mips-quine","commit_stats":null,"previous_names":["meithecatte/mips-quine"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meithecatte%2Fmips-quine","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meithecatte%2Fmips-quine/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meithecatte%2Fmips-quine/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/meithecatte%2Fmips-quine/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/meithecatte","download_url":"https://codeload.github.com/meithecatte/mips-quine/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":245555901,"owners_count":20634814,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-12-03T17:43:21.622Z","updated_at":"2025-03-25T22:34:11.114Z","avatar_url":"https://github.com/meithecatte.png","language":"Assembly","funding_links":[],"categories":[],"sub_categories":[],"readme":"# MIPS quine\n\nA quine is a program that prints its own source code. This one accomplishes this\nby disassembling itself.\n\n```\n$ mips-linux-gnu-gcc -static -fno-pic -mno-abicalls -nostdlib quine.S -o quine\n$ qemu-mips ./quine | head\n.global __start\n.set noreorder\n\n__start:\n    la $a1, s0\n    jal zstr\n    addu $0, $0, $0\n\n    la $t0, __executable_start\n    lw $t1, 32($t0)\n$ diff \u003c(qemu-mips ./quine) quine.S\n$\n```\n\n## why?\n\nIt [seemed more enticing than going to sleep][nerdsnipe].\n\n## how do you handle labels?\n\nIt parses its own ELF headers and walks its own symbol table.\n\n## what's with the cryptic label names?\n\nIf the binary goes over 4 KiB, the symbol table lands in a part of the file that\ndoesn't get mapped. The easiest way to work around this was to golf it down.\nIt even was a fun challenge to make it fit. I could probably open the executable\nand map it into memory, but that seems really finicky.\n\n## Trivia\n\n- The code assumes that a `lui` instruction is always part of the assembler's\n  expansion of `la` and blindly reads out the literal field of the following\n  `addiu` without checking whether it's actually an `addiu`. This is fine,\n  as we only need to handle the situations that occur in our code.\n- The disassembler is table driven, with each entry in the table consisting\n  of a single byte, followed by the opcode name as a null-terminated string.\n  The single byte holds 6 bits to identify the opcode, and 2 bits to describe\n  how the operands should get decoded.\n\n  This became a problem when the `jr` instruction called for a 5th operand mode\n  in the R-encoding table. Instead of handling this properly, I just made\n  the instruction always decode as `jr $ra`, by having `\"jr $ra\"` be the name\n  of the opcode. It's not like anything else occurs in the quine's code.\n- To avoid writing a separate routine for printing out the tables that drive\n  the disassembler, I encode the opcode bytes using octal escapes. It's hideous,\n  but it gets the job done.\n- MIPS register names are mere suggestions. \"Caller-saved registers\"? That sounds\n  like a global variable to me. \"Function arguments are passed through `$a0-$a3`\"?\n  Sometimes you just don't feel like it and use `$t0`. Sometimes the only argument\n  goes through `$a1`, skipping `$a0` entirely. I plead code golf.\n\n## Closing remarks\n\nmeow!! ^_^ :3\n\n[nerdsnipe]: https://xkcd.com/356/\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeithecatte%2Fmips-quine","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmeithecatte%2Fmips-quine","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmeithecatte%2Fmips-quine/lists"}