| RSS



Меню

Bookmark and Share


Статистика
Ваш IP: 3.144.248.24
Вы используете: v





Сейчас на сайте:

Тех поддержка ->

Облако тэгов
ОС видио Tor Обратная сторона антенна 4.6 PHP Эксплоит Windows Server 2008 qip Virtual chroot kernel proc sysctl tune FreeBSD bridge Boot Disk Bluetooth GEO game directx Emulator Python Shell DDoS червь Conficker вирус троян Лаборатория Касперского пиратство apple iPhone ИТ-отрасль Щеголев Microsoft экономический кризис Twitter социальная сеть анонимность Лицензия Open Source ASP.NET MVC уязвимость MySQL база данных файлообмен закон франция пират Skype мобильный Deutsche Telekom Хакер киберпреступник Trend Micro кибератака Германия робот утечка данных персональные данные ноутбук интернет Китай цензура ядро Linux Торвальдс Windows Vista Acer Linux патент браузер Firefox Internet Explorer Opera Net Applications Safari Intel Linux Foundation Moblin Oracle патч банкомат кардер HSM IBM X-Force Cofee сша кибервойна Эстония Dell ИТ-специалист хакерские атаки Pirate Bay контроль кибербезопасность язык программирования The Pirate Bay Пиратская партия утечка информации приговор Mozilla Chrome безопасность Госдума СМИ Windows 8 Баллмер взлом Пентагон ботнет Украина Facebook Cisco cloud Windows XP нетбук торрент музыка биометрический nokia ФБР IP-адрес CIPAV Comcast sms RSA java Google CAPTCHA Symantec спам конфиденциальная информация инсайдер Perimetrix антивирус тест Anti-Malware Windows 7 операционная система Windows провайдер авторское право RapidShare UNIX свиной грипп шантаж дети EFF BluWiki копирайт экстремизм Panda Security cloud computing McAfee Cybercrime Response Unit Bottle Domains HTTPS ICANN студент шпионское ПО Норвегия школьник New York Times XSS YouTube Warner Music кибершпионаж КНДР Ubuntu свободное ПО AMD ATI касперский Россия РФ сервер хостинг фальшивый антивирус Comodo CA Wi-Fi D-Link суд пароль блог фишинг Одноклассники медведев контрафакт мошенник штраф Sony GPS по Gumblar JAVASCRIPT хакеры вредоносное ПО Yahoo ФАС компьютер Софт MPAA кибероружие PandaLabs Red Hat Минкомсвязи сбой ASUSTeK Computer мошенничество Доктор Веб ВКонтакте Cyber-Arc исходный код PCI DSS МВД фильтр порнография BREIN свобода слова Казахстан GEMA Autodesk сисадмин Gmail кредитная карта кибермошенник LiveJournal шифрование криптография Deep Purple банк нанотехнологии Wikipedia zero-day ColdFusion выборы кража данных DNS BIND Android BASIC атака Black Hat Mac OS X Click Forensics Clampi домен фсб Прокуратура Уголовное дело icq Barrelfish киберпреступность Sophos AT&T ошибка Electa Gamma Knife OpenBSD DARPA военные Сайт Visual Studio 2010 .NET Framework 4 Chrome OS электронная почта турция конференция спамер FTC полиция российская ОС Koobface Великобритания БЕЛОРУССИЯ грузия BSA Bittorrent облачные вычисления Azure Европа Dr.Web Билл Гейтс спецслужбы Cryzip Живой Журнал Royal Bank of Scotland смартфон Canonical Pwn2Own F-Secure Symbian Hotmail фильм

Главная » Статьи » Общие Статьи

brainfuck

Brainfuck, вероятно, это самый безумный язык программирования, который встречается на свете. Сам язык состоит всего из 8 операторов, которыми можно написать практически любую программу, которую вы хотите. Для работы вам понадобится: компилятор или интерпретатор (приводятся в конце статьи - компилятор на ассемблере, интерпретатор Brainfuck-C); ASCII таблица; вероятно калькулятор :).

Основы

