Apparently, there is no special behavior of the GNU linker in obtaining the MSP value: the value is used in the CMSIS-defined vector table, provided by the micro vendor, and defined in the startup file (startup_stm32F303xc.s in my project):
/******************************************************************************
*
* The minimal vector table for a Cortex M4. Note that the proper constructs
* must be placed on this to ensure that it ends up at physical address
* 0x0000.0000.
*
*******************************************************************************/
.section .isr_vector,"a",%progbits
.type g_pfnVectors, %object
.size g_pfnVectors, .-g_pfnVectors
g_pfnVectors:
.word _estack
.word Reset_Handler
.word NMI_Handler
...
I had assumed the linker somehow obtained the MSP value (_estack) from the linker script. It is the assembly, however, that simply stubs the value of _estack, which the linker later resolves. Nothing cryptic--just a plain old table of initialized data, placed by the linker at the appropriate address for the microprocessor.
I suppose _estack is simply the canonical symbol used by CMSIS-based projects and linker scripts.