The start address of your code is normally determined by the linker script or settings. The default for your toolchain will be to run from reset (i.e. the reset vector will point to the start address of the code). Your secondary program needs to be located in a different memory space (via the linker settings) and your primary program will simply need to jump to to the second.
Some gotchas you may need to be wary of; your primary program may not leave I/O and peripherals in the "reset" state, so you secondary program should not make any assumptions. Before making the jump, it is probably important that you disable any peripherals that may be generating interrupts.
As far as combining the hex files, that can be achieved easily with a text editor if you are careful and prepared to interpret the hex records manually or more flexibly (and less error prone) with the SRecord tool.
One problem you may encounter is that while the code itself may be separately located, the vector table in AVR is fixed and will be shared between the two programs. The interrupt vector tables for the two programs must be identical and must share handlers - that is not straightforward if the handlers need to communicate with whichever program is "running". The simplest solution is to arrange it so that only one of the programs uses interrupts. SRecord will usefully resolve or warn of conflicts where both hex files define overlapping memory regions, and I think you can arrange it so that one file overrides the other.