Avaleht
uus teema   vasta Tarkvara »  Programmeerimine »  32 bit aadress 64 bit operandiga x86-l märgi kõik teemad loetuks
märgi mitteloetuks
vaata eelmist teemat :: vaata järgmist teemat
Hinnavaatlus :: Foorum :: Uudised :: Ärifoorumid :: HV F1 ennustusvõistlus :: Pangalink :: Telekavad :: HV toote otsing
autor
sõnum Saada viide sõbrale. Teata moderaatorile
otsing:  
kalvis
Kreisi kasutaja

liitunud: 20.10.2009




sõnum 24.04.2020 12:56:31 32 bit aadress 64 bit operandiga x86-l vasta tsitaadiga

Kood ise on 99% 32 bit assembleris ja integreeritud C-ga (C roll väheoluline, kutsub vaid asm fn-i välja ilma parameetriteta). Kompilaatoriks on MinGW32 (on ka installitud MinGW64)
Kood töötab suurepäraselt kui mõlemad 32 bitisena kompileerida. Mõlemad tuleb kompileerida sama bitilisusena.
Kood kompileerub nii 32 bit kui 64 bit modes ja käivitub .exe Kuid 64 bit keskonnas hakkas lollusi viskama ja hangus. Viga leitud - selleks on kaudse adresseerimise jump tabelid (aadress [4*eax+table]), paraku see käsk vajalik ja mõttetu oleks need ümber teha kuna ASM kood vaid 2K ja mul ei ole miskist otsast vajalik 64 bit adresseeringut. Jump tabeleid on seeeest väga palju

Kogu programmis on vaid kaks käsku kus oleks hea kasutada 64 bit registrit tehteks. Võitu palju ei anna (praegu lahendatud ca 10 lisakäsuga, töötab) Windows 10 on 64 bbit, prose samuti. Kuid see lahendus võimaldaks just 64 bit koodi kasutada. Mul ei ole tulemas mitte ühtegi programmi mis vajaks rohkem kui 4GB mäluruumi adresseerimist. Seega minu vajadus olekski 32 bit adresseering 64 bit käsutöötlusega!

KAS saab NASM-is ja MinGW-s kompileerida nii, et kasutaks 32 bit aadresse (ei viskaks sinna jmp käsu ette 64 bit prefiksit), kuid aadress oleks default kogu programmis 32 bit. Kunagi ammu kui 64 bit prosed tulid siis mainiti, et selline võti on olemas. Programm kompileeritakse nagu 64 bit ikka aga default on kasutusel 32 bit aadressid. No ei leia googlega. Praegu on säte kas kõik 32 bit või kõik 64 bit ja raibe (64 bitis) kompileerib kõikide käskude aadressid 64 bitistena mistõttu mistahes kaudne adresseering läheb vigaseks. On keegi kokku puutunud?

Vahepeal leidsin NASM manuaalist sobiva vastuse. Kui on BITS 64 siis default on 64 bit aadress ja prefiks 0x67 saab kasutada 32 bit aadressi. Seega peaks programm kompileerumi õigesti, teadmata on kas see on NASM bug või teeb linkur lollusi (eeldab, et aadressid on kõik 64 bit ja sodib valed aadressid külge)

Tuhnides AMD 64 bit manuaalis leidsin vist ka algse veapõhjuse ülesse. Nimelt järgnevad käsud CALL, JMP, LOOP POP ja PUSH on kõik default 64 bit. Ju siis NASM bug kui JMP [4*eax+jumptable] ei suudeta aru saada (peab olema 32 bit aadress), et peab olema 32 bit aadress ja teeb omaloomingust rax aadressiks. Kuigi ma katsetasin SHL, eax,2 ja ADD eax,jumptable ja seega peaks AMD manuaali järgi olema RAX ülemine osa nullitud siis käsk jmp [eax] pani ikka puusse. Ju siis osad käsud ei nullinud seda ülaosa ära. See sai kontrollitud eax omas õiget 32 bit aadressi ja näiteks mov [temp],eax ja jmp [temp] töötas perfektselt (temp oli tegelt nullitud quadword)

Põhimõtteliselt on küsimus lahendatud.

