2012-01-22 12 views
6

Relato largo. Deseo aprender a crear una buena secuencia de comandos del vinculador, así que si cambio las plataformas/arquitecturas/proveedores, no volveré a estar en la zona cero sin saber qué hacer. No me preocupa la dificultad de la tarea, sino la comprensión.Asesoramiento en la creación y verificación de scripts del enlazador

he empezado una especie de project, por así decirlo, para crear una base o esqueleto para la programación y el desarrollo de chips de 32 bits Cortex-M3 de MCI. Con la ayuda de jsiei97 comenzando con el STM32F103RB (también tengo un TI Stellaris LM3S828, pero ese es otro problema), sin la necesidad de un IDE con licencia. Como soy estudiante, y la mayoría de los estudiantes no pueden pagar tales cosas.

Entiendo que hay ODev, y Eclipse Plugins y qué no, y he leído varios blogs, wikis, páginas de documentos/manual y la mayoría de los proyectos proporcionan un script enlazador con pocas explicaciones sobre por qué y dónde han sido definidos.

He compilado una cadena de herramientas de brazo-ninguno-eabi para el STM32 pero donde me cuelgo está en el script del enlazador. CodeSourcery también requiere uno. Tengo un concepto básico de cómo crearlos y su sintaxis después de leer las páginas de manual de gnu, pero simplemente no tengo ni idea de por dónde empezar agregando varias secciones adicionales aparte de los obvios .text, .bss y .data .

Creé un rudimentary version pero obtengo errores de enlace al solicitar definiciones de sección y es allí donde me quedo atascado. Sé cómo definirlos, pero saber si lo que estoy haciendo es incluso más cercano a la derecha es el problema.

+0

Los scripts de gnu linker son bastante dolorosos en el mejor de los casos. Y de gcc 3.xa 4.x las cosas que solían funcionar ya no funcionan, así que supongo que continuará que, por muy buenas que sean, le arrancarán la alfombra de debajo de los pies algún día. –

+0

Esto es cierto. Solo puedo esperar eso. Sin embargo, de 4.x a 5.x podría obtener un trabajo sólido, y sería una cuestión de seguir el registro de cambios. debería cambiar algo importante. – Crewe

Respuesta

2

Aquí es un script enlazador que trabaja para una STM32F105RB (también existen versiones para R8 y RC):

https://github.com/anrope/stm-arp/blob/github/arp.rb.ld (texto a continuación)

Mi conjetura más alto de la cabeza es que usted no tiene que cambiar cualquier cosa Tal vez el origen de las regiones definidas en la declaración MEMORY {}. Espero que los comentarios te sean útiles.

Lo usé con un compilador cruzado de GNU/GCC. Después de compilar, es útil ejecutar nm en su código para asegurarse de que las secciones se coloquen en las direcciones correctas.

Editar: I retazos este script enlazador juntos mediante el uso de la documentación ld GNU:

http://sourceware.org/binutils/docs/ld/

y mediante el examen de la salida de un GCC cross-compilar con la secuencia de comandos enlazador estándar, utilizando nm. Básicamente, identifiqué todas las secciones que se estaban produciendo y descubrí cuáles eran realmente útiles, y en qué lugar de la memoria deberían ir al STM32F105.

Hice notas en el script del enlazador del propósito de cada sección.

/* 
arp.{r8,rb,rc}.ld : 
These linker scripts (one for each memory density of the stm32f105) are used by 
the linker to arrange program symbols and sections in memory. This is especially 
important for sections like the interrupt vector, which must be placed where the 
processor is hard-coded to look for it. 
*/ 

/*stm32f105 dev board linker script*/ 

