Application code portability is really just the tip of the iceberg. Small, embedded microcontroller-based applications may run alone, but anything bigger uses an operating system. Large applications include even more baggage, from middleware to runtime libraries. Yet without these, the system can't run.
Bringing support code to a new platform can be as easy as porting an application, depending on the technology employed. Obviously, source-code migration requires the support code's source. The process is definitely easier in the embedded space, where licensing of third-party products includes source code. However, that code is frequently unavailable.
Debugging can be a problem without support source code, when other techniques like virtual machines or machine-code translation are used. Target platforms can induce errors due to compatibility. So finding the cause and generating a solution for an error can be very difficult if the error is outside of the application, but present in the support code, as the code interacts with the application.
Porting becomes even more complex when support code on the target is a mix of migrated and target code. This is typical of a system that employs a different operating system on the target that has a facade, to provide an interface comparable to the original operating system.