Here is snippets from the linksplit.ld along with descriptions about the sections in the linker script.

----
MEMORY {              
  sram (rwx) : ORIGIN = 0x0EE90000, LENGTH = 0x4000
  maskrom_mem (rx) : ORIGIN = 0x2EFC0000, LENGTH = 0x20000
}

SECTIONS
{
 
  .text.init ALIGN((ORIGIN(maskrom_mem) + 0x0), 64) : AT(ALIGN((ORIGIN(maskrom_mem) + 0x0), 64)) {
    PROVIDE(_ftext = .);
    *(.text.init)
    PROVIDE(_etext = .);
  }

  .text ALIGN((ADDR(.text.init) + SIZEOF(.text.init)), 64) : AT(ALIGN((LOADADDR(.text.init) + SIZEOF(.text.init)), 64)) {
    *(.text)
  }

  .tohost ALIGN((ORIGIN(sram)), 64) : AT(ALIGN((LOADADDR(.text) + SIZEOF(.text)), 64)) {
    *(.tohost)
  }

  .data ALIGN((ADDR(.tohost) + SIZEOF(.tohost)), 64) : AT(ALIGN((LOADADDR(.tohost) + SIZEOF(.tohost)), 64)) {
    *(.data)
  }

  PROVIDE(_data = ADDR(.data));
  PROVIDE(_data_lma = LOADADDR(.data));
  PROVIDE(_edata = ADDR(.data) + SIZEOF(.data));
----

Each section is defined to start at a region in the MEMORY area via the `ORIGIN()`.  This is the area 
the code / data expects to be at runtime. So for the `.text.init` section this address is
`0x2EFC0000` and for the `.tohost` section it is `0x0EE90000`.

The section that dictates how the elf and binary derived from the elf is packaged is the `AT()` keyword.  
This tells the linker where the load address for a section is. For the elf file this would be where 
the elf loader would load this section to. It also dictates where the section is physically in the elf file. 
This is used to build up the ROM image.  

In the above snippet, `.text.init` is the first section and expects to be loaded at `0x2EFC0000`.  
The next section `.text` follows this in the elf image at `0x2EFC0000 + sizeof(.text.init)`.
In the same way, each of the next sections follows the previous section. 

In the above you can see the next section `.tohost` has a different runtime `0x0EE90000` address than its load address of  
`LOADADDR(.text) + SIZEOF(.text)`.  

The linker script file is used to setup a runtime address and a load address for each section.  
Sometimes these would be the same address, as in the case of `.text` and `.text.init`. 
In other cases, like `.tohost`, `.data` and `.data.strings` they can be different.

The linker script file can also export variables back into the code to provide the starting and ending 
address of a given section.  As you see in the above snippet, the start and end addresses of the `.data` 
section are exported as variables `_data`, `_edata` and `_data_lma`. 

In the code you can then use these addresses to copy from the load address to the execute address.

----
  la t0, _data_lma; \
  la t1, _data; \
  la t2, _edata; \
1: \
  lw t3, 0(t0); \
  sw t3, 0(t1); \
  addi t0, t0, 4; \
  addi t1, t1, 4; \
  bltu t1, t2, 1b;
----

You can specify that all sections get loaded and executed from the same address space using this framework as well.  In this case all the load addresses would equal the 
execute addresses.   You would not need the copy code in this case.