/* 
OUTPUT_FORMAT() defines the BFD (binary file descriptor) format 
OUTPUT_FORMAT(default, big, little) 
*/ 
OUTPUT_FORMAT ("elf32-littlearm", "elf32-bigarm", "elf32-littlearm") 
/* ENTRY() defines the symbol at which to begin executing code */ 
ENTRY(_start) 
/* tell ld where to look for archive libraries */ 
/*SEARCH_DIR("/home/arp/stm/ctc/arm-eabi/lib")*/ 
/*SEARCH_DIR("/home/arp/stm/ccbuild/method2/install/arm-eabi/lib")*/ 
SEARCH_DIR("/home/arp/stm32dev-root/usrlol/arm-eabi/lib") 

/* 
MEMORY{} defines the memory regions of the target device, 
and gives them an alias for use later in the linker script. 
*/ 

/* stm32f105rb */ 
MEMORY 
{ 
    ram (rwx) : ORIGIN = 0x20000000, LENGTH = 32k 
    flash (rx) : ORIGIN = 0x08000000, LENGTH = 128k 
    option_bytes_rom (rx) : ORIGIN = 0x1FFFF800, LENGTH = 16 
} 

_sheap = _ebss + 4; 
_sstack = _ebss + 4; 
/*placed __stack_base__ trying to figure out 
global variable overwrite issue 
__stack_base__ = _ebss + 4;*/ 

_eheap = ORIGIN(ram) + LENGTH(ram) - 1; 
_estack = ORIGIN(ram) + LENGTH(ram) - 1; 

/* SECTIONS{} defines all the ELF sections we want to create */ 
SECTIONS 
{ 
    /* 
    set . to an initial value (0 here). 
    . (dot) is the location counter. New sections are placed at the 
    location pointed to by the location counter, and the location counter 
    is automatically moved ahead the length of the new section. It is important 
    to maintain alignment (not handled automatically by the location counter). 
    */ 
    . = SEGMENT_START("text-segment", 0); 



    /*isr_vector contains the interrupt vector. 

    isr_vector is read only (could be write too?). 

    isr_vector must appear at start of flash (USR), 
    address 0x0800 0000*/ 
    .isr_vector : 
    { 
     . = ALIGN(4); 
     _sisr_vector = .; 

     *(.isr_vector) 

     _eisr_vector = .; 
    } >flash 

    /*text contains executable code. 

    text is read and execute.*/ 
    .text : 
    { 
     . = ALIGN(4); 
     *(.text) 
     . = ALIGN(4); 
     *(.text.*) 
    } >flash 

    /*init contains constructor functions 
    called before entering main. used by crt (?).*/ 
    .init : 
    { 
     . = ALIGN(4); 
     KEEP(*(.init)) 
    } >flash 

    /*fini contains destructor functions 
    called after leaving main. used by crt (?).*/ 
    .fini : 
    { 
     . = ALIGN(4); 
     KEEP(*(.fini)) 
    } >flash 

    /* rodata contains read only data.*/ 
    .rodata : 
    { 
     . = ALIGN(4); 
     *(.rodata) 

     /* sidata contains the initial values 
     for variables in the data section. 

     sidata is read only.*/ 
     . = ALIGN(4); 
     _sidata = .; 
    } >flash 

    /*data contains all initalized variables. 

    data is read and write. 
    .data (NOLOAD) : AT(_sidata)*/ 
    .data : AT(_sidata) 
    { 
     . = ALIGN(4); 
     _sdata = .; 

     *(.data) 

     _edata = .; 
    } >ram 

    /*bss contains unintialized variables. 

    bss is read and write. 
    .bss (NOLOAD) :*/ 
    .bss : 
    { 
     . = ALIGN(4); 
     _sbss = .; 
     __bss_start__ = .; 

     *(.bss) 
     . = ALIGN(4); 

     /*COMMON is a special section containing 
     uninitialized data. 

     Example: (declared globally) 
     int temp; //this will appear in COMMON */ 
     *(COMMON) 

     _ebss = .; 
     __bss_end__ = .; 
    } >ram AT>flash 

    . = ALIGN(4); 
    end = .; 

     /* remove the debugging information from the standard libraries */ 
    DISCARD : 
    { 
    libc.a (*) 
    libm.a (*) 
    libgcc.a (*) 
    } 

    /* Stabs debugging sections. */ 
    .stab   0 : { *(.stab) } 
    .stabstr  0 : { *(.stabstr) } 
    .stab.excl  0 : { *(.stab.excl) } 
    .stab.exclstr 0 : { *(.stab.exclstr) } 
    .stab.index 0 : { *(.stab.index) } 
    .stab.indexstr 0 : { *(.stab.indexstr) } 
    .comment  0 : { *(.comment) } 
    /* DWARF debug sections. 
     Symbols in the DWARF debugging sections are relative to the beginning 
     of the section so we begin them at 0. */ 
    /* DWARF 1 */ 
    .debug   0 : { *(.debug) } 
    .line   0 : { *(.line) } 
    /* GNU DWARF 1 extensions */ 
    .debug_srcinfo 0 : { *(.debug_srcinfo) } 
    .debug_sfnames 0 : { *(.debug_sfnames) } 
    /* DWARF 1.1 and DWARF 2 */ 
    .debug_aranges 0 : { *(.debug_aranges) } 
    .debug_pubnames 0 : { *(.debug_pubnames) } 
    /* DWARF 2 */ 
    .debug_info  0 : { *(.debug_info .gnu.linkonce.wi.*) } 
    .debug_abbrev 0 : { *(.debug_abbrev) } 
    .debug_line  0 : { *(.debug_line) } 
    .debug_frame 0 : { *(.debug_frame) } 
    .debug_str  0 : { *(.debug_str) } 
    .debug_loc  0 : { *(.debug_loc) } 
    .debug_macinfo 0 : { *(.debug_macinfo) } 
    /* SGI/MIPS DWARF 2 extensions */ 
    .debug_weaknames 0 : { *(.debug_weaknames) } 
    .debug_funcnames 0 : { *(.debug_funcnames) } 
    .debug_typenames 0 : { *(.debug_typenames) } 
    .debug_varnames 0 : { *(.debug_varnames) } 
} 
+0

