NOVINKA - Online rekvalifikační kurz Python programátor. Oblíbená a studenty ověřená rekvalifikace - nyní i online.
Hledáme nové posily do ITnetwork týmu. Podívej se na volné pozice a přidej se do nejagilnější firmy na trhu - Více informací.
Avatar
Caster
Člen
Avatar
Caster:20.11.2022 22:08

Funkcí Crypto v x64 asm spočítám hash SHA-1. Výsledkem je číslo (160 bitů tj. 20 bytů) uložené ve tvaru 5x uint32_t viz např.:
7e 19 30 a4 26 9d ee 54 1f 3c a9 04 4a b3 6b 72 e4 20 d9 76

Výstupem funkce Crypto je jedno číslo 64 bit deklarované jako pointer na začátek paměti, kdy je uložen výsledek hashe. Vstupem pak počet opakování generování hashe, aby se dala spočítat rychlost programu v x64 asm (je nutno použít minimálně 1 mil. opakování). V C++ trvá jeden výpočet cca 100*E-9 sekundy.

Zkusil jsem:

extern "C" __int64 Crypto(__int64);
__int64 value = 1;      // Počet cyklů generování hashe
uint64_t* result;

int main()
{
    result = (uint64_t*)Crypto(value);
    printf("Hodnota: %x\n", (uint32_t)result);
}

Funkce Crypto vrátí adresu začátku paměti `0x00007FF62F7EE158 `na které je 5 uint32_t hodnot:
7e 19 30 a4 26 9d ee 54 1f 3c a9 04 4a b3 6b 72 e4 20 d9 76

Print ale zobrazí:
Hodnota: 2f7ee158

Chci docílit: Abych správně vytiskl všech 5 uint32_t vypočítaných hodnot.

 
Odpovědět
20.11.2022 22:08
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:21.11.2022 1:41

Vůbec nepracuješ s hodnotou, neprovádíš dereferenci ukazatele. Když znáš adresu počátku 5 hodnot typu uint32_t, tak abys mohl vytáhnout všechny uint32_t hodnoty, musíš adresu přetypovat na základní datový typ který chceš z paměťového bloku tahat. Tedy na (uint32_t*). Na tuto přetypovanou adresu spolu s aplikovanou ukazatelovou aritmetikou s ohledem na základní datový typ v počtu iterací rovno počtu vytahovaných uint32_t hodnot aplikuješ dereferenci adres uložených hodnot.

#include <stdio.h>
#include <stdint.h>

#define COUNT 5

int main(void) {
        // blok paměti s uloženými 5 uint32_t hodnotami
        unsigned char val[] = {0x7e, 0x19, 0x30, 0xa4,
                               0x26, 0x9d, 0xee, 0x54,
                               0x1f, 0x3c, 0xa9, 0x04,
                               0x4a, 0xb3, 0x6b, 0x72,
                               0xe4, 0x20, 0xd9, 0x76
        };

        // přetypování adresy na požadovaný základní datový typ
        uint32_t* address = (uint32_t*)val;

        // vytažení a vypsání 5 uint32_t hodnot z paměťového bloku
        for (size_t i = 0; i < COUNT; i++) {
                printf("%08x\n", *(address + i));
        }

        return 0;
}
Nahoru Odpovědět
21.11.2022 1:41
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Caster:21.11.2022 10:10

Teoreticky mi je sice jasné, že pointer na datový typ musí být stejného typu jako proměnná. Problém je ale v tom, že typ proměnné není definován v C++ programu ale v asm funkci a k dispozici mám jen 64 bit pointer na začátek pole dat, proměnné jsou přitom 32 bitové. Přitom nechci nic složitého. Na adrese v paměti začíná pole 5 proměnných uint32_t a jen je chci vypsat,

Program jsem trochu upravil a už začal vypisovat první proměnnou i když k překlad hlásí varování:
C4477 Zprintf: Formátovací řetězec %x vyžaduje argument typu unsigned int, ale variadický argument 1 má typ uint64_t
Zvažte použití %llx ve formátovacím řetězci.
Zvažte použití %lx ve formátovacím řetězci.
Zvažte použití %I64x ve formátovacím řetězci.

Upravený výpis:

uint64_t* result;

printf("Hodnota: %08x\n", *result);

V "čisté" verzi C++ programu (bez asm funkce) vypisuji hodnoty takto:

#include <immintrin.h>

__m256i sha1;  // AVX2

