In the modern era, I feel like ROMhacking is almost "obsolete" as a pursuit. By bit-twiddling a ROM image file, you're effectively forced to work within the constraints of an arbitrary static-linked memory-map generated by a linker decades ago to suit the precise needs of the particular assembler source fed in at the time (and the needs of the ROM chip that said source would be burned onto.)

IMHO, with the tools we have available today, it makes much more sense to not directly hack on ROM images themselves, but rather to first disassemble the ROM; to factor the produced assembly into modules; to reverse the assembler data constant sections into separate named resource files, with a Makefile that converts them back; and so forth. At each step, with each change to increase legibility, you ensure that typing `make` continues to reproduce the original ROM image byte for byte.

We've done this enough times now (e.g. https://github.com/pret/pokered et al) that the process is now as well-documented and tooling-supported as the process of hacking directly on ROMs is. With these tools, this reversing process is effectively no additional work over that required to develop a complete understanding of what the original game's ROM "says" — which you'd need to do either way. (Just, in the case of ROMhacking, the output of that understanding process are messy rambling docs, rather than an annotated ASM codebase under version control.)

Once you have a source repo containing a clean, original-ROM-reproducing disassembly, you can then fork that repo, and develop any "hacks" you like on top of it, with a regular IDE and cross-compile toolchain. At this level, you don't have to worry about overrunning allocated strings-sections, rewriting pointers, patching subroutines with jumps because there's no room left at the call-site, etc. The assembler and linker handle all that, and sort+fixup all the symbols and entries after knowing how big they are. (There's also nothing† stopping you from just bumping up your target ROM image size if you run out of headroom.)

If you do go through this reversing process on your way to producing a hack, then as a side-benefit, you'll have also produced an artifact (the clean disassembly) that documents the original game for anyone who wants it, e.g. people who want to know how the game's algorithms work to build speedrunning tools; people who want to learn old programming techniques lost to time; people who want to conserve the game by porting it to new platforms; etc.

And, of course, you make it far easier for anyone who comes after you to also produce hacks. They don't have to go through the reversing process; they can just start with your clean disassembly code. (That "anyone else" also includes "future you who might want to come back and finish a years-old hack, and has forgotten how this all worked!")

If you're a programmer, and you feel drawn to make ROMhacks, you should reverse-engineer the source game first, if it hasn't been already. It benefits you now; it benefits you later; it benefits the community. When you reverse an old game, everybody wins.

-----

† Well, okay, maybe you'll be limited by the fact that the system architecture only has an address-space so large, and the original game as written was small enough that it didn't use banking, but upon expanding it you now need to use banking. That's a hurdle, but not an insurmountable one... unless the system didn't even support banking. (Are there any systems that didn't?)