Incidentally, the way we made save states endian-safe in Atari800 code base was to create serialization functions for all the fundamental data types (anything larger than a byte), which involved simply saving the low byte, shifting, saving again, etc. Since shifts are endian agnostic it works fine. You have to agree on a size for some types that may differ, like int - a natural choice is 4 - and if the native platform has a wider representation than that you have to save off the sign bit. When you read it in just read byte1, byte2, byte3, byte4 and value = (byte4 << 24) | (byte3 << 16) | (byte2 << 😎 | byte1 as an example.
You don't have to do this for general memory of course in the emulated machine, as that's all emulated and should be the same regardless of architecture, you just have to do it for all of your native variables - pointers, counters and the like - that exist in the host emulator.
It's cumbersome but completely doable. Helps when you are C++ as you have a lot more robust serialization support in the language, but it's doable even in C (which is what Atari800 is).