Главная идея Brainfuck - манипулирование памятью. Вам выдается 30.000 массив 1 байтовых блоков, хотя на самом деле размер массива зависит от компилятора или интерпретатора, но стандартный размер - 30.000. Внутри этого массива вы можете увеличивать указатель, значение в ячейке и так далее. Для работы, как я уже говорил, используется 8 операторов:

> = увеличение указателя памяти или смещение право на 1 блок
< = уменьшение или смещение влево на 1 блок
+ = увеличение значения в ячейке памяти, на которую ссылается указатель
- = соответственно уменьшение на единиц
[ = аналог цикла while(cur_block_value != 0)
] = если значение в ячейке на которую указывает указатель не равно нулю, то переход на [
, = аналог getchar(), ввод одного символа
. = аналог putchar(), вывод одного сивола на кончоль

Вводные правил

  • Любые символы кроме описанных выше игнорируются
  • Все значения в памяти устанавливаются на 0 в начале работы программы
  • Циклов может быть сколько угодно, однако каждая [ должна заканчиваться]

И вернемся к нашим баранам. Напишем простую программу:

[-]

Что делается? По идее открывается цикл, уменьшается значение текущей ячейки на 1 и цикл продолжается до тех пор, пока значение не достигнет 0. Однако так как изначально все значения в памяти и есть 0, цикл никогда не начнется.

Напишем другую программу:

+++++[-]

На С это аналогично такой программе:

*p=+5;
while(*p != 0){
*p--;
}


В этой программе мы увеличили значение по указателю на 5, потом открыли цикл, который уменьшал значение до 0.

>>>>++

На выходе мы получим такой вид памяти.

Очевидно, что сначала мы увеличиваем указатель на 4 и затем два раза увеличиваем значение на 1 два раза. Разнообразим?

>>>>++<<+>>+

Получаем:

Опять же понятно, что сначала 2 записывается в четвертую ячейку, потом 1 во вторую и затем еще раз 1 прибавляется к 4.

Давайте напишем программу, которая будет уже выводить нечто в консоль, например любимый всеми нами "Hello world". Выглядит она так:

>+++++++++[<++++++++>-]<.>+++++++[<++++>-]<+.
+++++++..+++.[-]>++++++++[<++++>-] <.
>+++++++++++[<++++++++>-]<-.--------.+++
.------.--------.[-]>++++++++[<++++>- ]<+.[-]++++++++++.

Круто? Настоящий Brainfuck... Разберем что происходит. Надо помнить, что мы имеем дело с кодами ASCII для вывода, так что надо оперировать именно такими кодами.

Первая часть:

>+++++++++[<++++++++>-]<.

Сдвигаемся вправо, оставляя первую ячейку пустой, записываем туда 9, открываем цикл. В цикле смещаемся влево, записываем туда 8, смещаемся вправо и уменьшаем значение на единицу.

Цикл идет до тех пор, пока во второй ячейке не станет 0. Не слишком трудные вычисления покажут, что в конце работы программы в первой ячейки памяти будет 72, во второй 0. Это код буквы Н, поэтому выводим ее в консоль. Продолжаем для каждого символа и в конце концов получаем заветные Hello world! Занятно, не правда ли? :)


Ввод

Как уже было сказано, ввод в языке осуществляется оператором '.'. Он получает символ и в виде десятичного ASCII кода записывает в тот блок, на который указывает в настоящее время указатель. Напомню операторы:

> = увеличение указателя памяти или смещение право на 1 блок
< = уменьшение или смещение влево на 1 блок
+ = увеличение значения в ячейке памяти, на которую ссылается указатель
- = соответственно уменьшение на единиц
[ = аналог цикла while(cur_block_value != 0)
] = если значение в ячейке на которую указывает указатель не равно нулю, то переход на [
, = аналог getchar(), ввод одного символа
. = аналог putchar(), вывод одного символа на консоль

Итак, поэкспериментируем:

,.,.,.

Такая программа прочтет три символа с клавиатуры и тут же выведет их. Более полноценно:

>,[>,]<[<]>[.>]

Эта программа работает как юниксовая команда cat - читает из STDIN и выводит в STDOUT. Разберем как она работает: >, - смещает указатель вправо и читает код символа; [>,] - цикл, в котором указатель смещается вправо и читается символ до тех пор, пока строка не закончится символом NULL (\0 или десятичный нуль); <[<] - перемотка, смещение указателя влево по блокам до тех пор, пока не встретится ноль, а он у нас лежит, напомню, в самой первой ячейке; >[.>] - соответственно обратный процесс, смещение по блокам вправо до нуля и вывод символов.

На С это выглядело бы так:

++p;
*p=getchar();
while(*p != 0){
++p;
*p=getchar();
}
--p;
while(*p != 0) --p;
++p;
while(*p != 0){
putchar(*p);
++p;
}

Собственно, теперь мы знаем как вводить символы, как их выводить и как манипулировать памятью - этого вполне достаточно для написания программ :).

Фишки

Есть много вещей, которые сделают программирование на Brainfuck проще. Дабы каждый не открывал для себя Америку опишу некоторые.

Перенос блоков памяти.

+++++[>>+<<-]

Устанавливаем в первую ячейку 5, затем организуем цикл, в котором переносим значение из первой ячейки в третью, оставляя первую пустой.

Копирование из одного блока памяти в другой.

+++++[>>+>+<<<-]>>>[<<<+>>>-]

Опять 5 в первую ячейку, копируем в третью и четвертую, оставляя первую пустой. Затем переносим значение из четвертой обратно в первую. Данные скопированы!

Сложение двух ячеек памяти:

+++++>+++[<+>-]

Заносим 5 и 3, организуем цикл, в котором добавляем к первой ячейке единицу и вычитаем из второй единицу.

Вычитание:

+++++++>+++++[<->-]

Очевидно, что тут из 7 вычитается 5.

Умножение мы уже разбирали в примере вывода, однако повторим еще раз:

+++[>+++++<-]

Деление делается аналогично, только на основе вычитания :)

Напомню, что операторов в нем всего восемь:

> = увеличение указателя памяти или смещение право на 1 блок
< = уменьшение или смещение влево на 1 блок
+ = увеличение значения в ячейке памяти, на которую ссылается указатель
- = соответственно уменьшение на единиц
[ = аналог цикла while(cur_block_value != 0)
] = если значение в ячейке на которую указывает указатель не равно нулю, то переход на [
, = аналог getchar(), ввод одного символа
. = аналог putchar(), вывод одного символа на консоль

В прошлых статьях мы прошлись по вводу и выводу, рассмотрели разные особенности языка. Однако как же реализовать условия? Допустим, мы хотим ввести с клавиатуры код символа (x) в первый блок памяти, определить равен ли он 5 и если равен установить другое значение памяти (y) в 3. На С все это выглядит просто:

x=getchar;
if(x == 5)
{
y = 3;
}

В реальном BrainFuck это всего лишь такая программа:

,[>>+>+<<<-]>>>[<<<+>>>-]>+<<[-----[>]>>[<<<+++>>>[-]]

Рассмотрим что же происходит в программе:

, - ввод символа в первую ячейку памяти

[>>+>+<<<-]>>>[<<<+>>>-] - копирование из ячейки 1 в ячейку 3 используя 4 как временный буфер. Указатель остается на 4 ячейке.

Память на момент завершения выглядит так:

>+<< - запись 1 в 5 ячейку и возврат к 3.

Самая важная часть:

[-----[>]>>[<<<+++>>>[-]] - вычитаем из значения 5 и если оно именно таким и было пишем во вторую 3, возвращаемся к 5 ячейке и записываем туда 0 и в результате цикл будет работать всего один раз. Если исходное введенное значение не равно 5, указатель останавливается на ячейке 6. Соответственно, память у нас может остаться такой:

Первый вариант если х=5, второй если не равен. Это первый пример, в котором исходное значение не "разрушается". Можно все сделать гораздо проще, но при этом потерять введенное число, получив только результат сравнения.

>>+[<<,-----[>]>>[<<+++>>[-]]]

Надеюсь вы разберетесь с нею сами :).

А теперь о программах для работы:

Удачи :)



Компилятор написанный на С для BrainFack

/*
* obfc.c
* The "omin0us brainfuck compiler"
* omin0us
*
* A simple BrainFuck to C interpretor and font end Compiler.
*
* This program is free software; you can
* redistribute it and/or modify it under the
* terms of the GNU General Public License as
* published by the Free Software Foundation;
* either version 2 of the License or (at
* your option) any later version;
*
* This program is distributed in the hope
* that it will be useful but WITHOUT ANY
* WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR
* A PARTICULAR PURPOSE; See the GNU General
* Public License for more details;
*
* You may find a copy of the GNU General Public
* License on my web site at:
* http://dtors.ath.cx/gpl.txt
* or from the Free Software Foundation's web site at:
* http://www.fsf.org/licenses/gpl.html
*/

#include
#include
#include
#define CC "/usr/bin/gcc"

void usage(char **argv);
void generate(char *c_output_name);

FILE *outfile;
FILE *infile;


int main(int argc, char **argv){

char c;
char *output_name; /* name of the executable that will be made */
char *c_output_name; /* name of the C source file that is generated */
char compile_opts[256] = CC; /* this array will contain the compiler options */
int keep_file = 0; /* Keep the generated C source file? */
int verbose = 0; /* Use verbose output? */
int no_compile = 0; /* Don't compile, just generate C source file */

if(argc < 2){
usage(argv);
exit(1);
}

/* chk(argv); */

while(1){
c = getopt(argc, argv, "o:c:knvh");
if(c < 0) break;

switch(c){
case 'o':
output_name = optarg;
break;
case 'v':
verbose = 1;
break;
case 'h':
usage(argv);
break;
case 'k':
keep_file = 1;
break;
case 'c':
c_output_name = optarg;
break;
case 'n':
no_compile = 1;
keep_file = 1;
break;
}
}


if((optind >= argc) || (strcmp(argv[optind], "-") == 0)){
fprintf(stderr, "%s: no input file specified\n", argv[0]);
usage(argv);
exit(-1);
}

if(verbose)printf("[+] Opening %s...", argv[optind]);
if((infile = fopen(argv[optind], "r")) == 0){
if(verbose)printf("failed\n");
fprintf(stderr,"%s: could not open %s\n", argv[0], argv[optind]);
exit(-1);
}
if(verbose)printf("Ok\n");

if(!c_output_name)
c_output_name = "bf.out.c";

if(!output_name)
output_name = "bf.out";

if(verbose)printf("[+] Opening the output file...");
if((outfile = fopen(c_output_name, "w")) == 0){
if(verbose)printf("failed\n");
fprintf(stderr, "%s: error opening output file %s\n", argv[0],
c_output_name);
exit(-1);
}
if(verbose)printf("Ok\n");

if(verbose)printf("[+] Generating C source...");
generate(c_output_name);
if(verbose)printf("Ok\n");
fclose(outfile);
/*strcat(compile_opts, "/usr/bin/gcc");*/
strcat(compile_opts, " -o ");
strcat(compile_opts, output_name);
strcat(compile_opts, " ");
strcat(compile_opts, c_output_name);

if(!no_compile){
if(verbose){
printf("[+] Compiling...\n");
printf("Compiler: " CC "\n");
printf("Compile Options: %s\n", compile_opts);
}
system(compile_opts);
if(verbose)printf("Compiling Complete\n");
}

if(!keep_file){
if(verbose)printf("[+] Deleting intermediate file %s...", c_output_name);
unlink(c_output_name);
if(verbose)printf("Ok\n");
}
else
if(verbose)printf("[+] Keeping intermediate file %s...Ok\n",
c_output_name);

fclose(infile);
return(0);
}

void generate(char *c_output_name){
char c;

fprintf(outfile, "/*\n * This source was automatically generated with");
fprintf(outfile, "\n * obfc - The \"omin0us brainfuck compiler\".");
fprintf(outfile, "\n * omin0us ");
fprintf(outfile, "\n * \n */\n");
fprintf(outfile, "#include \n");
fprintf(outfile, "main() {\nchar a[30000],*ptr=a;\n");

while((c=fgetc(infile)) != EOF){
switch(c){
case '>': fprintf(outfile, "ptr++;\n"); break;
case '<': fprintf(outfile, "ptr--;\n"); break;
case '+': fprintf(outfile, "++*ptr;\n"); break;
case '-': fprintf(outfile, "--*ptr;\n"); break;
case '[': fprintf(outfile, "while(*ptr){\n"); break;
case ']': fprintf(outfile, "}\n"); break;
case '.': fprintf(outfile, "putchar(*ptr);\n"); break;
case ',': fprintf(outfile, "*ptr=getchar();\n"); break;
}
}
fprintf(outfile,"exit(0);\n}\n");
}



void usage (char *argv[]){

printf("obfc - the \"omin0us brainfuck compiler\"\n");
printf("by omin0us
printf("\n");
printf("Usage: %s [OPTIONS] [FILE]\n",argv[0]);
printf("Available Options:\n");
printf("\t-o outfile\tspecify output file name\n");
printf("\t-k\t\tkeep the generated C source (normally bf.out.c)\n");
printf("\t-c c_outfile\tspecify C source file name. Only used option-\n");
printf("\t\t\tally in conjunction with -k option\n");
printf("\t-n\t\tDon't compile the C source, just output a copy of it\n");
printf("\t-v\t\tverbose output\n");
printf("\t-h\t\tdisplay help\n");
}


Интерпритатор написанный на BrainFuck


[/* bf2c.b
* The omin0us Brainfuck to C interpretor
* omin0us <omin0us208@gmail.com>
*
* NOTE: This was written just before the release of K-1ine #44
* and consequently was rushed to be finished. Currently
* it does not take well to any characters of input besides
* the 8 standard brainfuck operators and newline and EOF.
* So consequently, it will only interpret un-commented code.
* Check my web site <http://dtors.ath.cx> for a later release
* that will probably have support for commented code.
*/]


>+++++[>+++++++<-]>.<<++[>+++++[>+++++++<-]<-]>>.+++++.<++[>-----<-]>-.<++
[>++++<-]>+.<++[>++++<-]>+.[>+>+>+<<<-]>>>[<<<+>>>-]<<<<<++[>+++[>---<-]<-
]>>+.+.<+++++++[>----------<-]>+.<++++[>+++++++<-]>.>.-------.-----.<<++[>
>+++++<<-]>>.+.----------------.<<++[>-------<-]>.>++++.<<++[>++++++++<-]>
.<++++++++++[>>>-----------<<<-]>>>+++.<-----.+++++.-------.<<++[>>+++++++
+<<-]>>+.<<+++[>----------<-]>.<++[>>--------<<-]>>-.------.<<++[>++++++++
<-]>+++.---....>++.<----.--.<++[>>+++++++++<<-]>>+.<<++[>+++++++++<-]>+.<+
+[>>-------<<-]>>-.<--.>>.<<<+++[>>++++<<-]>>.<<+++[>>----<<-]>>.++++++++.
+++++.<<++[>---------<-]>-.+.>>.<<<++[>>+++++++<<-]>>-.>.>>>[-]>>[-]<+[<<[
-],[>>>>>>>>>>>>>+>+<<<<<<<<<<<<<<-]>>>>>>>>>>>>>>[<<<<<<<<<<<<<<+>>>>>>>>
>>>>>>-]<<+>[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-[-
[-[-[-[-[-[-[-[-[-[-[-[<->[-]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]<[
<<<<<<<<<<<<[-]>>>>>>>>>>>>[-]]<<<<<<<<<<<<[<+++++[>---------<-]>++[>]>>[>
+++++[>+++++++++<-]>--..-.<+++++++[>++++++++++<-]>.<+++++++++++[>-----<-]>
++.<<<<<<.>>>>>>[-]<]<<<[-[>]>>[>++++++[>+++[>++++++<-]<-]>>++++++.-------
------.----.+++.<++++++[>----------<-]>.++++++++.----.<++++[>+++++++++++++
++++<-]>.<++++[>-----------------<-]>.+++++.--------.<++[>+++++++++<-]>.[-
]<<<<<<<.>>>>>]<<<[-[>]>>[>+++++[>+++++++++<-]>..---.<+++++++[>++++++++++<
-]>.<+++++++++++[>-----<-]>++.<<<<<<.>>>>>>[-]<]<<<[-[>]>>[>+++[>++++[>+++
+++++++<-]<-]>>-.-----.---------.<++[>++++++<-]>-.<+++[>-----<-]>.<++++++[
>----------<-]>-.<+++[>+++<-]>.-----.<++++[>+++++++++++++++++<-]>.<++++[>-
----------------<-]>.+++++.--------.<++[>+++++++++<-]>.[-]<<<<<<<.>>>>>]<<
<[<+++[>-----<-]>+[>]>>[>+++++[>+++++++++<-]>..<+++++++[>++++++++++<-]>---
.<+++++[>----------<-]>---.<<<<<<.>>>>>>[-]<]<<<[--[>]>>[>+++++[>+++++++++
<-]>--..<+++++++[>++++++++++<-]>-.<+++++[>----------<-]>---.[-]<<<<<<.>>>>
>]<<<[<+++[>----------<-]>+[>]>>[>+++[>++++[>++++++++++<-]<-]>>-.<+++[>---
--<-]>.+.+++.-------.<++++++[>----------<-]>-.++.<+++++++[>++++++++++<-]>.
<+++++++[>----------<-]>-.<++++++++[>++++++++++<-]>++.[-]<<<<<<<.>>>>>]<<<
[--[>]>>[>+++++[>+++++[>+++++<-]<-]>>.[-]<<<<<<<.>>>>>]<<<[<++++++++++[>--
--------------<-]>--[>]>>[<<<<[-]]]]]]]]]]]>>]<++[>+++++[>++++++++++<-]<-]
>>+.<+++[>++++++<-]>+.<+++[>-----<-]>.+++++++++++.<+++++++[>----------<-]>
------.++++++++.-------.<+++[>++++++<-]>.<++++++[>+++++++++++<-]>.<+++++++

+++.


Компилятор написанный на Ассемблере для BrainFack

;; bf.asm: Copyright (C) 1999-2001 by Brian Raiter, under the GNU
;; General Public License (version 2 or later). No warranty.
;;
;; To build:
;;nasm -f bin -o bf bf.asm && chmod +x bf
;; To use:
;;bf < foo.b > foo && chmod +x foo

BITS 32

;; This is the size of the data area supplied to compiled programs.

%define arraysize30000

;; For the compiler, the text segment is also the data segment. The
;; memory image of the compiler is inside the code buffer, and is
;; modified in place to become the memory image of the compiled
;; program. The area of memory that is the data segment for compiled
;; programs is not used by the compiler. The text and data segments of
;; compiled programs are really only different areas in a single
;; segment, from the system's point of view. Both the compiler and
;; compiled programs load the entire file contents into a single
;; memory segment which is both writable and executable.

%defineTEXTORG0x45E9B000
%defineDATAOFFSET0x2000
%defineDATAORG(TEXTORG + DATAOFFSET)

;; Here begins the file image.

orgTEXTORG

;; At the beginning of the text segment is the ELF header and the
;; program header table, the latter consisting of a single entry. The
;; two structures overlap for a space of eight bytes. Nearly all
;; unused fields in the structures are used to hold bits of code.

;; The beginning of the ELF header.

db0x7F, "ELF"; ehdr.e_ident

;; The top(s) of the main compiling loop. The loop jumps back to
;; different positions, depending on how many bytes to copy into the
;; code buffer. After doing that, esi is initialized to point to the
;; epilog code chunk, a copy of edi (the pointer to the end of the
;; code buffer) is saved in ebp, the high bytes of eax are reset to
;; zero (via the exchange with ebx), and then the next character of
;; input is retrieved.

emitputchar:addesi, byte (putchar - decchar) - 4
emitgetchar:lodsd
emit6bytes:movsd
emit2bytes:movsb
emit1byte:movsb
compile:leaesi, [byte ecx + epilog - filesize]
xchgeax, ebx
cmpeax, 0x00030002; ehdr.e_type (0x0002)
; ehdr.e_machine (0x0003)
movebp, edi; ehdr.e_version
jmpshort getchar

;; The entry point for the compiler (and compiled programs), and the
;; location of the program header table.

dd_start; ehdr.e_entry
ddproghdr - $$; ehdr.e_phoff

;; The last routine of the compiler, called when there is no more
;; input. The epilog code chunk is copied into the code buffer. The
;; text origin is popped off the stack into ecx, and subtracted from
;; edi to determine the size of the compiled program. This value is
;; stored in the program header table, and then is moved into edx.
;; The program then jumps to the putchar routine, which sends the
;; compiled program to stdout before falling through to the epilog
;; routine and exiting.

eof:movsd; ehdr.e_shoff
xchgeax, ecx
popecx
subedi, ecx; ehdr.e_flags
xchgeax, edi
stosd
xchgeax, edx
jmpshort putchar; ehdr.e_ehsize

;; 0x20 == the size of one program header table entry.

dw0x20; ehdr.e_phentsize

;; The beginning of the program header table. 1 == PT_LOAD, indicating
;; that the segment is to be loaded into memory.

proghdr:dd1; ehdr.e_phnum & phdr.p_type
; ehdr.e_shentsize
dd0; ehdr.e_shnum & phdr.p_offset
; ehdr.e_shstrndx

;; (Note that the next four bytes, in addition to containing the first
;; two instructions of the bracket routine, also comprise the memory
;; address of the text origin.)

db0; phdr.p_vaddr

;; The bracket routine emits code for the "[" instruction. This
;; instruction translates to a simple "jmp near", but the target of
;; the jump will not be known until the matching "]" is seen. The
;; routine thus outputs a random target, and pushes the location of
;; the target in the code buffer onto the stack.

bracket:moval, 0xE9
incebp
pushebp; phdr.p_paddr
stosd
jmpshort emit1byte

;; This is where the size of the executable file is stored in the
;; program header table. The compiler updates this value just before
;; it outputs the compiled program. This is the only field in the two
;; headers that differs between the compiler and its compiled
;; programs. (While the compiler is reading input, the first byte of
;; this field is also used as an input buffer.)

filesize:ddcompilersize; phdr.p_filesz

;; The size of the program in memory. This entry creates an area of
;; bytes, arraysize in size, all initialized to zero, starting at
;; DATAORG.

ddDATAOFFSET + arraysize; phdr.p_memsz

;; The code chunk for the "." instruction. eax is set to 4 to invoke
;; the write system call. ebx, the file handle to write to, is set to
;; 1 for stdout. ecx points to the buffer containing the bytes to
;; output, and edx equals the number of bytes to output. (Note that
;; the first byte of the first instruction, which is also the least
;; significant byte of the p_flags field, encodes to 0xB3. Having the
;; 2-bit set marks the memory containing the compiler, and its
;; compiled programs, as writeable.)

putchar:movbl, 1; phdr.p_flags
moval, 4
int0x80; phdr.p_align

;; The epilog code chunk. After restoring the initialized registers,
;; eax and ebx are both zero. eax is incremented to 1, so as to invoke
;; the exit system call. ebx specifies the process's return value.

epilog:popa
inceax
int0x80

;; The code chunks for the ">", "<", "+", and "-" instructions.

incptr:incecx
decptr:dececx
incchar:incbyte [ecx]
decchar:decbyte [ecx]

;; The main loop of the compiler continues here, by obtaining the next
;; character of input. This is also the code chunk for the ","
;; instruction. eax is set to 3 to invoke the read system call. ebx,
;; the file handle to read from, is set to 0 for stdin. ecx points to
;; a buffer to receive the bytes that are read, and edx equals the
;; number of bytes to read.

getchar:moval, 3
xorebx, ebx
int0x80

;; If eax is zero or negative, then there is no more input, and the
;; compiler proceeds to the eof routine.

oreax, eax
jleeof

;; Otherwise, esi is advanced four bytes (from the epilog code chunk
;; to the incptr code chunk), and the character read from the input is
;; stored in al, with the high bytes of eax reset to zero.

lodsd
moveax, [ecx]

;; The compiler compares the input character with ">" and "<". esi is
;; advanced to the next code chunk with each failed test.

cmpal, '>'
jzemit1byte
incesi
cmpal, '<'
jzemit1byte
incesi

;; The next four tests check for the characters "+", ",", "-", and
;; ".", respectively. These four characters are contiguous in ASCII,
;; and so are tested for by doing successive decrements of eax.

subal, '+'
jzemit2bytes
deceax
jzemitgetchar
incesi
incesi
deceax
jzemit2bytes
deceax
jzemitputchar

;; The remaining instructions, "[" and "]", have special routines for
;; emitting the proper code. (Note that the jump back to the main loop
;; is at the edge of the short-jump range. Routines below here
;; therefore use this jump as a relay to return to the main loop;
;; however, in order to use it correctly, the routines must be sure
;; that the zero flag is cleared at the time.)

cmpal, '[' - '.'
jzbracket
cmpal, ']' - '.'
relay:jnzcompile

;; The endbracket routine emits code for the "]" instruction, as well
;; as completing the code for the matching "[". The compiler first
;; emits "cmp dh, [ecx]" and the first two bytes of a "jnz near". The
;; location of the missing target in the code for the "[" instruction
;; is then retrieved from the stack, the correct target value is
;; computed and stored, and then the current instruction's jmp target
;; is computed and emitted.

endbracket:moveax, 0x850F313A
stosd
leaesi, [byte edi - 8]
popeax
subesi, eax
mov[eax], esi
subeax, edi
stosd
jmpshort relay

;; This is the entry point, for both the compiler and its compiled
;; programs. The shared initialization code sets eax and ebx to zero,
;; ecx to the beginning of the array that is the compiled programs's
;; data area, and edx to one. (This also clears the zero flag for the
;; relay jump below.) The registers are then saved on the stack, to be
;; restored at the very end.

_start:
xoreax, eax
xorebx, ebx
movecx, DATAORG
cdq
incedx
pusha

;; At this point, the compiler and its compiled programs diverge.
;; Although every compiled program includes all the code in this file
;; above this point, only the eleven bytes directly above are actually
;; used by both. This point is where the compiler begins storing the
;; generated code, so only the compiler sees the instructions below.
;; This routine first modifies ecx to contain TEXTORG, which is stored
;; on the stack, and then offsets it to point to filesize. edi is set
;; equal to codebuf, and then the compiler enters the main loop.

codebuf:
movch, (TEXTORG >> 8) & 0xFF
pushecx
movcl, filesize - $$
leaedi, [byte ecx + codebuf - filesize]
jmpshort relay


;; Here ends the file image.

compilersizeequ$ - $$



Категория: Общие Статьи | Добавил: aka_kludge (19.03.2008)
Просмотров: 4089 | Комментарии: 3 | Рейтинг: 5.0/2
Всего комментариев: 3

3 пишет:

(21.11.2008 13:08)

Название себя оправдывает, мозг рвет просто

0




2 пишет:

(20.07.2008 19:33)

прикоьный язычокк, нада будет поизучать )

0




1 пишет:

(20.07.2008 19:32)

wacko

0



Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]
    Главная      
...
На службе : дней

00:30
Обновить


Пользователи
aka_kludge
qwerty
LeadyTOR
aka_Atlantis
AdHErENt
mAss
Sissutr
hiss
DrBio
tHick

Поиск


Copyright tHR - TeAM 2024 г. admin: aka_kludge (ICQ:334449009) Moderator's: LeadyTOR, ... Яндекс.Метрика