I had a complicated problem that I needed to access the .data initialization data as a separate segment for an Arm bare-metal application.
I was able to achieve it using Output Section Region.
My original linker script went something like this:
SECTIONS
{
    /*
     * For Cortex-M devices, the beginning of the startup code is stored in
     * the .interrupt_vector section, which goes to FLASH
     */
    .text :
    {
        . = ALIGN(4);
        KEEP(*(.interrupt_vector))
        KEEP(*(.reset))
        *(.text .text.*)            /* all remaining code */
        *(.rodata .rodata.*)        /* read-only data (constants) */
        . = ALIGN(4);
    } >FLASH
   /*
     * This address is used by the startup code to
     * initialize the .data section.
     */
    . = ALIGN(4);
    __data_init__ = .;
    .data  : AT ( __data_init__ )
    {
        . = ALIGN(4);
        /* This is used by the startup code to initialize the .data section */
        __data_start__ = . ;
        *(.data_begin .data_begin.*)
        *(.data .data.*)
        *(.data_end .data_end.*)
        . = ALIGN(4);
        /* This is used by the startup code to initialize the .data section */
        __data_end__ = . ;
    } >RAM
    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        __bss_start__ = .;
        *(.bss_begin .bss_begin.*)
        *(.bss .bss.*)
        *(COMMON)
        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;
    } >RAM
And my startup function has:
    /* Copy .data from FLASH to RAM */
    src = &__data_init__;
    dest = &__data_start__;
    end = &__data_end__;
    while(dest < end) {
      *dest++ = *src++;
    }
I changed my linker script to:
SECTIONS
{
    /*
     * For Cortex-M devices, the beginning of the startup code is stored in
     * the .interrupt_vector section, which goes to FLASH
     */
    .text :
    {
        . = ALIGN(4);
        KEEP(*(.interrupt_vector))
        KEEP(*(.reset))
        *(.text .text.*)            /* all remaining code */
        *(.rodata .rodata.*)        /* read-only data (constants) */
        . = ALIGN(4);
    } >FLASH
    .data :
    {
        . = ALIGN(4);
        __data_init__ = LOADADDR (.data);
        /* This is used by the startup code to initialize the .data section */
        __data_start__ = . ;
        *(.data_begin .data_begin.*)
        *(.data .data.*)
        *(.data_end .data_end.*)
        . = ALIGN(4);
        /* This is used by the startup code to initialize the .data section */
        __data_end__ = . ;
    } >RAM AT > FLASH
    .bss (NOLOAD) :
    {
        . = ALIGN(4);
        __bss_start__ = .;
        *(.bss_begin .bss_begin.*)
        *(.bss .bss.*)
        *(COMMON)
        *(.bss_end .bss_end.*)
        . = ALIGN(4);
        __bss_end__ = .;
    } >RAM AT > RAM
And now I have .data as an entirely separate ELF segment:
arm-none-eabi-readelf.exe -l ../../../firmware/Cortex-M3/cm3-bootloader/Release/cm3-bootloader.elf
Elf file type is EXEC (Executable file)
Entry point 0x601b9
There are 3 program headers, starting at offset 52
Program Headers:
  Type           Offset   VirtAddr   PhysAddr   FileSiz MemSiz  Flg Align
  LOAD           0x010000 0x00060000 0x00060000 0x067fc 0x067fc R E 0x10000
  LOAD           0x019b30 0x20019b30 0x000667fc 0x00064 0x00064 RW  0x10000
  LOAD           0x029b2c 0x20019b2c 0x20019b2c 0x00000 0x060e8 RW  0x10000
 Section to Segment mapping:
  Segment Sections...
   00     .text .ARM.exidx.reset
   01     .data
   02     .systemclock .bss ._stack
Also, __data_init__ still points exactly where .data LMA is:
.data           0x20019b30       0x64 load address 0x000680f4
                0x20019b30                . = ALIGN (0x4)
                0x000680f4                __data_init__ = LOADADDR (.data)
                0x20019b30                __data_start__ = .
This is not a question, this is just to register how I did this in case it's helpful to someone else.