Küsiksin üle vaid ühe asja - kuidas on õige MinGW64 ja NASM kood kokku kompileerida/linkida.
nasm -f win64 katse.asm -o katse.o
x86_64-w64-mingw32-gcc -m64 -c main.c -o main.o
x86_64-w64-mingw32-gcc -o katse.exe main.o katse.o

Annab veateateta väljundi kuid programm kräshib - st loodetud väljundit ei tule. Seejuures ei toimi enam 32 bit tasandil kahe mooduli funktsiooni ühendamine mis toimis C- on extern int katse(); ja väljakutse a=katse(), Asmis aga peab olema _katse väljakutse aadressil.
64 bit annab sellele et funktsiooni ei leita (ja 32 bit töötab!) Kui panen mõlemad C ja asmis _katse - veateateta aga ei tööta! Kui panen katse ja katse mõlemas - ei leia.
Ja ei leia ühtegi näidet kuidas 64 bit koodi vaja kompileerida...


Leidsin vea ülesse, kahjuks alati sama viga - veak tihend klaviatuuri ja tooli vahel. Pisasi aga olin kogemata väljakutsutava fn kirjutanud data sektsiooni. 32bit kompileerub ja töötab aga 64 bit annab veateateta väljumise.

Case closed.
tagasi üles
vaata kasutaja infot saada privaatsõnum
RassK
HV Guru
RassK

liitunud: 17.01.2007




sõnum 12.06.2020 09:17:42 vasta tsitaadiga

Nii huvi pärast, milline erivajadus sunnib AMD64 peal tegelema nii madalas kihis ?
Kommentaarid: 111 loe/lisa Kasutajad arvavad:  :: 0 :: 0 :: 97
tagasi üles
vaata kasutaja infot saada privaatsõnum
Supiplex
HV veteran
Supiplex

liitunud: 11.12.2002




sõnum 12.06.2020 11:35:24 vasta tsitaadiga

Ma kalvise motivatsiooni ei tea, aga üldiselt on raua otsa progemine ajurakke taastava mõjuga (ja ühtlasi õpetlik, aga see on rohkem kõrvalmõju). Eriti kui oled päev otsa kellegi teise freimvöörgi otsa õhulosse ehitanud icon_smile.gif
Hack on!

_________________
The young lady had an unusual list,
Linked in part to a structural weakness.
She set no preconditions.
Kommentaarid: 38 loe/lisa Kasutajad arvavad:  :: 0 :: 1 :: 34
tagasi üles
vaata kasutaja infot saada privaatsõnum
kalvis
Kreisi kasutaja

liitunud: 20.10.2009




sõnum 14.06.2020 11:11:57 vasta tsitaadiga

RassK kirjutas:
Nii huvi pärast, milline erivajadus sunnib AMD64 peal tegelema nii madalas kihis ?
Sel on pikem ajalugu j algaski siit foorumist tagasisside pärast.
Oli C-s vajas bitväljadest lugeda andmeid - peamiselt videotöötluseks. Mina pole süüdi, et paljud TS headeri andmekihid pole baitorienteeritud vaid bitipõhised. Ja siis veel see little ja big endiani jama. Lühidalt - ühe kahe asm käsuga oli asi imelihtne, samas kui C-s oma vahenditega tuli üksjagu tüüpide ja muu lollusega tegeleda. Mõlemas variandis sain tööle aga ASM kood jooksis suurepäraselt ja lihtsalt.
Järgmine tase oli foorumis soovitatud - kasutada suuremahulistes andmete datablokkides SIMD käske (MMX, SSE). Kui muidu kulus ühe piksli datatöötlusele tavameetodil x arv käske siis SIMD käskudega saab 16x kiiremini!!! Just viimaseid saab normaalselt kasutada ainult puhtas assembleris, C lahendused on alla igasugust normaalset võimalust. Alguses mässasisn otse C inline assembleriga aga selle gcc lahendus oli perverssuse ülim tipp. Lõpuks avastasin NASM-i - lühidalt ainult tööjõudlust vajav C alamprogramm on kirjutatud NASM-is, kõik muu on ikka C. N: ekraanitäie pixlite mistahes muutmine - see on jutavaline mingi elementaarne ja/või/ei ning +/- tehted baitidega. SIMD käskudes saab ühe käsuga töödelda 16 baiti infot ühe prose taktiga! Ja vastav alamprogramm on vaid kümmekond assembleri käsku (For tsükkel, C muutujast andmete lugemine, töötlus ja salvestamine C muutujasse)

