- 759 megtekintés
Hozzászólások
Elvileg erre a -ffreestanging kapcsoló való. Ha úgy se jó, próbáld meg -ansi kapcsolóval, csak próbából, nehogy valami modern standard miatt próbálja kikapcsolni, mert megváltozott a default.
Lehet tévedek, de elvileg az sem baj, ha nincs ott a BSS szekció, attól még futnia kéne OS-től függetlenül.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
Elvileg erre a -ffreestanging kapcsoló való. Ha úgy se jó, próbáld meg -ansi kapcsolóvalMindkettő már meg van adva, de azért kössz!
Lehet tévedek, de elvileg az sem baj, ha nincs ott a BSS szekcióDe nekem kéne... Ráadásul amit korábban a BSS-be rakott, az került most ebbe az LOOS-be. Legalábbis az egyik eltűnt, a másik megjelent és egyforma a méretük.
- A hozzászóláshoz be kell jelentkezni
Hasznos információt nem a Type=LOOS alapján találtam, hanem a Section Name=.llvm_addrsig alapján.
Ez szemre egy lld linker feature, nem bug; úgy hívják, hogy "Identical Code Folding". Ennek a gcc BZ-nek a legelső kommentjében jól összefoglalják a feature-t:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=105625#c0
A .llvm_addrsig section ahhoz kell, hogy ezt az optimalizálási lépést "biztonságosan" végre lehessen hajtani, amit pedig az --icf=safe kapcsolóval lehet kérni:
https://llvm.org/docs/Extensions.html#sht-llvm-addrsig-section-address-…
https://maskray.me/blog/2024-03-09-a-new-relocation-format-for-elf#llvm…
Tipp: próbáld meg az lld-nek megadni az --icf=none kapcsolót:
https://man.archlinux.org/man/extra/lld/ld.lld.1.en#icf~3
Általános tipp: a readelf olvashatóbb kimenetet produkál a --wide kapcsolóval.
- A hozzászóláshoz be kell jelentkezni
Ez szemre egy lld linker feature, nem bug; úgy hívják, hogy "Identical Code Folding"Nem lehet linker feature, mert linkert nem is használok hozzá, csak fordítót. Ráadásul nem is kódot rakja bele (az a .text szekcióba került), hanem a BSS adatotokat (0x18 bájtnyit, pont ekkora volt a régi verzióval a BSS).
https://llvm.org/docs/Extensions.html#sht-llvm-addrsig-section-address-…Amit itt írnak, az teljes hülyeség. Egyrészt milyen extension az, amit nem lehet kikapcsolni (mert ha nem lehet, akkor az nem is lehet extension, ugye), másrészt asszongya: "This section is used to mark symbols as address-significant, i.e. the address of the symbol is used in a comparison or leaks outside the translation unit.", ami alapján üresnek kéne lennie ennek a szekciónak (mivel csak helyi változókról van eleve szó, tehát nem lehet "leaks outside the translation unit", a mondat másik felének meg nincs is értelme, max. ha dinamikusan linkelnék, ami meg freestanding módban nem is lehetséges). Azt is írja, hogy "Without this directive, all symbols are considered address-significant.", magyarán mi a francnak van ez a szekció, ha alapból úgyis az összes szimbólumot bele kell rakni??? Normális? És miért nem a szimbólumindexek vannak benne, és miért pont akkora, mint a hiányzó BSS? Ehh... esszerint két bugról beszélünk: a hiányzó BSS, és a freestanding ellenére megjelenő LOOS, de a kettőnek semmi köze egymáshoz, csak véletlenül egyforma a méretük?
Tipp: próbáld meg az lld-nek megadniEnnél bonyoltultabb a dolog, mert nem használok se LLVM lld-t, se GNU ld-t. Speciális formátumú kimenetre van szükségem, ezért igazából én írtam a linkert hozzá, ami beolvassa az ELF objektumokat és előállítja ez a formátumot. Ezért kéne tudnom, pontosan hol van és mekkora a BSS, és ezért baj, ha valami gányolt LOOS szekció van helyette. (Eredetileg a.out-ot akartam volna, de a gccből újabban kivették alapból, a Clang-ba meg soha nem is implementálták, ezért a szopóroller a saját formátummal.) Kis rant: ahogy én látom, ennek a Rui Ueyama nevű faszjancsinak fingja sincs, hogy mi is a linker feladata, és valószínűleg még soha életében nem fordított bare metalra, de még csak statikusan sem linkelt soha, csakis kizárólag mindenféle fos bloated frameworköket linkelt dinamikusan, ezért azt hiszi, csak az létezik... Hogy nem küldték még el a P-be az öreg motorosok? Mármint oké, hogy belerak egy ilyen szart a fosai kedvéért, na de hogy úgy, hogy még ki sem lehet kapcsolni, és minden mást tör vele...?
- A hozzászóláshoz be kell jelentkezni
Ez azért van, mert a C nyelv való rendszerprogramozásra és ezért ha egyszer leírtál egy programot, vagy összeraktál egy buildet akkor az nem törik el. Nem kell folyton hülyeségek miatt újrapeccselni minden régi kódot minden fordítóverzióval, mert ez C, nem csiligány újhullámos szar.
- A hozzászóláshoz be kell jelentkezni
LOL :D
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
Ezek az esetek amikor valamit újra elő kell venni, guglizni napokat, fórumozgatni és a végén megjavítani mindig úgy szoktak lenni, hogy valójában nem is hiba, meg nem hibája annak amit szeretünk, csak éppen elment vele három nap amit ki kell fizetni és mégis annyival később lesz kész a termék is. De a C nyelvnek semmi köze hozzá, az tökéletes, csak a fordítóval van valami apróság, lényegtelen semmiség.
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
Szóval a Clang fordító csinált neked egy problémát, de semmi köze a C-hez az egésznek. Emlékszel, hogy nem is olyan régen egy egész topikot elfloodoltál azzal a gondolattal, hogy ha írsz egy C programot, akkor az működni fog 10 év múlva is változatlanul? Mert "szabvány". Kivéve például a szegmensek nevei: az nem szabvány. Talán megpróbálhatnád átírni Rustra.
- A hozzászóláshoz be kell jelentkezni
Valóban irónikus, és a C sem tökéletes, ezt aláírom. Nem annyira felhőtlen, mint azt mi C fanboyok előadjuk idealizáltan, megvannak a saját problémái, a nyelvnek, szabványainak, fordítóknak is. Másik oldalról meg semmi nem lesz soha hibátlan, egyik nyelv, fordító sem, a Rust sem lesz mindenhatóbb, annak is megvannak a hátrányai.
A C legalább még mindig a legegyszerűbbek, legkonzervatívabbak között van, még általában azzal a legkisebb a fordított bináris mérete, azzal a legjobb a futási sebessége (hacsak nem speciális műfajról van szó, pl. CUDA számításokra optimalizált Fortran fordítóval vetjük össze, és linpack-szerű felhasználás a cél).
Nyilván a Clang/LLVM mindig is erőteljesen újító volt, aki konzervativizmust akar (mind pl. a Linux kernelesek), az inkább marad gcc-n, meg régebbi C-szabványon (C89, 90, 99), meg linkeléskor se újítgat be túl modern módszerekkel, túl agresszív optimalizációkkal (LTO és társai).
Ez a 10 év múlva is változatlanul lefordul, az kb. sose volt igaz C-nél sem, míg nem volt szabványosítva, a C fordítók gyakran egyedi megoldásoztak, aztán meg mikor lett szabvány, azok állandóan változtak, egymással nem feltétlen kompatibilisen. Pl. én a múlt héten belefutottam egy csomó olyan régi CLI program projektjébe, amik már nem fordultak le, pedig nagyon egyszerű, alap programok, de már olyan blőd dolgok miatt nem fordulnak le, hogy már nem tudja rendesen beemelni függőségnek a libcurses-t, meg pl. olyan régi kód, hogy még nincs a függvényeknek visszatérési típusa definiálva, amire a modern fordító nem is warningot dob, hanem kifejezett error-ral bukik el az egész. Ráadásul az -ansi kapcsoló se segített, kézzel kellett a problémás kódrészeket áthegeszteni, pedig ráadásul ne is ilyen ultramodern fordítóval mentem neki, mint a Clang, hanem konzervatív gcc-vel.
Meg pl. most néztem pár napja Tannenbaumnak az egyik régebbi BSDCan-előadását, amiben a modern Minix helyzetét taglalta, meg hogy miért a NetBSD userland-et, pkg/ports, Clang ökoszisztémát vették át alapul a Minix 3+ esetében, miért nem a GNU-s, linuxos toolokat, aminél megjegyezte, hogy pedig próbálkoztak az utóbbival is, de egy csomó minden nem fordult le, mert kiderült, hogy a GNU/linuxos kódok igazából nem C-ben, hanem gcc-ben vannak írva (meg én részemről hibának látom, hogy sokszor x86-ra vannak alapozva, és nem kellően portolhatóan megírva, igaz ez nem mindegyikre igaz, de vannak kivételek sajnos, főleg GPU drivernél, meg egyes nem GNU-s, de linuxos szoftvereknél). Hallatszott rajta, a maró gúny, amivel mondta, a közönség fel is röhögött rajta.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
A leírás alapján ez egy linker-feature _támogatása_ compiler oldalon. Úgynevezett _fejlődés_ .
- A hozzászóláshoz be kell jelentkezni
linkert nem is használok hozzá, csak fordítót
Az llvm/clang forrásfában bányászva eljutottam a következő kapcsolóig: -fno-addrsig.
Miután a forrásban megtaláltam, és tudtam, hogy pontosan mire kell keresni a neten, meglett a dokumentáció is:
https://clang.llvm.org/docs/UsersManual.html#cmdoption-faddrsig
Azt írja:
Controls whether Clang emits an address-significance table into the object file. Address-significance tables allow linkers to implement safe ICF without the false positives that can result from other implementation techniques such as relocation scanning. Address-significance tables are enabled by default on ELF targets when using the integrated assembler. This flag currently only has an effect on ELF targets.
Ha megadod a clang-nak az -fno-addrsig-et, változik valami?
(A kapcsoló egyébként elég régi; én most git-blame-mel a következő commit-ig nyomoztam le: 14b468bab620 ("Re-land r337333, "Teach Clang to emit address-significance tables.", which was reverted in r337336.", 2018-07-18). Azért nem könnyű megtalálni, mert mostanra a clang opciók reprezentációja a forrásban megváltozott. Például a 7694b571d9fd ("[Driver] Add multiclass OptInFlag and OptOutFlag to simplify boolean option definition", 2020-06-02) után az faddrsig sztringre keresve nincs az Options.td file-ban találat.)
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
hu hanyszor volt mar nekem is hogy valaminek a forrasabol kellett kibanyaszni a parametert, mert a doksi/help szar volt...
nem veletlen a mondas, hogy a forraskod a legjobb dokumentacio :)
- A hozzászóláshoz be kell jelentkezni
Ez pont ugyanolyan okos mondás mint hogy mindenkinek van tesztrendszere csak a szerencsésebbeknek van a prodon kívül 1-2 másik is.
- A hozzászóláshoz be kell jelentkezni
es a legjobb tesztelo a felhasznalo...
- A hozzászóláshoz be kell jelentkezni
Nekem ez a Rui Ueyama nem tűnik annyira hülye gyereknek. Legalábbis nem egy átlag soydev, de abban igazad lehet, hogy bare metalban nem utazott eddig. Védelmére legyen mondva, hogy abba nagyon kevesen is utaznak, lényegében már csak kernel, driver, firmware-fejlesztők, meg esetleg Xen-fejlesztők. A többiek, kb. az összes fejlesztők 99,999999999999%-a tényleg ilyen-olyan framworkökbe, meg dinamikus linkeléssel, bytecode-ra fordítással, stb. tolja.
Ez a bare metal fejlesztési tudás kihalóban lévő műfaj, fekete mágiának számít már.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
Az -fno-common-nal kapcsolatban: őszintén szólva nem értem, hogy miért nem az -fno-common az alapértelmezett beállítás. Ugyanis az -fcommon definiál egy olyan viselkedést, ami a C szabvány szerint definitálatlan -- és ez minimum zavaró. Például:
// a.c
int x;
int main(void) { return x; }
// b.c
int x;
Bármelyik file-t önmagában tekintve az int x; deklaráció tentative definition (kísérleti definíció), amely a file végét elérve external definition-né (külső definícióvá) válik. Ugyanis idézzük pl. a C99 szabványt (6.9.2 External object definitions, 2. bekezdés):
A declaration of an identifier for an object that has file scope without an initializer, and without a storage-class specifier or with the storage-class specifier
static, constitutes a tentative definition. If a translation unit contains one or more tentative definitions for an identifier, and the translation unit contains no external definition for that identifier, then the behavior is exactly as if the translation unit contains a file scope declaration of that identifier, with the composite type as of the end of the translation unit, with an initializer equal to 0.
Más szóval a szabvány a két fenti forrásfile viselkedését úgy szabja meg, hogy az egyenrangú legyen a következőkkel:
// a2.c
int x = 0;
int main(void) { return x; }
// b2.c
int x = 0;
Ezek viszont már (külön-külön) external definition-nek számítanak (6.9.2 External object definitions, 1. bekezdés)::
If the declaration of an identifier for an object has file scope and an initializer, the declaration is an external definition for the identifier.
Továbbá az x változónak mindkét file-ban (és mindkét változatban) external linkage-e van (6.2.2 Linkages of identifiers, 5. bekezdés 2. mondat):
[...] If the declaration of an identifier for an object has file scope and no storage-class specifier, its linkage is external.
A két eredeti forrásfile-t egyetlen programba összelinkelve pedig megszegnénk a szabványt (6.9 External definitions, 5. bekezdés 2. mondat; aláhúzásos kiemelés tőlem):
[...] If an identifier declared with external linkage is used in an expression (other than as part of the operand of a
sizeofoperator whose result is an integer constant), somewhere in the entire program there shall be exactly one external definition for the identifier [...]
És akkor nézzük meg pl. a gcc viselkedését:
gcc -std=c99 -Wall -Wextra -pedantic a.c b.c
A parancs nem jelez hibát. Itt jön a képbe az, hogy a shall hogyan értelmezendő:
- 4. Conformance, 1. és 2. bekezdésekből:
In this International Standard, ‘‘shall’’ is to be interpreted as a requirement on an implementation or on a program [...]
If a ‘‘shall’’ or ‘‘shall not’’ requirement that appears outside of a constraint is violated, the behavior is undefined. [...] - 5.1.1.3 Diagnostics, 1. bekezdés 1. mondat:
A conforming implementation shall produce at least one diagnostic message (identified in an implementation-defined manner) if a preprocessing translation unit or translation unit contains a violation of any syntax rule or constraint, even if the behavior is also explicitly specified as undefined or implementation-defined. [...]
A gcc-re csak azért nem mondhatjuk, hogy megszegi a szabványt, met a 6.9 External definitions, 5. bekezdés -- amely a "pontosan egy külső definíció" előírást tartalmazza -- nem egy Constraints szakaszban található, hanem egy Semantics szakaszban. Az előbbi esetben a gcc viselkedése megszegné a szabványt, így viszont csak az a helyzet, hogy a gcc definiál egy olyan viselkedést, amelyet a szabvány nem definiál. Ennek ellenére a gcc működése szerintem nagyon zavaró.
És akkor az -fno-common kapcsolóval ugyanez:
gcc -std=c99 -Wall -Wextra -pedantic -fno-common a.c b.c
Itt már van hibaüzenet:
/tmp/cc96ba6O.o:(.bss+0x0): multiple definition of `x'
/tmp/ccL5BbT8.o:(.bss+0x0): first defined here
collect2: error: ld returned 1 exit status
Csak hogy három projektet említsek, amivel dolgom volt: mind az edk2, mind a qemu, mind a libvirt projektek megadják az -fno-common-t. Szerintem állíthatjuk azt, hogy az -fcommon mint alapértelmezés hiba (vagy minimum tévedés) a fordítókban.
- A hozzászóláshoz be kell jelentkezni
- A hozzászóláshoz be kell jelentkezni
Én inkább nem is azt nem értem, hogy az alapértelmezett viselkedés miért változott, hanem hogy ez miért nincs rendesen lekommunikálva, dokumentálva, aztán meg a felhasználó észreveszi, hogy valami nem stimmel. Ez így elég gáz, hogy random verzióban sunyiban ilyenek húznak meg.
“Windows 95/98: 32 bit extension and a graphical shell for a 16 bit patch to an 8 bit operating system originally coded for a 4 bit microprocessor, written by a 2 bit company that can't stand 1 bit of competition.”
- A hozzászóláshoz be kell jelentkezni
őszintén szólva nem értem, hogy miért nem az -fno-common az alapértelmezett beállítás
Hm... most ugy latom hogy ujabban itten (gcc-12 videken) mar ez az alapertelmezett. Legalabbis a manual szerint. De az ketsegtelen hogy beagyazott cuccoknal mindig megadom, foleg hogy ott vannak regebbi forditok (pl riscv64-unknown-elf-gcc-8.3.0) ahol tenyleg nem az az alapertelmezett... De ujabban (riscv64-unknown-elf-gcc-12.2.0) mar ott is...
Erdekes nagyon, koszi a reszletes leirast :) Tudtam csak nem sejtettem hogy ez az -fno-common azert fontos :)
- A hozzászóláshoz be kell jelentkezni