Немногие смело признают, что могут ошибиться в идентификации ассемблера, ведь это по-своему особенный язык. Однако не спешите с выводами, а лучше пройдите небольшой тест, который не просто позволит взгялуть на него в ином свете, но и проверит вашу осведомленность в этой сфере.
Программирование на ассемблере сегодня в лучшем случае занимает нишевое положение и чаще воспринимается как неоправданно педантичное, требовательное и затратное даже для своей ниши.
Ассемблер непрост. Он недружелюбен. Программирование на этом языке происходит медленно и зачастую сопряжено с ошибками — таково общепринятое мнение.
К сожалению, в современной цифровой среде исходит это мнение от людей, которые, как правило, плохо представляют, как реально выглядят современные языки ассемблера. Этот стиль программирования не застрял в 50-х, он развивался вместе с высокоуровневыми языками, вбирая в себя структурные, функциональные и объектно-ориентированные элементы. Он отлично дружит с современными API и DOM. Конечно же, принципиально это низкоуровневый язык, но вы можете с тем же успехом создавать поверх него и высокоуровневые абстракции.
Честно говоря, я даже не уверен, что кто-нибудь сможет легко отличить код ассемблера от какого-нибудь высокоуровневого кода без помощи гугла. Вот вы сможете?
1. GUI
Ниже приведен фрагмент кода. Он создает окно с WinAPI и запускает для него цикл обработки сообщений.
Прошу вас, ознакомьтесь с ним и ответьте, написан ли он на одном из видов ассемблера или же на высокоуровневом языке?
nMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD LOCAL wc:WNDCLASSEX ; создает локальные переменные в стеке LOCAL msg:MSG LOCAL hwnd:HWND mov wc.cbSize,SIZEOF WNDCLASSEX ; заполняет значения в членах wc mov wc.style, CS_HREDRAW or CS_VREDRAW mov wc.lpfnWndProc, OFFSET WndProc mov wc.cbClsExtra,NULL mov wc.cbWndExtra,NULL push hInstance pop wc.hInstance mov wc.hbrBackground,COLOR_WINDOW+1 mov wc.lpszMenuName,NULL mov wc.lpszClassName,OFFSET ClassName invoke LoadIcon,NULL,IDI_APPLICATION mov wc.hIcon,eax mov wc.hIconSm,eax invoke LoadCursor,NULL,IDC_ARROW mov wc.hCursor,eax invoke RegisterClassEx, addr wc ; регистрирует класс window invoke CreateWindowEx,NULL, ADDR ClassName, ADDR AppName,\ WS_OVERLAPPEDWINDOW,\ CW_USEDEFAULT, CW_USEDEFAULT,\ CW_USEDEFAULT, CW_USEDEFAULT,\ NULL, NULL, hInst, NULL mov hwnd,eax invoke ShowWindow, hwnd,CmdShow ; отображает окно на рабочем столе invoke UpdateWindow, hwnd ; обновляет клиентскую область .WHILE TRUE ; вход в цикл сообщений invoke GetMessage, ADDR msg,NULL,0,0 .BREAK .IF (!eax) invoke TranslateMessage, ADDR msg invoke DispatchMessage, ADDR msg .ENDW mov eax,msg.wParam ; возврат кода выхода в eax ret WinMain endp
Источник: Iczelion’s Win32 Assembly Homepage, Tutorial 3: A Simple Window. win32assembly.programminghorizon.com/tut3.html
Источник: Iczelion’s Win32 Assembly Homepage, Tutorial 3: A Simple Window. win32assembly.programminghorizon.com/tut3.html
2. Библиотеки
Ниже дан пример функциональной библиотеки. Функция “add” просто складывает два целых числа и возвращает их сумму.
(module (func $add (param $lhs i32) (param $rhs i32) (result i32) get_local $lhs get_local $rhs i32.add) (export "add" (func $add)) )
Источник: примеры WebAssembly с официального сайта: developer.mozilla.org/en-US/docs/WebAssembly.
Источник: примеры WebAssembly с официального сайта: developer.mozilla.org/en-US/docs/WebAssembly.
3. Алгоритмы
Это реализация алгоритма TPK. Она содержит функцию, несколько циклов, массив и инструкцию вывода в консоль.
1 c@VA t@IC x@½C y@RC z@NC 2 INTEGERS +5 →c 3 →t 4 +t TESTA Z 5 -t 6 ENTRY Z 7 SUBROUTINE 6→z 8 +tt→y→z 9 +tx→y→x 10 +z+cx CLOSE WRITE 1 11 a@/½ b@MA c@GA d@OA e@PA f#HA i@VE x@ME 12 INTEGERS +20 →b +10 →c +400 →d +999 →e +1 →f 13 LOOP 10n 14 n→x 15 +b-x→x 16 x→q 17 SUBROUTINE 5 →aq 18 REPEAT n 16 +c →i 20 LOOP 10n 21 +an SUBROUTINE 1 →y 22 +d-y TESTA Z 23 +i SUBROUTINE 3 24 +e SUBROUTINE 4 25 CONTROL X 26 ENTRY Z 27 +i SUBROUTINE 3 28 +y SUBROUTINE 4 29 ENTRY X 30 +i→f→i 31 REPEAT n 32 ENTRY A CONTROL A WRITE 2 START 2
источник: The Early Development Of Programming Languages by Donald E. Knuth, Luis Trabb Pardo, 1976.
Кстати, TPK означает «Typical Pardo Knuth» (типичный Пардо Кнут, от имени его создателя) Это не настоящий алгоритм, и создавался он для демонстрации нескольких языков в одном примере.
источник: The Early Development Of Programming Languages by Donald E. Knuth, Luis Trabb Pardo, 1976.
Кстати, TPK означает «Typical Pardo Knuth» (типичный Пардо Кнут, от имени его создателя) Это не настоящий алгоритм, и создавался он для демонстрации нескольких языков в одном примере.
4. Структурное программирование
Вот пример вычисления суперскалярной суммы.
v0 = my_vector // нам нужна горизонтальная сумма следующего int64 r0 = get_len ( v0 ) int64 r0 = round_u2 ( r0 ) float v0 = set_len ( r0 , v0 ) while ( uint64 r0 > 4) { uint64 r0 > >= 1 float v1 = shift_reduce ( r0 , v0 ) float v0 = v1 + v0 } // Теперь сумма представлена скаляром в v0
Источник: примеры кода из ForwardCom: An open-standard instruction set for high-performance microprocessors by Agner Fog.
Источник: примеры кода из ForwardCom: An open-standard instruction set for high-performance microprocessors by Agner Fog.
5. Еще структурное программирование
Это решение задачи о восьми ферзях с выводом в консоль. Его платформенная зависимость минимальна, но при этом оно не обогащено высокоуровневыми возможностями вроде классов, шаблонов или встроенных контейнеров.
GET "LIBHDR" GLOBAL $( COUNT: 200 ALL: 201 $) LET TRY(LD, ROW, RD) BE TEST ROW = ALL THEN COUNT := COUNT + 1 ELSE $( LET POSS = ALL & ~(LD | ROW | RD) UNTIL POSS = 0 DO $( LET P = POSS & -POSS POSS := POSS - P TRY(LD + P << 1, ROW + P, RD + P >> 1) $) $) LET START() = VALOF $( ALL := 1 FOR I = 1 TO 12 DO $( COUNT := 0 TRY(0, 0, 0) WRITEF("%I2-QUEENS PROBLEM HAS %I5 SOLUTIONS*N", I, COUNT) ALL := 2 * ALL + 1 $) RESULTIS 0 $)
Источник: BCPL From Wikipedia, the free encyclopedia.
Источник: BCPL From Wikipedia, the free encyclopedia.
6. ООП (с классами и методами)
Вот ассемблер .NET (не путать с ассемблером в «языке ассемблера»). Он состоит из одного модуля с одним классом, имеющим один метод, который выводит в консоль “Hello World”.
// Metadata version: v2.0.50215 .assembly extern mscorlib { .publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) .ver 2:0:0:0 } .assembly sample { .custom instance void [mscorlib]System.Runtime.CompilerServices .CompilationRelaxationsAttribute::.ctor(int32) = ( 01 00 08 00 00 00 00 00 ) .hash algorithm 0x00008004 .ver 0:0:0:0 } .module sample.exe // MVID: {A224F460-A049-4A03-9E71-80A36DBBBCD3} .imagebase 0x00400000 .file alignment 0x00000200 .stackreserve 0x00100000 .subsystem 0x0003 // WINDOWS_CUI .corflags 0x00000001 // ILONLY // Image base: 0x02F20000 // =============== CLASS MEMBERS DECLARATION =================== .class public auto ansi beforefieldinit Hello extends [mscorlib]System.Object { .method public hidebysig static void Main(string[] args) cil managed { .entrypoint // Размер кода 13 (0xd) .maxstack 8 IL_0000: nop IL_0001: ldstr "Hello World!" IL_0006: call void [mscorlib]System.Console::WriteLine(string) IL_000b: nop IL_000c: ret } // конец метода Hello::Main .method public hidebysig specialname rtspecialname instance void .ctor() cil managed { // Размер кода 7 (0x7) .maxstack 8 IL_0000: ldarg.0 IL_0001: call instance void [mscorlib]System.Object::.ctor() IL_0006: ret } // конец метода Hello::.ctor } // конец класса Hello
Вы вольны использовать все возможности .NET: GUI, обращение к базе данных, сетевые функции – все это при одновременном наличии низкоуровневого контроля деталей. Да, такой вариант может показаться чересчур многословным и неоправданно подробным, но все равно он представляет весьма мощный вариант ассемблера. Помимо классов и методов в качестве встроенных типов он предлагает исключения и строки.
Источник: docs.microsoft.com/en-us/dotnet/framework/tools/ilasm-exe-il-assembler.
Бессовестная реклама: пару лет назад я начал вводить в ILAsm макросы, создавая MILasm. Это вполне рабочее доказательство концепции. С ним интересно играться, хотя для продакшена он не совсем готов ввиду наследственных проблем с производительностью.
Вы вольны использовать все возможности .NET: GUI, обращение к базе данных, сетевые функции – все это при одновременном наличии низкоуровневого контроля деталей. Да, такой вариант может показаться чересчур многословным и неоправданно подробным, но все равно он представляет весьма мощный вариант ассемблера. Помимо классов и методов в качестве встроенных типов он предлагает исключения и строки.
Источник: docs.microsoft.com/en-us/dotnet/framework/tools/ilasm-exe-il-assembler.
Бессовестная реклама: пару лет назад я начал вводить в ILAsm макросы, создавая MILasm. Это вполне рабочее доказательство концепции. С ним интересно играться, хотя для продакшена он не совсем готов ввиду наследственных проблем с производительностью.
7. ООП (с объектами и сообщениями)
Это пример TCP-сервера. В нем есть объекты и методы, а работает он в собственной среде.
Namespace current addSubspace: #SimpleTCP! Namespace current: SimpleTCP! "A simple TCP server" Object subclass: #Server instanceVariableNames: 'serverSocket socketHandler' classVariableNames: '' poolDictionaries: '' category: ''! !Server class methodsFor: 'instance creation'! new: aServerSocket handler: aHandler | simpleServer | simpleServer := super new. simpleServer socket: aServerSocket. simpleServer handler: aHandler. simpleServer init. ^simpleServer !! !Server methodsFor: 'initialization'! init ^self !! !Server methodsFor: 'accessing'! socket ^serverSocket ! socket: aServerSocket serverSocket := aServerSocket. ^self ! handler ^socketHandler ! handler: aHandler socketHandler := aHandler. ^self !! !Server methodsFor: 'running'! run | s | [ serverSocket waitForConnection. s := (serverSocket accept). self handle: s ] repeat ! !Server methodsFor: 'handling'! handle: aSocket socketHandler handle: aSocket !!
Источник: Building a simple chat server with GNU Smalltalk using class inheritance из smalltalk.gnu.org/wiki/examples\
Источник: Building a simple chat server with GNU Smalltalk using class inheritance из smalltalk.gnu.org/wiki/examples\
Заключение
Современное программирование на ассемблере не обязательно связано с инструкциями процессора и регистрами. Да, код всегда начинается с низов, но его можно оснастить функциями, классами и макросами, сделав до нужной степени высокоуровневым.
Программировать на этом языке не всегда трудно, и он не всегда оказывается чрезмерно педантичен. Просто каждому нужно подобрать подходящий для работы уровень.
ссылка на оригинал статьи https://habr.com/ru/company/ruvds/blog/554910/
Добавить комментарий