Добро пожаловать! Это — архивная версия форумов на «Хакер.Ru». Она работает в режиме read-only.
 

Вновь оптимизация.

Пользователи, просматривающие топик: none

Зашли как: Guest
Все форумы >> [Компилируемые языки] >> Вновь оптимизация.
Имя
Сообщение << Старые топики   Новые топики >>
Вновь оптимизация. - 2011-12-13 20:53:02.530000   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
void PushDouble(double Digit) { Instruction Instruct; /* PUSH Part 1 */ Instruct.Type = CG_BINARY; Instruct.Size = 5; Instruct.Data = (void*) malloc(5); (PBYTE(Instruct.Data))[0] = 0x68; memcpy(&(PBYTE(Instruct.Data))[1], &(PBYTE((void*)&Digit))[4], 4); AddInstruction(CurrentFunction, &Instruct); /* PUSH Part 2 */ Instruct.Type = CG_BINARY; Instruct.Size = 5; Instruct.Data = (void*) malloc(5); (PBYTE(Instruct.Data))[0] = 0x68; memcpy(&(PBYTE(Instruct.Data))[1], &(PBYTE((void*)&Digit))[0], 4); AddInstruction(CurrentFunction, &Instruct); }
Я так понимаю не выйдет оптимизировать подобные конструкции. Имеется ввиду визуально.
Post #: 1
RE: Вновь оптимизация. - 2011-12-14 01:26:37.670000   
_SaZ_

Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
Параметры для memcpy можешь отдельно высчитать со всеми кастами. Да и вообще, имхо, с кастами там перебор =)
Post #: 2
RE: Вновь оптимизация. - 2011-12-14 17:17:49.293333   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
Без этого перебора, никак. Придумал заменить эти касты одним понятным макросом. Будет лучше думаю.
Post #: 3
RE: Вновь оптимизация. - 2011-12-14 17:52:08   
_SaZ_

Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
Собственно в идеале можно вообще практически без кастов писать, особенно таких изощрённых… если на с++
Post #: 4
RE: Вновь оптимизация. - 2011-12-14 19:25:12.846666   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
Можно пример?
Post #: 5
RE: Вновь оптимизация. - 2011-12-14 19:46:36.886666   
_SaZ_

Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
Пример чего?
Post #: 6
RE: Вновь оптимизация. - 2011-12-14 20:07:27.230000   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
А ты как думаешь? Тут вроде не сложно догадаться. Как ты хочешь реализовать на С++ что конечный код будет лучше по всем параметрам текущего?
Post #: 7
RE: Вновь оптимизация. - 2011-12-14 22:58:08.026666   
_SaZ_

Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
Никак, т.к. ты не привёл текущего кода. Вернее самого главного - объявления типов данных.
Post #: 8
RE: Вновь оптимизация. - 2011-12-14 23:44:33.060000   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
Instruct.Type – DWORD
Instruct.Size – DWORD
Instruct.Data – PVOID

// уже так просто не развернешь, в двух словах добавляет в двусвязный список структуру.
AddInstruction(CurrentFunction, &Instruct);
Post #: 9
RE: Вновь оптимизация. - 2011-12-15 10:04:53.613333   
_SaZ_

Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
Для начала:
Instruct.Data – BYTE * // какая максимальная длина буфера? если в пределах 8-16 байт, то имеет смысл сделать тупо массив, без лишних выделений памяти

