Форум программистов
 

Восстановите пароль или Зарегистрируйтесь на форуме, о проблемах и с заказом рекламы пишите сюда - alarforum@yandex.ru, проверяйте папку спам!

Вернуться   Форум программистов > IT форум > Помощь студентам
Регистрация

Восстановить пароль

Купить рекламу на форуме - 42 тыс руб за месяц

Ответ
 
Опции темы Поиск в этой теме
Старый 10.10.2015, 11:47   #1
Abrokadawr
 
Регистрация: 03.11.2011
Сообщений: 8
По умолчанию Объяснить логику работы ассемблерного кода

Всем привет. Собственно, есть С++-листинг функции :
Код:
double getPi(const uint64_t mCount)
{
	double result = 0;

	for (uint64_t i = 0; i < mCount; i++)
	{
		result += ((double)(i % 2 == 0 ? 1 : -1)) / ((double)(2 * i + 1));
	}

	return result * 4;
}
Помогите разобраться со сгенерированным ассемблерным кодом для этой функции (вообще не понимаю, что происходит). Столкнулся с разбором asm-листингов впервые, поэтому очень трудно воспринимать такой код , даже узнав назначение всех регистров и инструкций, здесь использованных. Был бы очень благодарен за каждую закомментированную строчку.

Вот, собственно, код (на адреса и сишные строки кода не обращайте внимания):

Код:
double getPi(const uint64_t mCount)
{
00BA1670  push        ebp  								 
00BA1671  mov         ebp,esp  							 
00BA1673  sub         esp,2Ch  							 
	double result = 0;
00BA1676  movsd       xmm0,mmword ptr ds:[0BA4298h]  	
00BA167E  movsd       mmword ptr [result],xmm0  

	for (uint64_t i = 0; i < mCount; i++)
00BA1683  xorpd       xmm0,xmm0  
00BA1687  movlpd      qword ptr [ebp-0Ch],xmm0  

	for (uint64_t i = 0; i < mCount; i++)
00BA168C  jmp         getPi+30h (0BA16A0h)  
00BA168E  mov         eax,dword ptr [ebp-0Ch]  
00BA1691  add         eax,1  
00BA1694  mov         ecx,dword ptr [ebp-8]  
00BA1697  adc         ecx,0  
00BA169A  mov         dword ptr [ebp-0Ch],eax  
00BA169D  mov         dword ptr [ebp-8],ecx  
00BA16A0  mov         edx,dword ptr [ebp-8]  
00BA16A3  cmp         edx,dword ptr [ebp+0Ch]  
00BA16A6  ja          getPi+0B1h (0BA1721h)  
00BA16A8  jb          getPi+42h (0BA16B2h)  
00BA16AA  mov         eax,dword ptr [ebp-0Ch]  
00BA16AD  cmp         eax,dword ptr [mCount]  
00BA16B0  jae         getPi+0B1h (0BA1721h)  
	{
		result += ((double)(i % 2 == 0 ? 1 : -1)) / ((double)(2 * i + 1));
00BA16B2  push        0  
00BA16B4  push        2  
00BA16B6  mov         ecx,dword ptr [ebp-8]  
00BA16B9  push        ecx  
00BA16BA  mov         edx,dword ptr [ebp-0Ch]  
00BA16BD  push        edx  
00BA16BE  call        _aullrem (0BA3330h)  
00BA16C3  mov         dword ptr [ebp-14h],eax  
00BA16C6  mov         dword ptr [ebp-10h],edx  
00BA16C9  mov         eax,dword ptr [ebp-14h]  
00BA16CC  or          eax,dword ptr [ebp-10h]  
00BA16CF  jne         getPi+6Ah (0BA16DAh)  
00BA16D1  mov         dword ptr [ebp-4],1  
00BA16D8  jmp         getPi+71h (0BA16E1h)  
00BA16DA  mov         dword ptr [ebp-4],0FFFFFFFFh  
00BA16E1  cvtsi2sd    xmm0,dword ptr [ebp-4]  
00BA16E6  push        0  
00BA16E8  push        2  
00BA16EA  mov         ecx,dword ptr [ebp-8]  
00BA16ED  push        ecx  
00BA16EE  mov         edx,dword ptr [ebp-0Ch]  
00BA16F1  push        edx  
00BA16F2  movsd       mmword ptr [ebp-24h],xmm0  
00BA16F7  call        _allmul (0BA32F0h)  
00BA16FC  add         eax,1  
00BA16FF  adc         edx,0  
00BA1702  mov         ecx,eax  
00BA1704  call        _ultod3 (0BA36BEh)  
00BA1709  movsd       xmm1,mmword ptr [ebp-24h]  
00BA170E  divsd       xmm1,xmm0  
00BA1712  addsd       xmm1,mmword ptr [result]  
00BA1717  movsd       mmword ptr [result],xmm1  
	}
00BA171C  jmp         getPi+1Eh (0BA168Eh)  

	return result * 4;
00BA1721  movsd       xmm0,mmword ptr [result]  
00BA1726  mulsd       xmm0,mmword ptr ds:[0BA42A0h]  
00BA172E  movsd       mmword ptr [ebp-2Ch],xmm0  
00BA1733  fld         qword ptr [ebp-2Ch]  
}
Abrokadawr вне форума Ответить с цитированием
Старый 10.10.2015, 12:33   #2
Stilet
Белик Виталий :)
Старожил
 