Mida rohkem koodi kirjutad seda lihtsam on assemblerit kasutada. Kõik if, tsüklid jne. tulevad pea imelihtsalt. Kõige suuremaks õnnistuseks pean C tüüpide jurast pääsemist. Kuigi C-s on see arusaadav miks ta olema peab siis ikkagi on C muutuja nii tüübis kinni, et pöördudes näiteks int muutuja poole ja soovides vaid keskelt lugeda 1 baiti - tuleb kasutada tüübiteisendust (teed Char viida, võtad sellele muutuja aadressi ning siis viit+2 loed baidi välja). Asmis saab otse lugeda (N: [Cvar+2]).
Eriti vinge on aga assembleris siis kui kasutada tuleb teadmata pikkusega bitivälju või mitte baitideks jagunevaid (TS_streamis palju kasutusel). SHLD käsuga imelihtne teha nad igaüks omasse muutujasse.
Viimase aja avastus on võimalik stringitöötlus. Kasutada saaks C stringi funktsioone kuid x86 on võimalik vägagi efektiivselt ka SIMD või stringi assembleri funktsioonidega sama asi teha! Kuid siin pole enam lihtsaid lahendusi. Efekt on siis kui kasutakse suurtes massiivides otsimist, eriti kui string on lühike (mitte üle 16 B) ja massiiv suur.

