is_реклам:

пошук, категорії та ін. показати ▼

Гулівер в Асемблері

Гулівер в Асемблері
автор опубліковано


Зараз ми дещо відхилимося від обговорення команд. Припустимо, що Ви хочете перевірити чи було значення 0x12345678, яке спершу знаходилось в регістрі EBP, коректно завантажено в 32-розрядну змінну counter. Наступний фрагмент коду заносить значення 0x12345678 в змінну counter:

mov ebp, 0x12345678	;завантажуємо в EBP значення 0x12345678  
mov [counter], ebp	;зберігаємо значення EBP в змінну-лічильник

Для того, щоб перевірити, було завантажено значення чи ні, треба скористатися відладчиком. Розумію, що Ви поки що не знаєте ні того, як скомпілювати програму, ні того, як завантажити її у відладчик, але давайте уявимо, що це вже зроблено за Вас.

Як буде виглядати відкомпільована програма у відладчику? Відладчик перетворює всі команди з машинного коду назад в мову Асемблер. Все точно так само, як ми написали, тільки з невеликими змінами: всюди, де ми використовували символьне ім'я змінної, воно буде замінено реальною адресою змінної, наприклад:

0804808А	BD78563412	mov ebp, 0x12345678
0804808F	892DC0900408	mov dword [+0x80490c0], ebp

Перший стовпчик — це реальна адреса команди в пам'яті, другий — машинний код, в який перетворилась команда після компіляції. Після цього ми бачимо символьне представлення машинної команди в мнемокодах Асемблера. Символьне ім'я нашої змінної counter було замінено адресою цієї змінної в пам'яті (+0x80490c0).

Перед виконанням першої команди, mov ebp, 0x12345678, регістри процесора містили наступні значення:

eax = 0x00000000	ebx = 0x00000000	ecx = 0x00000000	edx = 0x00000000
esp = 0xBFFFF910	ebp = 0x00000000	esi = 0x00000000	edi = 0x00000000
ds  = 0x0000002B	es  = 0x0000002B	fs  = 0x00000000	gs  = 0x00000000
ss  = 0x0000002B	cs  = 0x00000023	eip = 0x0804808A	eflags=0x00200346
Flags: PF ZF TF IF ID

Після виконання першої команди значення регістра EBP було замінено значенням 0x12345678. Якщо переглянути дамп пам'яті за адресою нашої змінної (0x80490c0), то ми побачимо наступне:

Dumping 64 bytes of memory starting at 0x80490C0 in hex
80490C0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00

Коли буде виконана друга команда MOV, значення 0x12345678 буде записано в пам'ять за адресою 0x80490c0 і дамп пам'яті покаже інший результат:

Dumping 64 bytes of memory starting at 0x80490C0 in hex
80490C0: 78 56 34 12 00 00 00 00 00 00 00 00 00 00 00 00 xV4

Потрібне значення (0x12345678) дійсно було записано за адресою 0x80490c0, але чомусь задом наперед. Справа в тому, що всі x86-процесори відносяться до класу LITTLE_ENDIAN, тобто зберігають байти слова або подвійного слова в порядку від найменш значимого до найбільш значимого ( "little-end-first", молодшим байтом вперед). Процесори BIG_ENDIAN (наприклад, Motorola) чинять навпаки: розміщують найбільш значимий байт за меншою адресою ("big-end-first", старшим байтом вперед).

Цікаво, що терміни LITTLE_ENDIAN і BIG_ENDIAN — це не просто скорочення: воно походять від назв партій-суперниць в Ліліпутії "гостроконечників" і "тупоконечників" з "Подорожей Гулівера" Джонатана Свіфта, звідси і назва :) "Гостроконечники" і "тупоконечники", у Свіфта їли яйця з різних сторін, одні — з гострого кінця, інші — з тупого. В результаті суперечки з приводу того, як правильніше, виникла війна, а далі... якщо не пам'ятаєте, деталі в книжці.

Порядок слідування байтів в слові (подвійному слові) враховується не тільки при збереженні, але і при передачі даних. Якщо у Вас є невеликий досвід програмування, можливо, Ви стикалися з "гостроконечниками і тупоконечниками" при розробці мережевих додатків, коли деякі структури даних треба було перетворювати до "тупоконечного" виду за допомогою спеціальних функцій (htonl, htons, ntohl, ntohs).

Коли змінна counter буде прочитана назад в регістр, там виявиться оригінальне значення, тобто 0x12345678.

Що почитати на цю тему? Рудольф Марек. Ассемблер на примерах. Базовый курс.

схоже за тегами

Залишити коментар:

Яндекс цитирования UA TOP Bloggers