Аватар для Stilet
 
Регистрация: 23.07.2007
Сообщений: 57,097
По умолчанию

А для чего, если не секрет, реверсируешь?
Академический интерес?
I'm learning to live...
Stilet вне форума Ответить с цитированием
Старый 10.10.2015, 12:55   #3
Abrokadawr
 
Регистрация: 03.11.2011
Сообщений: 8
По умолчанию

Цитата:
Сообщение от Stilet Посмотреть сообщение
А для чего, если не секрет, реверсируешь?
Академический интерес?
Лабораторная в ВУЗе
Abrokadawr вне форума Ответить с цитированием
Старый 10.10.2015, 13:17   #4
p51x
Старожил
 
Регистрация: 15.02.2010
Сообщений: 15,770
По умолчанию

А что вам не понятно? Код же читаем с небольшими оптимизациями, да и комментарии есть...
p51x вне форума Ответить с цитированием
Старый 10.10.2015, 13:32   #5
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Код:
double getPi(const uint64_t mCount)
{
// Выделяем в стеке память для локальных переменных 
00BA1670  push        ebp      // Сохраняем ebp в стеке, что-бы потом восстановить
00BA1671  mov         ebp,esp  // Заносим в EBP верхушку стека.  							 
00BA1673  sub         esp,2Ch  // Увеличиваем стек(стек росёт всегда вниз) на размер локальных переменных							 
	double result = 0;
// В ассемблере нет иструкции память-память поэтому, заносим константу в Result, в две инструкции.
00BA1676  movsd       xmm0,mmword ptr ds:[0BA4298h]  // Загружаем в нижнюю часть xmm0 размером double константу из 0BA4298h
                                                     // mmword ptr - смена типа указателя на mmword.
                                                     // Логика такова что указателю присваеваем размер равный 64 бита
00BA167E  movsd       mmword ptr [result],xmm0       // Заносим константу в result

	for (uint64_t i = 0; i < mCount; i++)
00BA1683  xorpd       xmm0,xmm0  		     // Обнуляем весь xmm0. (xmm0=0) Но через xor быстрее, так как операция не сериальная.	
00BA1687  movlpd      qword ptr [ebp-0Ch],xmm0       // По адресу [ebp-0Ch] лежит переменная i. Обнуляем её путем копирования нижней части xmm0

	for (uint64_t i = 0; i < mCount; i++)
00BA168C  jmp         getPi+30h (0BA16A0h)          // Прыгаем на андрес 0BA16A0h видимо там тело цикла
// Инкриментое увеличение переменной i на 1 (i++).
// Код не оптимизирован. По идее он должен лежать в конце тела цикла но почему-то попал сюда.

00BA168E  mov         eax,dword ptr [ebp-0Ch]       // загружаем нижнюю часть переменной i в eax                                                        
00BA1691  add         eax,1                         // Прибавляем единицу, резльтат попадает в EAX, в случае переполнения
                                                    // В CF попадает 1, инача 0. 
00BA1694  mov         ecx,dword ptr [ebp-8]         // загружаем верхнюю часть переменной i в eсx
00BA1697  adc         ecx,0                         // Прибавляем ноль плюс бит переноса CF  
00BA169A  mov         dword ptr [ebp-0Ch],eax       // Кладём результат в переменную i  
00BA169D  mov         dword ptr [ebp-8],ecx
//  Начало тело цикла проверяем условие  i < mCount   
00BA16A0  mov         edx,dword ptr [ebp-8]         // В edx кладём верхнюю часть i
00BA16A3  cmp         edx,dword ptr [ebp+0Ch]       // Сравниваем edx с верхнюю частью mCount
00BA16A6  ja          getPi+0B1h (0BA1721h)         // Если >, то выходим из цикла, иначе 
00BA16A8  jb          getPi+42h (0BA16B2h)          // Если <, то выполняем цикл, иначе
                                                    // Сюда попадаем если =
00BA16AA  mov         eax,dword ptr [ebp-0Ch]       // В edx кладём нижнюю часть i
00BA16AD  cmp         eax,dword ptr [mCount]        // Сравниваем нижние части
00BA16B0  jae         getPi+0B1h (0BA1721h)         // Если >= то выходим из цикла
	{
		result += ((double)(i % 2 == 0 ? 1 : -1)) / ((double)(2 * i + 1));
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 10.10.2015, 13:33   #6
Pavia
Лис
Старожил
 
Аватар для Pavia
 
Регистрация: 18.09.2015
Сообщений: 2,409
По умолчанию

Код:
		result += ((double)(i % 2 == 0 ? 1 : -1)) / ((double)(2 * i + 1));
// Пошёл код.
// Для получения остатка от деления на 2 вызываем _aullrem  
// Инициируем параметрам для _aullrem.
// Для вызова параметры кладутся в стек
// push заносит в стек DWord поэтому константа 2 заносится в 2 приеёма.
00BA16B2  push        0  // Верхняя часть 2 
00BA16B4  push        2  // Нижняя часть 2
// Заносим в стек  переменную i 
00BA16B6  mov         ecx,dword ptr [ebp-8]  
00BA16B9  push        ecx  
00BA16BA  mov         edx,dword ptr [ebp-0Ch]  
00BA16BD  push        edx  

00BA16BE  call        _aullrem (0BA3330h)  // Вызываем _aullrem 
                                           // u-unsigned, ll- Long Long, rem-%
// Ризульт 64 битный заносим в локальную переменную                     
00BA16C3  mov         dword ptr [ebp-14h],eax  
00BA16C6  mov         dword ptr [ebp-10h],edx  
// В верху будет всегда 0 так как 2 меньше 32 бит
00BA16C9  mov         eax,dword ptr [ebp-14h]  
00BA16CC  or          eax,dword ptr [ebp-10h]  // сравниваем с нулём
00BA16CF  jne         getPi+6Ah (0BA16DAh)    // Прыгаем если !=, иначе
00BA16D1  mov         dword ptr [ebp-4],1     // Присваеваем 1 в [ebp-4]
00BA16D8  jmp         getPi+71h (0BA16E1h)    
00BA16DA  mov         dword ptr [ebp-4],0FFFFFFFFh //  Присваеваем -1 в [ebp-4]
                                                   //  0FFFFFFFFh это в дополненном коде -1
00BA16E1  cvtsi2sd    xmm0,dword ptr [ebp-4]       // Преобразуем знаковое целое Integer из [ebp-4]
						  // В один Double который клодем в нижнюю часть xmm0
// Умножаем 64 битную переменную i на коснтанту 2.
// push заносит в стек DWord поэтому константа 2 заносится в 2 приёма.
00BA16E6  push        0   
00BA16E8  push        2  
00BA16EA  mov         ecx,dword ptr [ebp-8]  
00BA16ED  push        ecx  
00BA16EE  mov         edx,dword ptr [ebp-0Ch]  
00BA16F1  push        edx  
// На всякий "пожарный" случай, чтобы _allmul не попортила xmm0 сохраняем её значения в локальную переменную.
// "пожарный" - смотри соглаение о вызовах.
00BA16F2  movsd       mmword ptr [ebp-24h],xmm0  
00BA16F7  call        _allmul (0BA32F0h)  // Вызов умножения
// Результат заносится в eax:edx

00BA16FC  add         eax,1  // Прибавляем единицу
00BA16FF  adc         edx,0  // Прибавляем бит переноса(CF) от предыдущей команды
00BA1702  mov         ecx,eax // Сохроняем eax в ecx 
00BA1704  call        _ultod3 (0BA36BEh) //  Преобразуем eax:edx в double и заносим результат в xmm0
// Деление
00BA1709  movsd       xmm1,mmword ptr [ebp-24h]  
00BA170E  divsd       xmm1,xmm0  // Делим часлитель на знаменатель
00BA1712  addsd       xmm1,mmword ptr [result]  // xmm1+=result 
00BA1717  movsd       mmword ptr [result],xmm1  // result=xmm1
	}
00BA171C  jmp         getPi+1Eh (0BA168Eh)   // Прыгаем в вверх, где у нас инкримент I++ 
                                             и дальнейшее сравнение условия цикла.

// Тут выход из цикла. Далее идёт умножение результата на 4
	return result * 4;
00BA1721  movsd       xmm0,mmword ptr [result]        // Загружаем в нижнюю часть xmm0, result 
00BA1726  mulsd       xmm0,mmword ptr ds:[0BA42A0h]  // Умножаем нижнюю часть xmm0, на константу
00BA172E  movsd       mmword ptr [ebp-2Ch],xmm0      // Заносим реультат во временную переменную
00BA1733  fld         qword ptr [ebp-2Ch]            // Копируем результат в регистр FPU.ST(0)   
}
Хорошо поставленный вопрос это уже половина ответа. | Каков вопрос, таков ответ.
У дзен программиста программа делает то что он хотел, а не то что он написал .
Pavia вне форума Ответить с цитированием
Старый 10.10.2015, 14:15   #7
Abrokadawr
 
Регистрация: 03.11.2011
Сообщений: 8
По умолчанию

Pavia, спасибо большое, очень выручил
Abrokadawr вне форума Ответить с цитированием
Ответ


Купить рекламу на форуме - 42 тыс руб за месяц



Похожие темы
Тема Автор Раздел Ответов Последнее сообщение
Объяснить кода shadow155 Visual C++ 1 19.06.2015 02:11
JavaScript выпадающее меню,объяснить часть кода Alina111 Помощь студентам 1 10.10.2014 15:47
Назначение участка ассемблерного кода Schmidt Assembler - Ассемблер (FASM, MASM, WASM, NASM, GoASM, Gas, RosAsm, HLA) и не рекомендуем TASM 10 17.07.2013 19:09
объяснить поведение кода denis7656 JavaScript, Ajax 6 24.04.2012 23:15
Преобразование ассемблерного кода в опкоды kaledonia007 Компоненты Delphi 4 26.03.2011 23:48