Me han dicho que no podemos proporcionar enlaces en las respuestas, ya que pueden cambiar pero traen la información a la respuesta de la que estamos hablando. He agregado el archivo que especificó a su respuesta. –

+1

¿Dónde adquiriste la información que necesitabas para crear este script? ¿Cómo sabías que necesitabas ** _ sheap **, ** _ sidata ** y ** _ sstack ** y qué asignarles? Ese es el tipo de información que estoy buscando. – Crewe

+1

He editado mi respuesta. Cada una de esas secciones (y más) apareció en una compilación usando un script de enlazador estándar. Verifica los comentarios en el guion. _sheap es el inicio del montón, _sstack es el inicio de la pila. – anrope

8

Tengo un script de enlazador simple que reutilizo regularmente en todas las plataformas, solo cambie algunas direcciones según sea necesario.

http://github.com/dwelch67/

Hay una serie de muestras con muchas muestras de gcc y la mayoría de los que tienen las secuencias de comandos del vinculador.

MEMORY 
{ 
    rom : ORIGIN = 0x00000000, LENGTH = 0x40000 
    ram : ORIGIN = 0x10000000, LENGTH = 30K 
} 

SECTIONS 
{ 
    .text : { *(.text*) } > rom 
    .bss : { *(.bss*) } > ram 
} 
+3

+1 por mantenerlo simple. Absolutamente cualquiera podría leer esto y entenderlo. Muchas personas intentan colocar directamente registros mapeados en memoria, etc. en el script del enlazador, y muy pronto adquieren vida propia. Sin mencionar que no es portatil. – Dan

+1

¿No falta esto al menos en la sección de datos? (¿Dónde irán tus globales globales inicializados?) – dbrank0

Cuestiones relacionadas