A traditional PalmOS emulator requires a ROM: a binary object that contains the original PalmOS compiled and linked for the 68K architecture. When you run an application PRC in those emulators, everything is emulated down to the hardware layer, so the ROM thinks it is talking to an actual device. Therefore, as an emulator developer, your job is to provide an implementation of the CPU, memory, display, serial port, and so on, taking into accounting the low level differences between the myriad of devices that ran PalmOS back then. As long as your implementation of the physical layer is accurate, applications will generally run fine.
PumpkinOS also allows you to run binary 68K applications, but do not require a copyrighted PalmOS ROM. The short story is this: the developers of PalmOS devised a clever way to implement system calls (also used in other 68K systems, I think). They used a feature of the 68K CPU called trap. A trap is like a subroutine call, but instead of jumping to a different memory addresses depending on the system call, it jumps to a fixed address, passing an argument identifying the system call. PumpkinOS takes advantage of this fact and, whenever a trap is issued, it intercepts the execution flow, identifies the system call, extract the parameters and calls a native implementation inside PumpkinOS, bypassing a ROM altogether. It is very similar to the way PACE (Palm Application Compatibility Environment) was implemented when PalmOS 5 was introduced. If the 68K application plays by the rules and only calls the OS through system traps, never accessing hardware directly, it will also run fine on PumpkinOS. Now, if you want to know the long version of this story, keep reading.
Even more details about the inner-workings of PumpkinOS.