Далее:
void PushCustom( BYTE *data, const size_t size ) { // проверка size на кратность четырём чуть усложнит цикл static const size_t block_size = 4; for ( size_t ofs = size - block_size; ofs &gt;= 0; ofs -= block_size ) { Instruction Instruct; Instruct.Type = CG_BINARY; Instruct.Size = block_size + 1; Instruct.Data = new BYTE[ Instruct.Size ]; // освобождать через delete [] Instruct.Data Instruct.Data[0] = 0x68; memcpy( &Instruct.Data[1], &data[ofs], block_size ); // Никаких кастов и "волшебных чисел" тут не нужно. AddInstruction(CurrentFunction, &Instruct); } } Если объяснишь, сколько должно быть таких функций (PushDouble, PushChar, PushInt и т.п.) и хоть чуть-чуть про их логику - подумаем дальше.
И не забудь, что есть такие вещи, как BE и LE. Хотя судя по дефайнам типа PVOID и DWORD у тебя 32-х битная винда, так что косяков не будет.
Post #: 10
RE: Вновь оптимизация. - 2011-12-15 12:54:11.130000   
rgo

Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
(PBYTE(Instruct.Data))[0] = 0x68; memcpy(&(PBYTE(Instruct.Data))[1], &(PBYTE((void*)&Digit))[4], 4); Тут я могу сказать одно, то что есть, сильно-то красивее не сделаешь. Надо брать и переделывать всё, начиная с функции AddInstruction. Я может не совсем понимаю о чём речь идёт, но, по-моему, надо сесть и написать функцию:enum opcodes { OC_PUSH = 0x68, OC_POP = 0x58, OC_KILL_KENNY = 0, ... }; void add_instruction(enum opcodes op_code, ...) { va_list args; va_start(args, op_code); case(op_code) { case OC_PUSH: { double arg = va_arg(args, double); /* добавляем arg куда надо.*/ } } }Если при добавлении arg его всё же надо пилить на два куска, то проще всего это сделать так:union { double d; int arr[2]; } arg = {.d = va_arg(args, double)};После этого нам будут доступны младшие и старшие биты дабла под именами arg.arr[0] и arg.arr[1].

Поскольку непонятно вообще о чём речь, сложно сказать что именно надо. Может надо взять, написать скрипт, который пробежится по документации на систему команд, и напишет за нас enum и add_instruction так, чтобы уже не надо было бы высчитывать биты. А может просто надо разбить все команды на типы, на каждый тип создать по структурке, и заполнять битовые поля структурки вручную? А может вообще задвинуть на все структуры и если уж код генерится автоматически, то пускай он хоть утонет в нужных и ненужных преобразованиях типов, лишь бы наружу из него эти преобразования не торчали, чтобы в клиентском коде не возиться с ними? Тут ведь не угадаешь, пока задача не известна. Может быть лучше взять существующий ассемблер в сорцах и копипастом выдрать из него всю инфраструктуру для представления отдельной инструкции и работы с этими инструкциями.
Post #: 11
RE: Вновь оптимизация. - 2011-12-15 18:19:54.396666   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
_SaZ_

memcpy( &Instruct.Data[1], &data[ofs], block_size );
Это понятно, но тогда предается касты юзать передавая аргумент. В общем-то же самое, только в профиль.

rgo
Тут я могу сказать одно, то что есть, сильно-то красивее не сделаешь. Надо брать и переделывать всё, начиная с функции AddInstruction. Я может не совсем понимаю о чём речь идёт, но, по-моему, надо сесть и написать функцию:
Такая функция уже написана.

union { double d; int arr[2]; } arg = {.d = va_arg(args, double)};
Вот это думаю будет интересно.

Суть-то в чем, что бы по красивее оформить-то что мне нужно, double компилятор представляет в виде 64 битного числа. Который мне нужно разбить на два 32 разрядных, и в две структуры поместить. В общем представить double как два DWORD.

quote:

Instruct.Data – BYTE * // какая максимальная длина буфера?


Максимальная не знаю, но думаю в 16 может уложится. Но типов различных 20 штук, в том числе есть такой, где засовывается две строки сепарируемые восклицательным знаком. А макс. длина строки до 80 байт может быть в теории.
Post #: 12
RE: Вновь оптимизация. - 2011-12-15 19:25:19.233333   
rgo

Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
quote:

Такая функция уже написана.

Да, я видел. Но на том что есть, красиво-то не сделаешь. Надо выполнять кучу ручной работы, типа заполнения структур, приведения типов, выделения памяти и пр. И для каждой инструкции придётся писать много-много букв. И это кривой подход по-определению: если надо писать много-много однотипных функций, то писать их вручную нельзя. И даже не потому, что как в учебниках пишут: легко ошибку совершить – ошибку можно выловить отладкой и тестами, – дело не в этом, а в том, что если потом вдруг захочется в struct instruction добавить ещё одно поле, надо модифицировать каждую из этих однотипных функций.

Я бы вообще пошёл бы декларативным путём, объявил бы массив данных описывающих генерацию инструкций, и единую функцию (сравнительно небольшую, просто микроскопическую), которая бы имея на входе опкод и аргументы создавала бы инструкцию (или последовательность инструкций) согласно правилам. Да, при этом можно было бы всю это декларативность одеть обёрткой поверх существующей AddInstruction, но если AddInstruction сводится к list_push_back(instruction), то возиться с созданием обёртки для обёртки над list_push_back считаю нерациональным.
Ну да, при этом, машкод x86 убог до невозможности, классифицировать его опкоды сложно, но в инете валяется куча таких классификаций в уже готовом варианте. Найти такую классификацию в текстовом виде, или в виде html и скормить скрипту – не так уж и сложно. Даже с учётом всей сложности x86 это максимум на день работы. На выходе же получится полноценный кодогенератор x86, причём легко модифицируемый, поскольку кода в нём совсем немного, а данные, при необходимости, несложно и в другой формат перевести – "рефакторинг" данных это тебе не рефакторинг кода. Данные можно и самописными утилитами рефакторить, для кода же нужны либо платные утилиты, либо всё ручками, ручками, как папы карло.

quote:

Максимальная не знаю, но думаю в 16 может уложится. Но типов различных 20 штук, в том числе есть такой, где засовывается две строки сепарируемые восклицательным знаком. А макс. длина строки до 80 байт может быть в теории.

struct instruction { бла-бла-бла; int size; unsigned char data[0]; /* при использовании не-gcc надо объявлять массив одного элемента */ }; struct instruction* new_instruction(int size) { struct instruction *p = malloc (sizeof(*p) + size); /* для не-gcc: sizeof(*p) + size - 1 */ p-&gt;size = size; return p; }Правда при таком подходе будут проблемы с выделением такой структуры на стеке, но при желании можно выкрутиться макросом с использованием alloca, либо можно объявить:union instruction { struct instruction i; struct { struct instruction i; char str[MAX_DATA_LEN]; } };И потом, обычным объявлением переменной, объявлять её типом union, и выделять таким образом память с запасом.
Post #: 13
RE: Вновь оптимизация. - 2011-12-17 01:22:02.300000   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
Обновил gcc до последней версии, размер ехе в конечном счете стало в два раза больше. К чему столько лишнего добавили? И как избавится?

К примеру для чего TLS директорию создают, если у меня однопоточное приложение.
Секцию .eh_frame

Добавил к makefile'у

quote:

COMPILER=C:\MinGW\bin\g++.exe -s -static


Что бы в импорте не добавлялись dll лишние. С ними размер еще более менее приличный, как в старой используемой мной gcc(3.4.5), но чуть больше.

added:

В общем пришел к выводу, либо использовать последний gcc с опцией -static, и увеличеным конечным размером в два раза, + еще уйма ненужных вещей. Либо использовать старый gcc.
Post #: 14
RE: Вновь оптимизация. - 2011-12-17 16:50:21.786666   
Sunzer

Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
quote:

test.cpp:14:87: предупреждение: deprecated conversion from string constant to &lt;char*&gt; [-Wwrite-strings]


Еще по поводу этого, для фикса достаточно const добавить, т.к. компилятор в read-only секцию кладет эти данные, соответственно понятно почему появляется предупредение.

1) Как отключить предупреждение? В документации не нашел.

