Assembly-Unitok-

Assembly-Unitok-
2004-10-14T17:04:48+02:00
2004-10-28T16:38:20+02:00
2022-10-22T13:35:48+02:00
sypor
A bajom az lenne, hogy assemblyben hogy kell használni az EXTRN és PUBLIC parancsokat?

pl
2 program közötti kapcsolat változókkal.

program1 segment cs:program1, ds:program1 org 100h EXTRN masfileban:proc start: call masfileban int 20h program1 ends end start


program2 segment cs:program2, ds:program2 PUBLIC masfileban masfileban proc push 0b800h pop es xor di,di mov ah,15 mov al,byte ptr[betü] mov es:[di],ax ret masfileban endp betü db "1" program2 ends end

Mármost az lenne a gondom, hogy a meghivott "masfileban" procedúra az istenért sem akarja kiirni az 1-es karaktert!
Bezzeg, ha nem használok változót, akkor kirakja!

Miért?
Miért nem tudok változókat használni?
A segítséget előre is mindenkinek köszönöm.
Mutasd a teljes hozzászólást!
Nos, a fentiek alapján egy megoldás (a trükkös):

Az első modulod változatlan:

program1 segment assume cs:program1, ds:program1 org 100h EXTRN masfileban:proc start: call masfileban int 20h program1 ends end start

A második:

program2 segment assume cs:program2, ds:program2 PUBLIC masfileban masfileban proc call holvagyunk holvagyunk: pop bx sub bx,3 push 0b800h pop es xor di,di mov ah,15 mov al,byte ptr[betu+bx] mov es:[di],ax ret masfileban endp betu db "1" program2 ends end

