Assembly 64bit függvényhívás

Assembly 64bit függvényhívás
2013-02-05T14:43:11+01:00
2013-02-06T16:57:24+01:00
2022-11-28T05:05:43+01:00
sqs
Abban szeretnék segítséget kérni, hogy 64 bites Assemblyben (Delphi + Assembly64) hogy kell olyan függvényt meghívni, amelynek több mint 4 paramétere van?

Az tiszta, hogy az első 4 paraméter az RCX,RDX,R8,R9 regiszterbe kerülnek, de azt nem értem, hogy
a "többi pedig a stack-be" részt hogy kell megvalósítani? A függvényen belül hogy tudom elérni a "többi" paramétert és hogy tudom helyesen kitölteni a paraméterlistát?

Az a helyzet is érdekelne, amikor a függvényen belül új függvényhívás is van, pl. egy rekurziónál.

Hogy kell kitölteni egy olyan függvény paraméterlistáját (4 paraméteren felül) ahol nem tudom mi történik a paraméterekkel a függvényen belül, pl. amikor egy Windows-os dll-ből hívok függvényt.

Köszönöm a segítséget!
Mutasd a teljes hozzászólást!
Szerintem a shadow area-t hagytad ki, meg a stack helyreállítását:

push rcx dec rcx mov r10,[RBP+64] //7. paraméter push r10 mov r10,[RBP+56] //6. paraméter push r10 mov r10,[RBP+48] //6. paraméter push r10 sub rsp,32 call fakt64 add rsp,56 pop rcx // a szorzó mul rcx