quote:

char *tmp = "test\n"


Как создать эту строку, доступную для изменения.

Нашел пару ссылок.

http://gcc.gnu.org/ml/gcc/2005-04/msg01257.HТМL
Post #: 15
RE: Вновь оптимизация. - 2011-12-17 19:55:06.406666   
rgo

Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
Предупреждение отключить можно элементарно: -Wno-write-strings. Другое дело как создать строку доступную для изменения… По ссылке которую ты привёл есть один способ. Правда я бы делал не совсем так как написано там… Тебе ведь строковый литерал нужен доступный для изменения? Ну тогда примерно так:void foo() { static char s[] = "нихерасебе"; *(uint16_t*)(s+3) = (((uint16_t)(unsigned char)'я') &lt;&lt; 8) + (uint16_t)(unsigned char)'у'; s[5] = ' '; printf("%s\n", s); }Такой подход неудачен тем, что если строка "нихерасебе" используется много раз, то она будет в .data иметь столько же копий, сколько и использований. С этим можно бороться так:char *s = strdup("hello world");Но тут придётся отслеживать строку, чтобы вовремя сказать free(s).

Есть ещё один путь… Тёмный и сложный… С учётом того, что ты так возишься с размером бинарника, по-моему этот третий – самый что ни на есть твой способ. Надо взять linker script для Portable Executable и переделать его под свои нужды. Например мергнув .const и .data воедино. И заказать у gcc линковку при помощи модифицированного скрипта.
Post #: 16
RE: Вновь оптимизация. - 2011-12-17 19:57:26.253333   
rgo

Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
А, ну да. Можно обойтись без strdup просто написав:int foo() { char s[] = "бла-бла-бла"; ... }Компилятор выделит память на стеке и скопирует туда строку из .const.
Post #: 17
Страниц:  [1]
Все форумы >> [Компилируемые языки] >> Вновь оптимизация.







Связаться:
Вопросы по сайту / xakep@glc.ru

Предупреждение: использование полученных знаний в противозаконных целях преследуется по закону.