Koondvastus - Assembleri eelis on just siis kui kasutada SIMD töötlust andmemassiividele (N: videotöötlus) või keerukad bitiväljad, eriti kui bitiväljad on dünaamilised (ei saa kasutada struktuure). Kolmas koht on kiirus aga enamikku see ei huvita. Ise kirjutan vaid üksikud funktsioonid assembleris. Puhast assemblerit ei kasuta (st. kogu programm oleks asmis, seda pole üldse teinud välja arvatud 1 kord, et veenduda, selle võimalikkuses (see oli Hello world)
tagasi üles
vaata kasutaja infot saada privaatsõnum
klf
HV vaatleja

liitunud: 08.03.2005




sõnum 14.06.2020 15:29:50 vasta tsitaadiga

Noh, ma kommenteeriks ka veidi...

Esiteks, 32-bitine aadress ja x86-64 arhitektuur on sisuliselt x32 ABI. Kas windows seda toetab, ma ei tea, aga gcc puhul -mx32 valib vastava rezhiimi.

Teiseks, raua otsa kirjutamine arendab ajutegevust küll, aga seda saab teha üldjuhul otse C-s. Näiteks, kui on soov lugeda int tüüpi muutuja keskelt
välja kolmas bait, kirjutab programmeerija ((foo >> 16) & 0xff). Kompilaator teeb sellest nii nagu heaks arvab, kas sama shift+mask, või siis emiteerib
üheainsa bextr instruktsiooni.

Selleks, et kood lendaks, tuleb enamasti alustada andmestruktuuride mälupaigutuse, pakkimise, striimimise, prefetchimise ja muu sellisega. Seda
loogikat on palju tõhusam C-s kirjutada. Kui on soov mingi operatsioon käsitsi paralleliseerida, siis seda saab ka enamasti C-s teha. Gcc ja clang (llvm)
teevad praktiliselt kõik SIMD käsud kättesaadavaks x86 intrinsic'utena. Lisad "#include <x86intrin.h>" ja võid kasutada igat sorti tehteid. Näiteks
_mm_shuffle_epi8() abil saad 16-le baidile suva permutatsioone rakendada. Masinkoodis on see mõistagi üks instruktsioon. (Kuigi, gcc/llvm omavad ka
__builtin_shuffle/__builtin_shufflevector, niiet selle jaoks ei pruugi isegi intrinsikut rakendada.)

Ülal mainiti ka stringide otsimist andmemassiividest. Jumala eest, selle tarvis soovitaks siiski alustada sobiva algoritmi valikuga (üks tuntumaid on
Boyer-Moore), mitte valida naiivne brute-force.

Lühidalt, raualähedast SIMD koodi saab kirjutada ka C keeles, tehes seda struktuurselt, paindlikult ja ülevaatlikult.

Edit. Mainiks veel ära niipalju, et C teeb koodikirjutaja eest ära suure hulga tööd, sh register allocation'i. Intrinsikute vahetulemusi hoitakse
loomulikult registrites nii palju kui võimalik, samamoodi nagu optimiseeritakse tavalist skalaarkoodi.


viimati muutis klf 15.06.2020 15:43:47, muudetud 1 kord
Kommentaarid: 10 loe/lisa Kasutajad arvavad:  :: 0 :: 0 :: 10
tagasi üles
vaata kasutaja infot saada privaatsõnum
kalvis
Kreisi kasutaja

liitunud: 20.10.2009




sõnum 15.06.2020 12:54:13 vasta tsitaadiga

See AND ja shift on ikkagi kaks lisakäsku, samas kui baiti keskel saab lugeda absoluutselt ilma ühegi lisakäsuta! Kui seda läheks vähe vaja siis olen otse C-s kasutanud.
Kuigi C-s nende masinkoodi derivaat funktsioonidega saab üksikuid SIMD käsutöötlusi teha, ei saa nendega teha just kahte või kolme omavahel seotuid edukalt - kus sul põhiargument on xmm registris ja töötled jadamisi. C käsk salvestab mällu tagasi, mistõttu kogu SIMD ilu läheb kaotsi. Assembleri efektiivsus ongi just registriga maksimaalses töötluses - laetakse lähteandmeid niipalju kui vaja registrisse, tehakse võimalikult keerulised tehted registritega ära ja alles siis lõppsaadus mällu tagasi. Muidu läheb kogu aur vaid registrisse laadimisele ja mällu tagasi laadimisele ja see on prose takte raiskav. Jah, kood töötab. Olen üksikuid instrinct käske kasutanud, üheainsa assembleri käsu pärast tõesti ei tasu hakata assembleris librarit kirjutama.

gcc ja windows toetavad kõiki võimalikke ABIsi, selleks kasutatakse vajaduse korral assembleri funktsioonidel registercall või standardcall atribuute. Ma eelistan registercall kasutada - nagu öeldud siis saan funktsiooni argumendid otse registrisse ja seda isegi win32 korral. Ainult et keegi ajunõder (tõenäoliselt M$) tegi need Linuxis ja Windowsis erinevalt just win64 koodi juhtumil (win32 koodis on registrite järjekord sama windowsis ja Linuxis). Saab ka siis aga hakkab rohkem perverssuseks minema opsüsteemi direktiiviga mängides.
tagasi üles
vaata kasutaja infot saada privaatsõnum
uu
HV vaatleja

liitunud: 16.08.2015




sõnum 22.07.2020 23:51:57 vasta tsitaadiga

Ise tegin SMID enamjaolt instricntide peale kus compiler hätta jäi või compatability meetmeid kasutas.
ASMi võrdluseks on hea kiire vahend https://godbolt.org/z/63feG5 , kasvõi 10 tk eri optimiseerimistega eri compilereid ritta võrdluseks kui monitor lai.
Annab ajapikku taju sellest kuidas on õige kirjutada et kompilaator optimiseeriks ise ära.

Üldiselt tundub et ICC on parim ja -O3 astmel ka GNU teeb palju SMID-d kui kood compilerile arusaadav.
+ICC profileerims vahendid head.

Kõige hullem pudelikael on kui palju RAM mäluga lugemist ja väikseid blokke eri paigust mis järjest ei jookse.
In cache kompressiooni algod võivad ka palju muuta kui on võimalik kasutada.
tagasi üles
vaata kasutaja infot saada privaatsõnum
näita postitusi alates eelmisest:   
uus teema   vasta Tarkvara »  Programmeerimine »  32 bit aadress 64 bit operandiga x86-l
[vaata eelmist teemat] [vaata järgmist teemat]
 lisa lemmikuks
näita foorumit:  
 ignoreeri teemat 
sa ei või postitada uusi teemasid siia foorumisse
sa ei või vastata selle foorumi teemadele
sa ei või muuta oma postitusi selles foorumis
sa ei või kustutada oma postitusi selles foorumis
sa ei või vastata küsitlustele selles foorumis
sa ei saa lisada manuseid selles foorumis
sa võid manuseid alla laadida selles foorumis



Hinnavaatlus ei vastuta foorumis tehtud postituste eest.