If these are truly separate programs - i.e. both have a main()
entry point then they clearly cannot be in a single binary generated by the linker. However you can combine two separately linked programs in different address spaces into a single image file using a tool such as srec_cat. This is best done with a format that includes address information such as Intel Hex (otherwise for raw binary you would need padding between the two images, and tell the programmer the start address):
srec_cat -Output combined.hex -Intel program1.hex -Intel program2.hex -Intel
srec_cat
is capable of combining multiple formats and can specify address offsets for input that does not include location information.
If your toolchain is not generating relocatable executables, you cannot arbitrarily locate the program at any particular offset. Generally you would specify memory map to the linker, and build the two separate programs in different memory spaces. That way you can simply combine them with srec_cat
as described.
You should be aware that separately linked executables each have their own runtime start-up code, vector table and hardware initialisation. Switching programs arbitrarily is not always straightforward. The hardware initialisation may for example assume that the hardware is in the reset state but the preceding program has made that untrue. You need to at least disable interrupts before starting the second program, otherwise if an interrupt occurs before the second application has set up the vector table, the interrupt handler of the first program will run erroneously.
A simpler solution is to not have two separate programs, but to have two functions in a single program. But if the first program is a bootloader and then second may be distributed separately then you may indeed want to do this simply to have a single load file for production (though that is by no means necessary - you can program two hex files separately for example).
You are still left with the problem of program1 knowing the start address of program2. That is seldom the same as the start address of the image. That is on may architectures where the vector table resides. For ARM-Cortex-M the start of the vector table included the initial stack-pointer address and that start address so it is relatively easy for example: How to jump between programs in Stellaris