Egy FPGA-s projekt kapcsan futottam bele a fenti uzenetbe. A kontextus: sima C kod forditasa beagyazott kornyezetben. A limitaciok miatt a teljes zubehor, init-estul, text-estul, rodata+data+bss-estul egyetlen RAM blokkba kerul, onnan is fut, azaz nem kulonul el a "flash" es a "ram" mint a szokasos esetekben - es emiatt kapom a targybeli hibauzenetet linkeleskor. Ez igy nyilvan rendben is van, de mivel ez tudatos, szeretnek megszabadulni ettol a figyelmeztetestol. Az interwebeken azt irjak hogy az .init meg a .text (READONLY) attributuma ezt megoldja, de sajna ez nem segit. Egyeb otlet? :)
A rendszer egyebkent RISC-V + picolibc alapu, igy a hozza tartozo alap linker szkriptet (/usr/lib/picolibc/riscv64-unknown-elf/lib/picolibc.ld) modositottam egy kicsit hogy minden egy RAM blokkba keruljon. De egy kicsit el is vesztam az ilyen .text { ... } >ram AT>ram :text meg hasonlo nyalanksagokban is...
Thx, A.
- 254 megtekintés
Hozzászólások
Egyeb otlet?
Régen kellett ilyesmi, akkor az ld "-N" kapcsolója megoldotta ezt. Nem tudom, hogy a legújabb verziónál is működik-e még ez a workaround.
A limitaciok miatt a teljes zubehor, init-estul, text-estul, rodata+data+bss-estul egyetlen RAM blokkba kerul, onnan is fut
Egyébként ha úgyis linker scriptből helyezed a RAM-ba a szegmenseket, akkor miért nem használsz két egymásutáni szegmenst és jóccakát? Ha az align-t leveszed 8-ra, akkor még a kihasználatlan memóriaterület is minimális lesz a :text és :data szegmens között, nem veszítesz semmit. Init, text rodata sections megy a :text szegmensbe, data, bss meg a :data szegmensbe, a két szegmens meg egymásután a RAM-ba (úgyis csak az első szegmens kezdőcíme az érdekes, ha jól sejtem).
Másik ötlet, hagyd a francba a MEMORY blokkot, helyette a szegmens kezdőcímét állítsd be, a végeredmény ugyanaz lesz:
SECTIONS { . = SEGMENT_START("text-segment", KEZDOCIM) + SIZEOF_HEADERS; .text . : { ... } :text ...
Ha nem akarod, hogy a programfejléc is benne legyen, akkor hagyd ki a SIZEOF_HEADERS-t. Ez akkor kell, ha az elf egy-az-egyben töltődik be a memóriába (azaz az elf fájl első bájtra kerül arra címre), és akkor nem kell, ha a kódszegmens első bájtja kerül arra a címre (vagy azért, mert kraftos az elf betöltő, vagy pedig azért, mert linkelés után objconv-val raw binary-vá alakítod). Hogy kell-e, azon múlik, hogy töltöd be végül.
Nagyon fontos, a szekció definícónál van egy PLUSZ PONT (a ".text" és a kettőspont között), ez helyezi el az adott címre, azaz ez a pont váltja ki a MEMORY-t és a kacsacsőrt.
- A hozzászóláshoz be kell jelentkezni
Régen kellett ilyesmi, akkor az ld "-N" kapcsolója megoldotta ezt. Nem tudom, hogy a legújabb verziónál is működik-e még ez a workaround.
Igen, a `man ld` szerint valami hasonlot kene csinalnia, de itt sajna nem segit :/ Kb ugy hatastalan mint a (READONLY) cucc.
Egyébként ha úgyis linker scriptből helyezed a RAM-ba a szegmenseket, akkor miért nem használsz két egymásutáni szegmenst és jóccakát?
Igyis automatikusan egymas utan helyezi el, ezzel nincs gond:
20000000 T __text_start
2000005c T __vectors
[...]
200012a4 T __modsi3
200012f4 T __text_end
200012f8 A __data_source
200012f8 D __bss_start
200012f8 D __data_start
200012f8 D __tls_base
20001af8 D __global_pointer$
200028c8 B __bss_end
20020000 T __stack
Raadasul pont 8-ra alignolva, ahogy mondod, ez van a default linker scriptben is :)
A gond inkabb az hogy tenyleg csak egy MEMORY blokk van:
MEMORY
{
ram(rwx): ORIGIN = DEFINED(__ram ) ? __ram : 0x20000000, LENGTH = DEFINED(__ram_size ) ? __ram_size : 0x08000
}
Es ezt elso korben megtartanam igy hogy tukrozze a bus_matrix strukturajat ahogy azt hardveresen kialakitottam. Olyat persze lehetne hogy felosztom igy jelkepesen ket reszre ezt a 0x20000000 <= ... < 0x20020000 tartomanyt, az also az (rx), a felso az (rw) es akkor szevasz. De akkor pont a flexibilitasat vesztem el: neha az kell hogy sok program + keves ram, neha kis program tobb memoriat enne, es akkor folyamatosan mozgatni kene a hatarokat. Nem olyan sok az a 128k...
Másik ötlet, hagyd a francba a MEMORY blokkot, helyette a szegmens kezdőcímét állítsd be, a végeredmény ugyanaz lesz:
Koszi, ezt megnezem, ezt nem ismertem. Ha ez igy flexibilis marad (nem kell kezzel allitgatnom a hatarokat) akkor kb jo is lehet :)
- A hozzászóláshoz be kell jelentkezni
Olyat persze lehetne hogy felosztom igy jelkepesen ket reszre
Erre semmi szükség.
Koszi, ezt megnezem, ezt nem ismertem. Ha ez igy flexibilis marad (nem kell kezzel allitgatom a hatarokat) akkor kb jo is lehet :)
Így van, pont az a lényeg, hogy csak a legelső szegmens címét állítod, aztán már akárhány blokkod lehet a linker scriptben, azokat szépen egymás utáni címre fogja pakolni. Ennek így tök mindegy, hogy végül hány szegmenst alakítasz ki.
Egyedül az a kérdés, hogy hogyan töltöd majd be: ha az elf-et egy-az-egyben, akkor kell a SIZEOF_HEADERS (és ilyenkor a PHDRS blokkban is meg kell adni, hogy a text szegmens magában foglalja az elf fejléceket)
PHDRS { text PT_LOAD FILEHDR PHDRS; data PT_LOAD; } SECTIONS { . = SEGMENT_START("text-segment", __ram) + SIZEOF_HEADERS; ...
Ha azonban csak a szegmenseket töltöd be (mert van elf loader vagy mert raw-á konvertálod a fordítás végén), akkor ezekre semmi szükség.
SECTIONS { . = SEGMENT_START("text-segment", __ram); .text . : { KEEP(*(.init)) *(.text .gnu.linkonce.t*) *(.rodata .rodata.* .gnu.linkonce.r*) } :text .data : { *(.data .data.* .gnu.linkonce.d*) } :data .bss (NOLOAD) : { *(.bss) *(COMMON) } :data PROVIDE(__ram_size) = . - __ram; }
A :text kerül fix címre, a :data egyből utánna, a .bss pedig a :data végére. Elvileg a PHDRS-ben is megadható lenne a kezdőcím AT()-el, de nekem azzal voltak gondjaim LLVM lld alatt, ez a SEGMENT_START() viszont ugyanúgy működik ott is és GNU ld alatt is.
Ilyenkor egyébként hasznos a KEEP, ez gondoskodik arról, hogy az init szekció mindig a :text szegmens legelejére kerüljön, és onnan még véletlenül se rakja át máshova a linker, ezért az init legelső bájtja kerül a __ram címre.
ps: egyébként az a különbség a ". = __ram;" és a ". = SEGMENT_START("text-segment", __ram);" között, hogy az előbbi állítja a memóriabeli címet és a fájloffszetet is, míg utóbbi csak a memóriabeli címet módosítja, a fájloffszetet nem, így akármekkora a cím, nem lesz bitang nagy az elf mérete. Elvileg ugyanerre szolgálna az AT() is.
- A hozzászóláshoz be kell jelentkezni