Уверены, что отличите ассемблер от других языков?
Твой программист
Немногие смело признают, что могут ошибиться в идентификации ассемблера, ведь это по-своему особенный язык. Однако не спешите с выводами, а лучше пройдите небольшой тест, который не просто позволит взгялуть на него в ином свете, но и проверит вашу осведомленность в этой сфере.
Программирование на ассемблере сегодня в лучшем случае занимает нишевое положение и чаще воспринимается как неоправданно педантичное, требовательное и затратное даже для своей ниши.
Ассемблер непрост. Он недружелюбен. Программирование на этом языке происходит медленно и зачастую сопряжено с ошибками — таково общепринятое мнение.
К сожалению, в современной цифровой среде исходит это мнение от людей, которые, как правило, плохо представляют, как реально выглядят современные языки ассемблера. Этот стиль программирования не застрял в 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
Это ассемблер
Это что-то другое
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))
)
Это ассемблер
Это что-то другое
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
Это ассемблер
Это что-то другое
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
Это ассемблер
Это что-то другое
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
$)
Это ассемблер
Это что-то другое
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
Это ассемблер
Это что-то другое
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
!!
Это ассемблер
Это что-то другое
Заключение
Современное программирование на ассемблере не обязательно связано с инструкциями процессора и регистрами. Да, код всегда начинается с низов, но его можно оснастить функциями, классами и макросами, сделав до нужной степени высокоуровневым.
Программировать на этом языке не всегда трудно, и он не всегда оказывается чрезмерно педантичен. Просто каждому нужно подобрать подходящий для работы уровень.