Üdv:
Mutasd a teljes hozzászólást!

  • Itt van 2 link, aol egy-egy assembly nyelvű programot találsz; ezekben van ilyen. (A programok XP alatt nem biztos, hogy menni fognak )

    http://www.szentesinfo.hu/lidercfeny/slalom.zip
    http://www.szentesinfo.hu/lidercfeny/bombazo.zip
    Mutasd a teljes hozzászólást!
  • a PUBLIC direktiva, arra használható, hogy az adott szibolumot elérhetővé tegyük más modulok számára is, a EXTRN direktíva pedig olyan szibolumot definiál, ami egy másik modulban van kifejtve, a kettőt ezért együt kell használni

    a fenti példa egy kissé átalakitva - igy talán érhetőbb, a második modulban lévő 'masfileban' eljárás elküld egy karaktert (amit AL-ben kell megadni) a stdout-ra (képernyőre)

    1. modul (főprogram)

    program segment ASSUME cs:program, ds:program org 100h EXTRN masfileban:proc start: mov al,'A' call masfileban mov ah,4ch int 21h program ends end start

    2. modul

    program2 segment ASSUME cs:program2 PUBLIC masfileban masfileban proc push ax mov ah,2 mov dl,al int 21h pop ax ret masfileban endp program2 ends end

    az eredeti példa ezért nem irta ki a karakter mert valószínű nem csináltál belőle com fájlt, ebben az esetben a program indulásakor a CS<>DS viszont a program a DS területéről akarta kiszedni a 'változot', de a DS nem volt beállitva, ráadásul az adat 'betu' cimke a kódszegmens területén van deklarálva, ezért a hivatkozáskor egy CS prefix nem ártott volna
    mov al,byte ptr cs:[betu]
    így valószínű műköne az is...
    Mutasd a teljes hozzászólást!
  • A programokat már megtaláltam régebbról, hisz egy csomó helyre belinkelted a prog.hu-n
    De a fenti programokban te is használtál változókat, csak nem értem, pontosan, hogy hogyan.
    Sajnos a fórdító direktíváit nem nagyon ismerem.
    pl _segment...
    Mutasd a teljes hozzászólást!
  • Köszi AFD, a Public és Extrn direktíva megyarázatát, bár enyit már én is tudtam.
    A fő bajom tulajdonképpen az lenne, hogy a program2-ben nem tudok változókat használni, pedig szükségem lenne rá.
    Tudom, hogy egy programozó nem szivesen ad teljes forráskódot, de ez egy igazán kis kód és csak 1 példa kéne.

    Kipróbálom az ötleted, hátha működik
    Majd meglátjuk, és a jutalom sem marad el

    De addig is légyszi segitsetek, hogy több infóm legyen a témával kapcsolatban.
    Mutasd a teljes hozzászólást!
  • Persze hogy nem írja ki a betűt mivel más szegmens címen van mint a program1! Szóval vagy paraméterként adod meg a betüt vagy közös adat és közös kód szegmenst használsz mind a két kódban! De elég furcsa hogy külön akarsz adat és kód szegmenst használni viszont a betü változót a kód szegmensen deklarálod!

    Szerintem hagyd a segment-eket (mivel úgyis com fájlt akarsz csinálni) és a program1 elejére nyomd be a
    PUSH CS POP DS
    kódot! Így minden közös szegmensen lesz!
    Mutasd a teljes hozzászólást!
  • ha COM programot csinál, akkor nem nem kell a push cs, pop ds páros mert mind a 4 szegmens (CS,DS,SS,ES) a psp-re mutat, legalábbis DOS 2.0 vagy annél nagyobb verzióval (1.x nem használtam)
    Mutasd a teljes hozzászólást!
  • Biztos ami biztos! Egyébként meg biztos COM programot csinál, az OK hogy benne van az org 100h de annak is linkeli!?
    Mutasd a teljes hozzászólást!
  • AFD-nek tökéletesen igaza volt abban, hogy a CS prefix nem ártott volna, de kifejezetten jó lett volna, a hivó programban ugyanis bárhol állhat a DS de a híváskor a CS biztos.
    Mutasd a teljes hozzászólást!
  • Bocsi, mielött még ebböl jönne ki a hiba!

    Az téma elején az ASSUME szót elhagytam, de tudom, hogy ott van és a forráskódomban is benne van.

    Nem értem miért kéne a
    pusd ds
    pop cs
    kód, mivel az mind a két fájlban meg van oldva az assume cs:xxx, ds:xxx paranccsal!

    Amúgy tlink és tasm-et használok és COM filet csinálok belölle!

    tasm xxx.asm
    tlink xxx.asm /t
    Mutasd a teljes hozzászólást!
  • Az alábbi dolgot sikerült kihámoznom a DEBUG segítségével:
    -u

    169E:0100 E80D00 CALL 0110
    169E:0103 CD20 INT 20
    169E:0105 0000 ADD [BX+SI],AL
    169E:0107 0000 ADD [BX+SI],AL
    169E:0109 0000 ADD [BX+SI],AL
    169E:010B 0000 ADD [BX+SI],AL
    169E:010D 0000 ADD [BX+SI],AL
    169E:010F 005055 ADD [BX+SI+55],DL
    169E:0112 8BEC MOV BP,SP
    169E:0114 C7460200B8 MOV WORD PTR [BP+02],B800
    169E:0119 5D POP BP
    169E:011A 07 POP ES
    169E:011B 33FF XOR DI,DI
    169E:011D B40F MOV AH,0F
    169E:011F A02601 MOV AL,[0126]
    -q

    Ami ebből kimazsolázható, hogy CS:100h-nál kezdődik a Program1, majd a linker CS:110h-nál szegmenshatárra illesztve rakta be a program2-t, ide szól a CALL 110H hívás. Vagyis az összeszerkesztett COM file-ban a Program2-n belüli hivatkozások mind 110H-val arrébb vannak. És tényleg, ha a Program2-ben MOV AL,BYTE PTR [Betu+110H]-t írsz, ki fogja írni az "1"-es karakteredet. Elég szörnyű, de így van. Üdv:
    Mutasd a teljes hozzászólást!
  • Ja, és mint azt AFD helyesen írta, a szegmensregiszterekkel nem sokra mégy, ugyanis mind a négyen a PSP-re mutatnak. Mindez a DEBUG-ban TRACE-szel látható. A feneség éppen a tiny modell választásban van, mert így csak egyetlen közös szegmensed van mindenre akkor is, ha a programod több modulból épül fel. Üdv:
    Mutasd a teljes hozzászólást!
  • ez a dump igy hulyeseég mivel a 2. modul segmese (alapol) paragrafus határra van illesztve (16 osztható címre) , ezért az int 20 után a kitoltő szemét látható kódként (nullák) ezért az érdemi első utasitás a második modulban nem látszik a 110 címen, ezért egy 'u 110' sem ártana hogy látni lehessen mi van ott, de mondjuk ezzel normális disassembler (sourcer,SR.EXE) megbírkozik...
    Mutasd a teljes hozzászólást!
  • Teljesen igazad van, de a lényeg úgy vélem így is kitűnik az egészből. A bajom a következő: Ez az egész dolog kísértetiesen hasonlít a COM fertőző file-append típusú vírusok működésére. Ott mi történik? Van egy program1 - a gazda. Program2 - a víruskód, amely hozzáfűződik a gazdához. A vírus meghívódásakor a kód első dolga az, hogy megállapítsa, milyen messzire is van ő a gazda belépési pontjától, és helyreállítsa a saját belső hivatkozásait. Ezért itt most hadd ne mondjam el, hogyan is kell egy ilyet megcsinálni...
    Másrészt a dologra van egy pofonegyszerű megoldás: a globális változókat a főprogramban kell deklarálni. Üdv:
    Mutasd a teljes hozzászólást!
  • szerintem semmi köze a vírushoz egy vírus, most COM fertőző a saját kezdőcímét kell hogy meghatározza ezután a saját adataira ezen bázisal tud hivatkozni, erröl itt szó sincs, hogy egy példa is legyen:


    call getip
    getip:
    pop bx
    sub bx,3 ; bx-be kerül a call utasítás címe (minden esetben)
    mov ax,[bx][adat1];ax-be kerül az adat1 adat, amnek az offsetjét az call-tól számítjuk

    na egy vírus valahogy így kezdi tevékenységét...
    Mutasd a teljes hozzászólást!
  • Nos, éppen ezt nem szerettem volna így nyilvánosan közzétenni - bár meglehet, ma már ez egy olyan vírustechnológiából származó programozási trükk, amelyen semmi féltenivaló nincsen, mindenki tudhatja, ismerheti, és meglehet rengetegen tudják is. Alkalmas arra, hogy -esetünkben- azt a bizonyos 110H offsetet ki lehessen számolni, és a 2. modulban valamennyi belső hivatkozásba be lehessen építeni. Ám akkor is egyszerűbbnek vélem, ha a globális változók egy kupacban a főprogramban vannak. Még trükközni sem kell.
    Mutasd a teljes hozzászólást!
  • Nos, a fentiek alapján egy megoldás (a trükkös):

    Az első modulod változatlan:

    program1 segment assume cs:program1, ds:program1 org 100h EXTRN masfileban:proc start: call masfileban int 20h program1 ends end start

    A második:

    program2 segment assume cs:program2, ds:program2 PUBLIC masfileban masfileban proc call holvagyunk holvagyunk: pop bx sub bx,3 push 0b800h pop es xor di,di mov ah,15 mov al,byte ptr[betu+bx] mov es:[di],ax ret masfileban endp betu db "1" program2 ends end

    Üdv:
    Mutasd a teljes hozzászólást!
  • az ASSUME azért kell (???) hogy a fordító tudja hogy éppen melyik szegmens van hozzárendelve az adott szegmens regiszterhez, de nem fogja inicializálni egyiket sem...
    az assume-nek az adathivatkozásoknál van inkább szerepe, a köv példa ez szemlélteti:

    code segment assume cs:code,ds:code mov ax,adat ... ... adat dw 0 code ends

    a forditás után a kapott kód MOV AX,[XXXX]
    lesz, ahol az XXXX helyén az adat címe szerepel, de tegyük fel hogy feledékeny valaki:

    code segment assume cs:code mov ax,adat ... ... adat dw 0 code ends

    ebben az esetben a lefordított kód MOV AX,CS:[XXXX] lesz, mert a DS-hez nincs szegmens párosítva...

    ja és nem push ds, pop cs hanem forditva, ez pedig azért kellene hogy a DS be legyen állítva, de ha valóban com-ot kapsz, akkor nincs rá szükség, de nem árt ha ott van...

    ha tényleg COM fájl-t kapsz a végén, akkor valóban nem fontos a szegmens regisztereket piszkálnod, de ha az eredeti programmal így sem jelenik meg semmi, akkor csak azt tudom elképzelni, hogy a képernyő scroll miat 'kifut' a karakter, vagy előtte beírtál egy mode mono parancsot
    ezért esetleg ne az első sorba probáld írni hanem a tizedikbe, 80 oszlopos képernyőmód esetén a DI-be 160*y kerüljön, ahol az y a sor száma nullától kezdve

    push 0b800h pop es mov di,(160*10) ; nem 1600 ám mov ah,15
    Mutasd a teljes hozzászólást!
  • Megnézem, remélem müxik

    Aműgy ez exe módra is így van?
    Mutasd a teljes hozzászólást!
  • hát most nem tudom, hogy te ezt télleg komolyan gondolod, vagy csak viccelsz, ha az első eset áll, akkor hogy néz ki egy szimpla ret, valami jmp kellene helyette, meg a mov es:[di],ax helyet egy stosw...
    Mutasd a teljes hozzászólást!
  • Nem. A COM file éppen abban (is) jelentősen különbözik az EXE file-októl, hogy ő egy egyszegmenses program. Az EXE file-ok teljesen más felépítésűek, több szegmenses programok. Egy ún. EXE file headerrel kezdődnek (amely többek között épp a szegmensek relokációját is tartalmazza, amely betöltéskor és indításkor fontos). Az op. rendszer is teljesen másképpen hajtja végre az egyiket és a másikat, pl. a belépési pont is bárhol lehet egy EXÉ-ben, míg a COM file-oknál ez mindig PSP:100H.
    Ha ASM programot írsz, memória modellt kell választanod és ennek megfelelően szegmenseket kell definiálnod: tiny, large, huge, stb.
    A tiny modell a COM, az összes többi EXE.
    Attól függően, melyik modellt választod, más-más módon kezeled a memóriát a szegmensregisztereken keresztül. Próbálj valami jó ASM könyvet szerezni, mert ezt így néhány sorban úgy sem lehet elmondani.
    Üdv:
    Mutasd a teljes hozzászólást!
  • Nem értelek. A programot kipróbáltam - sypor is rövidesen megteszi -, működik. Milyen JMP kellene a RET helyett?
    Felborulna a stack. A MOV ES:[DI],AX és a STOSW pedig - én úgy tudom - egy és ugyanaz.
    Üdv:
    Mutasd a teljes hozzászólást!
  • nem borul fel stack, hacsak nem azt akarjuk...

    pop bx
    loop1:
    cmp BYTE PTR cs:[bx],0cch
    jz loop1
    jmp bx

    de hogy legyen egy iret is:

    pop bx
    xor ax,ax
    push ax
    push cs
    mov ax,OFFSET loop1
    push ax
    iret
    loop1:
    cmp BYTE PTR cs:[bx],0cch
    jz loop1
    jmp bx

    természetesen még ezeket is lehetne szépiteni...


    A MOV ES:[DI],AX és a STOSW pedig nem éppen ua...
    Mutasd a teljes hozzászólást!
  • Pontosítanom kell: igaz, a két utasítás nem pontosan ugyanaz. Esetünkben viszont mindegy, mindkettővel egyformán működik (kipróbáltam). Üdv:
    Mutasd a teljes hozzászólást!
  • A kód amit írtál, ill. egy része:

    loop1:
    cmp BYTE PTR cs:[bx],0cch
    jz loop1

    Ha a BX értéke 0cch, akkor ez egy végtelen ciklus, mivel a BX értéke sosem változik meg a cikluson belül...
    Üdv:
    Mutasd a teljes hozzászólást!
  • ezek szerint nem vetted az adást...
    nem a bx tartalmát vizsgálom és valóban végtelen ciklusba megy - ez volt a cél, és hogy mi az a cc azon még gondolkodj...
    de ezek szeint de valóban komolyan gondoltad a 'trükkös' megoldást, na jó, akkor legyen az...
    Mutasd a teljes hozzászólást!
  • Mindenkinek köszönöm az eddigi válaszokat.

    Az ötletek nem rosszak, bár csak holnapra tudom megnézni, hogy ténylegesen működnek-e, így első olvasásra jónak tünnek.

    A téma elején Kapitány beszúrt két linket, melyen assembly-s forráskódok vannak(exe) példával.
    Ott is egy csomó Public és Extrn direktiva van, csak nem értem a forrás felépítését. Nem ismerem nagyon a Tasm beépített parancsait.(.segment...stb, bár sejtem mire való)

    Ha valaki mégis tudna valami hasznosat mondani, a felépítésröl annak nagyon örülnék, főleg ha meg is értem
    Mutasd a teljes hozzászólást!
  • Most értem csak haza, majd most elmélyülök a kódodban. Odáig rendben, hogy a 0cch az INT 3 debugger interrupt opkódja, de azt csakugyan nem értem, mit is akarsz ezzel, és hogyan keveredsz ki a végtelen ciklusból... Sebaj, majd csak rájövök...Üdv:
    Mutasd a teljes hozzászólást!
  • Az általam 'trükkösnek' nevezett megoldást végül azért választottam, mert sypor alapkérdése végülis arról szólt, hogy a változó(i)t a program2-ben deklarálhassa, megtartva a tiny memóriamodellt.
    Viszont most kérdeznem kell feléd: póbálgattam a kódjaidat, ill. kanyarítottam egy egyszerű kis programot:

    code segment assume cs:code,ds:code,es:code,ss:code org 100h start:mov bx,0ffffh mov byte ptr [bx],0cch xor ax,ax push ax push cs mov ax,offset loop1 push ax iret loop1:cmp byte ptr cs:[bx],0cch jz loop1 jmp bx int 20h code ends end start end

    Galád módon úgy írtam, hogy a ciklusba belezuhanjon. Odáig rendben van, hogy furmányos stackműveletek révén az IRET éppen a loop1-re tér vissza. Viszont ha ebbe belemegyünk, a JMP BX sosem hajtható végre, mert utána már csak a RESET gomb marad... Biztos hogy jól írtad amit akartál? Üdv:
    Mutasd a teljes hozzászólást!
  • jaj de figyelmetlen vagyok!!!
    a szegmensek neve mindenkét modulban különböző ezért télleg nem megy a 2. modulban ird át a nevét program1-re mint az első modulban volt...
    de ha ajánlhatok valamit akkor célszerű általánosan elfogadott segmens azonositókat használnod
    pl. a kód minden modulban legyen _TEXT
    az adat segmens DATA nevet kapja
    ha több adatszegmensed van akkor ezeket egy csoportba gyüjtheted a GROUP operátorral, ennek a neve DGROUP legyen
    Mutasd a teljes hozzászólást!
Tetszett amit olvastál? Szeretnél a jövőben is értesülni a hasonló érdekességekről?
abcd