(Szerk: az előzőt végül is nem akartam elküldeni, de rám ijesztettek, és a 'Mehet'-re kattintottam)
Mutasd a teljes hozzászólást!

  • > a "többi pedig a stack-be" részt hogy kell megvalósítani?

    A PUSH-t javasolnám.

    > A függvényen belül hogy tudom elérni a "többi" paramétert

    Mint 16-biten a BP-vel, 32-biten az EBP-vel, ugyanúgy itt az RBP-vel. (Elnézést, javítottam, az RPB az a Request Parameter Bereich DCAM-ban, és nincs köze ehhez a kérdéshez.)

    > és hogy tudom helyesen kitölteni a paraméterlistát?

    Ezt nem értem.

    > Az a helyzet is érdekelne, amikor a függvényen belül új függvényhívás is van, pl. egy rekurziónál.

    Kicsit pontosabban a kérdés?

    > Hogy kell kitölteni egy olyan függvény paraméterlistáját (4 paraméteren felül) ahol nem tudom mi történik a paraméterekkel a függvényen belül, pl. amikor egy Windows-os dll-ből hívok függvényt.

    Mit jelent nálad 'egy függvény paraméterlistájának kitöltése'?
    Mutasd a teljes hozzászólást!
  • Paraméterlista kitöltése:
    mov rcx,1 //1.paraméter
    mov rdx,2 //2.paraméter
    mov r8,3 //3.paraméter
    mov r9,4 //4.paraméter

    és a "többi" paramétert csak push-al tegyem bele a stack-be. jogos.

    Amikor a függvényen belül szeretném használni a "többi paramétert" akkor csak az RBP-t ráállítva kiveszem?

    A rekurziós kérdésemet úgy értettem, hogy amikor új függvényhívás van függvényen belül hogy kell beállítani az rbp értékét, hogy ki tudjam olvasni a "többi" paramétert?
    Mutasd a teljes hozzászólást!
  • > Amikor a függvényen belül szeretném használni a "többi paramétert" akkor csak az RBP-t ráállítva kiveszem?

    Az segít, hogy pont úgy, mint 32-biten az EBP-vel? (Egyébként ez most stand-alone Assembly program, vagy Delphi-be beleágyazott Assembly kódrészlet?)

    > A rekurziós kérdésemet úgy értettem, hogy amikor új függvényhívás van függvényen belül hogy kell beállítani az rbp értékét, hogy ki tudjam olvasni a "többi" paramétert?

    Megegyezés kérdése, hogy mely regisztereket kell menteni a hívottnak, és melyeket ronthatja el. Tipikusan a *BP-t a hívottnak el kell mentenie, és kilépéskor visszaállítania.

    Calling convention - Wikipedia, the free encyclopedia
    x86 calling conventions - Wikipedia, the free encyclopedia
    Mutasd a teljes hozzászólást!
  • Használd a debuggert és lesd el a dephitôl, hogy hogyan csinalja!

    Te is csinalhatsz, egy functiont, amit meghivsz altalad ismert parameterekkel, majd egy breakpointtal megfogod a hivasnal.
    Illetve egy windows funkciohivast is ki lehet debugolni. Igy lathatod, hogy a delphi hogyan pakolja rá a parametereket.

    function(a,b,c,d,e,f:integer):integer; begin result:=a+b+c+d+e+f; end; ... a(1,2,3,4,5,6) <- ide johet a breakpoint, aztan Ctrl+Alt+C
    En kapasbol egy ilyet debugolnek ki... DE! Abbol a 16 regiszterbol biztos, hogy csak 4-et hasznal parameteratadasra? 32biten 8-bol 3-at hasznalt...

    Aztan vannak a kulonbozo calling conventionok, szerintem az 64biten sem lett egyszéges.
    Mutasd a teljes hozzászólást!
  • > Az segít, hogy pont úgy, mint 32-biten az EBP-vel?
    A 32bit kimaradt, csak 16biten és 64biten Assemblyzek.

    Azt tudom, hogy
    RAX,RCX,RDX,R8,R9,R10,R11 rutinban elromolhat, szabadon mentés nélkül
    RBX,RBP,RDI,RSI,R12,R13,R14,R15 rutinban el kell menteni, nem szabad rontani

    Az a homályos, hogy a függvényben hogy tudok hivatkozni a 4 paraméter fölötti paraméterekre.

    Ez Delphibe ágyazott Assembly. De ugye 64 biten úgy van, hogy nem lehet akárhova inline asm-et írni, csak rutinokat, ami tisztán ASM vagy tisztán Delphi. Nem lehet/szabad keverni!

    Olyan ASM függvényeim vannak, amelyek meg is hivogatják egymást vagy rekurzió esetén önmagukat.
    Mutasd a teljes hozzászólást!
  • > > Az segít, hogy pont úgy, mint 32-biten az EBP-vel?
    > A 32bit kimaradt, csak 16biten és 64biten Assemblyzek.
    Akkor mint 16-biten a BP-vel.

    > Az a homályos, hogy a függvényben hogy tudok hivatkozni a 4 paraméter fölötti paraméterekre.

    [RBP+32] 7. paraméter
    [RBP+24] 6. paraméter
    [RBP+16] 5. paraméter
    [RBP+8] visszatérési cím
    [RBP+0] RBP elmentett előző értéke

    Vagy hasonló...
    Mutasd a teljes hozzászólást!
  • Jé ugyanaz lett a calling conv a delphiben, mint a VS-ben

    "For example, a function taking 5 integer arguments will take the first to fourth in registers, and the fifth will be pushed on the top of the shadow space. So when the called function is entered, the stack will be composed (in ascendant order) the return address, by the shadow space (32 bytes) followed by the fifth parameter."

    Hát nem aprózza el az MS a stack memoriat, nem art vigyazni a rekurziv hivasokkal.
    Mutasd a teljes hozzászólást!
  • Épp akartam írni, hogy a leírásokból úgy tűnik, hogy van ottan 4*8 byte kihasználatlan ('shadow'), ez esetben így nézne ki:

    [RBP+64] 7. paraméter
    [RBP+56] 6. paraméter
    [RBP+48] 5. paraméter
    [RBP+16] 32 byte nem használt
    [RBP+8] visszatérési cím
    [RBP+0] RBP elmentett előző értéke
    Mutasd a teljes hozzászólást!
  • Van nekem egy jól működő faktoriális számító rekurzív progim, azon kísérleteztem a több paraméteres függvényhívással. (1 paraméterrel helyesen működik)

    Erre jutottam a több paramétert illetően, de nem jó, mert nem tudom mit kellene csinálni az rbp-vel. Az első meghívásig jó, utána már nem.


    function fakt64(n,a,b,c,d,e,f:UInt64):UInt64; asm cmp rcx,0 //n=0? jnz @tovabb mov rax,1 jmp @vegeez @tovabb: cmp rcx,1 //1-e már? jnz @nemegy //nem egy, akkor csinálja a rekurziót mov rax,rcx // Visszatérési érték! jmp @vegeez //1, akkor vége @nemegy: push rcx dec rcx mov r10,[RBP+64] //7. paraméter push r10 mov r10,[RBP+56] //6. paraméter push r10 mov r10,[RBP+48] //6. paraméter push r10 call fakt64 pop rcx // a szorzó mul rcx @vegeez: end;
    Mutasd a teljes hozzászólást!
  • Faktoriális számításámál minek 7 paramétrer?

    A függvényhívás a debugger-ben való megfigyelésem szerint általában így működik:
    -Fene tudja miért, de fontos a 16 byte align-itás. Az rsp alsó 4 bitje legyen 0 a call hívásnál.
    -Még a call előtt le szokták csökkenteni az rsp-t:
    0..4 paraméternél: 4*8 byte-tal (32=20h)
    5..6 paraméternél: 6*8 (48=30h)
    7..8 paraméternél: 8*8 (64=40h)
    9..10-nél 10*8 (80=50h)
    11..12-nél 12*8 (60h) Ilyen pl. a CreateWindowExA.
    ...
    Tehát ahány paraméter van, annyiszor 8 byte, de ha páratlan van, akkor többet az alignitás miatt.
    Ezután az első 4 paraméter a regiszterekbe (rcx,rdx,r8,r9)
    mov [rsp+20h],5.par
    mov [rsp+28h],6.par
    ...
    -utána jön a call
    -utána a főprogram növeli vissza az rsp-t (add-dal, nem a ret-ben!)

    A szubrutinban:
    push rbp mov rbp,rsp and rsp,-16 ;16 byte alignitas mov ...,[rbp+30h] ;30h=48 5. parameter mov ...,[rbp+38h] ;6. parameter ...

    A végére:
    leave ret
    vagy:
    mov rsp,rbp pop rbp ret

    Persze, ha saját szubrutint írsz mondjuk puszta assembly-ben, akkor mindegy, hogyan adod át a paramétereket, csak ezek a standard dolgok hagynak valami kívánnivalót maguk után.
    Mutasd a teljes hozzászólást!
  • Mutasd a teljes hozzászólást!
  • Név szerint nem lehet elérni a paramétereket?
    Tippem:

    function fakt64(n,a,b,c,d,e,f:UInt64):UInt64; asm cmp n,0 //n=0? jnz @tovabb mov rax,1 jmp @vegeez @tovabb: cmp n,1 //1-e már? jnz @nemegy //nem egy, akkor csinálja a rekurziót mov rax,rcx // Visszatérési érték! jmp @vegeez //1, akkor vége @nemegy: push f push e push d sub sp,32 mov r9,c mov r8,b mov rdx,a mov rcx,n dec rcx call fakt64 add sp,56 @vegeez: end;
    Mutasd a teljes hozzászólást!
  • Szerintem a shadow area-t hagytad ki, meg a stack helyreállítását:

    push rcx dec rcx mov r10,[RBP+64] //7. paraméter push r10 mov r10,[RBP+56] //6. paraméter push r10 mov r10,[RBP+48] //6. paraméter push r10 sub rsp,32 call fakt64 add rsp,56 pop rcx // a szorzó mul rcx

    (Szerk: az előzőt végül is nem akartam elküldeni, de rám ijesztettek, és a 'Mehet'-re kattintottam)
    Mutasd a teljes hozzászólást!
  • Így már tiszta!

    sub rsp,32 //kihagyni az árnyékrészt call fakt64 add rsp,56 //56=paraméterszám*8
    Mutasd a teljes hozzászólást!
  • 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