void p256_hex_u32(__m256i in) {
    alignas(32) uint32_t v[8];
    _mm256_maskstore_epi32((int*)v, _mm256_setr_epi32(-1, -1, -1, -1, -1, 0, 0, 0), in);
    printf("v8_u32: %x %x %x %x %x\n", v[0], v[1], v[2], v[3], v[4]);

main ()
{
   ...
   sha1 = _mm256_setr_epi32(h0, h1, h2, h3, h4, 0, 0, 0);  // Uložení 5ti uint32_t hodnot do proměnné _mm256 (ymm v asm)
   p256_hex_u32(sha1);  // Tisk 5ti hodnot (maska uloží jednotlivé hodnoty v obráceném pořadí (setr = set reverse) jen pokud je nejvyšší bit masky "1" tj. -1
   ...
}
 
Nahoru Odpovědět
21.11.2022 10:10
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:21.11.2022 11:37

k dispozici mám jen 64 bit pointer na začátek pole dat, proměnné jsou přitom 32 bitové.

Však víc nepotřebuješ znát.

Ještě jednou:

Přetypuj pointer na pointer na typ dat, která chceš z paměťového bloku tahat. Aplikuj ukazatelovou aritmetiku pro přesun na adresu prvku, dereferencuj adresu prvku, iteruj.

Nepotřebuješ žádnou funkci. Pouze jednu proměnnou pro uložení přetypovaného ukazatele.

Podívej se znovu na kompletní program co jsem Ti prvotně poslal. Je tam úplně vše ukázané a zřetelně popsané.

Nahoru Odpovědět
21.11.2022 11:37
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Odpovídá na DarkCoder
Caster:21.11.2022 12:11

Díky, ale to nejsou stejné podmínky, jako mám já. Zapomeň na:

unsigned char val[] = {0x7e, 0x19, 0x30, 0xa4,
                      0x26, 0x9d, 0xee, 0x54,
                      0x1f, 0x3c, 0xa9, 0x04,
                      0x4a, 0xb3, 0x6b, 0x72,
                      0xe4, 0x20, 0xd9, 0x76
        };

K dispozici máš pouze jednu 64 bitovou proměnnou, např. 0x00007FF62F7EE158, která obsahuje adresu na začátek pole dat v paměti a vypiš 5 náhodných uint32_t z paměti svého počítače ;-)

Ukázka části x64 asm funkce pro výpočet SHA-1:

    xor r9, r9  ; cyklus 80, for (int r9 = 0; r9 < 80; r9++)
L_loop:
    cmp r9, 16
    jb L_temp   ; index < 15
    mov rbx, r9
    sub rbx, 16             ; index i - 16
    mov eax, [r8+rbx*4+52]  ; [i-3]
    xor eax, [r8+rbx*4+32]  ; [i-8]
    xor eax, [r8+rbx*4+8]   ; [i-14]
    xor eax, [r8+rbx*4]     ; [i-16]
    rol eax, 1
    mov [r8+r9*4], eax      ; [i]
L_temp:
    mov eax, r11d
    rol eax, 5
    add eax, r15d
    add eax, [r8+r9*4]
    mov r10d, eax           ; temp = rotl32_5(a) + e + pole[i];
    cmp r9, 19
    ja L_40
    mov eax, r12d
    and eax, r13d
    mov edx, r12d
    not edx
    and edx, r14d
    or eax, edx
    add eax, 5A827999h
    add r10d, eax           ; temp += ((b & c) | ((~b) & d)) + 0x5A827999;
L_40:
 
Nahoru Odpovědět
21.11.2022 12:11
Avatar
Caster
Člen
Avatar
Caster:21.11.2022 12:35

Ještě doplním, že podobný problém jsem již řešil před pár lety pomocí DWORD, adresa je 64 bit pointer na začátek pole v paměti. Je nutné si uvědomit, že nečtu data z klasické paměti proměnných C++ ale ze skutečné RAM paměti počítače (proměnné použité v externí x64 asm funkci nebo třeba alokací 8 GB RAM).

DWORD r = *(DWORD *)(adresa + (l + i) * 125 + poz + 4);
 
Nahoru Odpovědět
21.11.2022 12:35
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:21.11.2022 12:45

Do třetice. Aplikuj to co jsem Ti napsal tučně v předchozím příspěvku.
Udělej toto:

uint64_t* result = adresa začátku bloku 5 uint32_t hodnot

uint32_t* address = (uint32_t*)result;

for (size_t i = 0; i < 5; i++) {
    printf("%08x\n", *(address + i));
}
Nahoru Odpovědět
21.11.2022 12:45
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Caster:21.11.2022 13:01

Díky, překlad proběhl úplně v pohodě bez jakýchkoliv chyb. Po spuštění (Debug) ale hlásí, že Došlo k výjimce: porušení přístupu pro čtení.

 
Nahoru Odpovědět
21.11.2022 13:01
Avatar
DarkCoder
Člen
Avatar
Odpovídá na Caster
DarkCoder:21.11.2022 13:17

Takto to samozřejmě nemůžeš udělat. address Ti neobsahuje adresu result. Není to double pointer aby četl hodnotu ukazatele při jeho změně. Ty musíš aplikovat přetypování po aktualizaci result. Používej lokální proměnné nikoli globální.

uint64_t* result = (uint64_t*)Crypto(value);

uint32_t* address = (uint32_t*)result;

for (size_t i = 0; i < 5; i++) {
    printf("%08x\n", *(address + i));
}
Akceptované řešení
+20 Zkušeností
+2,50 Kč
Řešení problému
Nahoru Odpovědět
21.11.2022 13:17
"I ta nejlepší poučka postrádá na významu, není-li patřičně předána." - DarkCoder
Avatar
Caster
Člen
Avatar
Caster:21.11.2022 13:24

Bezva, díky za tvou pomoc, už to funguje ;-).

86e018b3
0992e073
27f74aa0
5ec5a54a
61d90985
 
Nahoru Odpovědět
21.11.2022 13:24
Děláme co je v našich silách, aby byly zdejší diskuze co nejkvalitnější. Proto do nich také mohou přispívat pouze registrovaní členové. Pro zapojení do diskuze se přihlas. Pokud ještě nemáš účet, zaregistruj se, je to zdarma.

Zobrazeno 10 zpráv z 10.