Вновь оптимизация.
Пользователи, просматривающие топик: 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);
} Я так понимаю не выйдет оптимизировать подобные конструкции. Имеется ввиду визуально.
|
|
|
RE: Вновь оптимизация. - 2011-12-14 01:26:37.670000
|
|
|
_SaZ_
Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
|
Параметры для memcpy можешь отдельно высчитать со всеми кастами. Да и вообще, имхо, с кастами там перебор =)
|
|
|
RE: Вновь оптимизация. - 2011-12-14 17:17:49.293333
|
|
|
Sunzer
Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
|
Без этого перебора, никак. Придумал заменить эти касты одним понятным макросом. Будет лучше думаю.
|
|
|
RE: Вновь оптимизация. - 2011-12-14 17:52:08
|
|
|
_SaZ_
Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
|
Собственно в идеале можно вообще практически без кастов писать, особенно таких изощрённых… если на с++
|
|
|
RE: Вновь оптимизация. - 2011-12-14 19:25:12.846666
|
|
|
Sunzer
Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
|
Можно пример?
|
|
|
RE: Вновь оптимизация. - 2011-12-14 19:46:36.886666
|
|
|
_SaZ_
Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
|
Пример чего?
|
|
|
RE: Вновь оптимизация. - 2011-12-14 20:07:27.230000
|
|
|
Sunzer
Сообщений: 253
Оценки: 31190
Присоединился: 2007-06-15 19:23:32.436666
|
А ты как думаешь? Тут вроде не сложно догадаться. Как ты хочешь реализовать на С++ что конечный код будет лучше по всем параметрам текущего?
|
|
|
RE: Вновь оптимизация. - 2011-12-14 22:58:08.026666
|
|
|
_SaZ_
Сообщений: 4329
Оценки: 398
Присоединился: 2008-01-30 02:18:05.553333
|
Никак, т.к. ты не привёл текущего кода. Вернее самого главного - объявления типов данных.
|
|
|
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);
|
|
|
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 >= 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-х битная винда, так что косяков не будет.
|
|
|
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 так, чтобы уже не надо было бы высчитывать биты. А может просто надо разбить все команды на типы, на каждый тип создать по структурке, и заполнять битовые поля структурки вручную? А может вообще задвинуть на все структуры и если уж код генерится автоматически, то пускай он хоть утонет в нужных и ненужных преобразованиях типов, лишь бы наружу из него эти преобразования не торчали, чтобы в клиентском коде не возиться с ними? Тут ведь не угадаешь, пока задача не известна. Может быть лучше взять существующий ассемблер в сорцах и копипастом выдрать из него всю инфраструктуру для представления отдельной инструкции и работы с этими инструкциями.
|
|
|
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 байт может быть в теории.
|
|
|
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->size = size;
return p;
} Правда при таком подходе будут проблемы с выделением такой структуры на стеке, но при желании можно выкрутиться макросом с использованием alloca, либо можно объявить:union instruction {
struct instruction i;
struct {
struct instruction i;
char str[MAX_DATA_LEN];
}
}; И потом, обычным объявлением переменной, объявлять её типом union, и выделять таким образом память с запасом.
|
|
|
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.
|
|
|
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 <char*> [-Wwrite-strings] Еще по поводу этого, для фикса достаточно const добавить, т.к. компилятор в read-only секцию кладет эти данные, соответственно понятно почему появляется предупредение. 1) Как отключить предупреждение? В документации не нашел. quote:
char *tmp = "test\n" Как создать эту строку, доступную для изменения. Нашел пару ссылок. http://gcc.gnu.org/ml/gcc/2005-04/msg01257.HТМL
|
|
|
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)'я') << 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 линковку при помощи модифицированного скрипта.
|
|
|
RE: Вновь оптимизация. - 2011-12-17 19:57:26.253333
|
|
|
rgo
Сообщений: 7170
Оценки: 281
Присоединился: 2004-09-25 05:14:25
|
А, ну да. Можно обойтись без strdup просто написав:int foo()
{
char s[] = "бла-бла-бла";
...
} Компилятор выделит память на стеке и скопирует туда строку из .const.
|
|
|
|
|