Diskuze: Tisk hodnot z paměti
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.

Člen

Zobrazeno 10 zpráv z 10.
//= Settings::TRACKING_CODE_B ?> //= Settings::TRACKING_CODE ?>
V předchozím kvízu, Online test znalostí C++, jsme si ověřili nabyté zkušenosti z kurzu.
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;
}
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
...
}
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é.
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:
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);
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));
}
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í.
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));
}
Zobrazeno 10 zpráv z 10.