Uploaded avatar of iHiD

Це Листопад ніблів

@iHiD
Майже 3 роки тому
Відео

Вступ

Привіт усім. Вітаю в листопаді. Сподіваюся, у всіх усе добре.

Жовтень у нас був надзвичайно насиченим. Ми щойно випустили велике покращення для рішень спільноти. Тепер ми прибираємо дублікати, тож схожі рішення показуються лише раз, ми додали нові варіанти впорядкування, можливість пошуку за кодом, а якщо зазирнути до C#, побачимо, що ми також додали фільтрування за різними концепціями програмування. Тож можна шукати рішення, які використовують побітовий зсув, рекурсію чи будь-що інше на власний смак. Ми поширимо це на інші треки протягом тижня спільноти.

Але поки що зосередьмося на #12in23. Жовтень був цікавим місяцем дослідження обʼєктно-орієнтованих мов, але цього місяця буде справжній хардкор. Ми зосереджуємося на мовах асемблера, а саме на асемблері MIPS, асемблері x86-64 та WebAssembly. Як завжди, Ерік розповість нам, що робить ці мови цікавими та унікальними.

Бейджі

Як завжди, бейдж Nibbly November можна отримати, виконавши будь-які 5 вправ цими мовами. Також є бейдж за весь рік, до якого, знаю, багато хто прямує. Для нього ми підготували 5 вибраних вправ, які потрібно виконати. Ось вони:

  • Підрахунок одиниць: порахувати одиничні біти в числі
  • Зерна: обчислити кількість зерен на шахівниці, де кількість на кожній наступній клітинці подвоюється
  • Колір резистора: перетворити колір смужки резистора на його числове подання
  • Ротаційний шифр: реалізувати ротаційний шифр (він же шифр Цезаря)
  • Підрахунок нуклеотидів: обчислити, скільки разів кожен нуклеотид трапляється в рядку тексту (англ. string) ДНК

Загальні відомості

Чому цей місяць зветься Nibble November?

Що ж, мабуть, усім відомо: байт - це 8 бітів. А нібл - це 4 біти. Назва починає набувати сенсу, якщо замінити y у слові byte на i, і вийде bite. Тоді нібл - це маленький укус.

Що таке мова асемблера?

Що ж, почнімо з основ. Процесор виконує інструкції, як-от «додати два числа» або «зсунути біти ліворуч», тощо. Ці інструкції називаються інструкціями машинного коду, і вони є не чим іншим, як конкретними послідовностями бітів. Виконати програму - це, «просто» (у лапках), опрацювати й виконати процесором ці послідовності бітів.

Оскільки записувати інструкції безпосередньо як послідовності бітів громіздко й схильно до помилок, Кетлін і Ендрю Дональд Бут ще 1947 року придумали зручнішу для людини мову для представлення інструкцій машинного коду. Таку мову, що представляє інструкції машинного коду, називають мовою асемблера. Цю мову асемблера потім перетворюють на інструкції машинного коду за допомогою «асемблера».

Цікавий аспект мов асемблера в тому, що вони безпосередньо привʼязані до архітектури процесора, хоча зазвичай не залежать від операційної системи.

До речі, якщо хтось памʼятає перфокарти, ті великі картки, які використовували в найперших компʼютерах, щоб ті виконували програми, то вони теж були мовою асемблера!

Чим мова асемблера відрізняється від мов, якими ми програмуємо тепер?

Ключова відмінність у тому, що мови асемблера дуже низькорівневі. Багато абстракцій, до яких ми звикли, тут бракуватиме. Класів чи обʼєктів тут годі й шукати. Цикли? Їх доведеться писати вручну за допомогою переходів. Функції? Аніяк! Мені було дуже тверезо писати код на асемблері, бо тоді усвідомлюєш, наскільки сучасні мови полегшують нам життя. Але писати код на асемблері також неймовірно корисно, бо починаєш значно краще розуміти, як усе насправді працює.

Цікавий факт: 99% вихідного коду RollerCoaster Tycoon було написано вручну на асемблері! Це вражаюче досягнення, яке ми оцінимо ще більше, коли самі трохи попрацюємо з асемблером.

Чи пишуть люди досі мовою асемблера?

Що ж, рідше, ніж раніше. Колись написаний вручну асемблер часто перевершував згенерований компілятором машинний код (це одна з причин, чому C++ дозволяє вбудовувати код на асемблері безпосередньо), але компілятори навчилися так добре генерувати машинний код, що тепер це рідко буває правдою. І все ж мову асемблера досі можна зустріти в середовищах, критичних до швидкодії або обмежених у ресурсах.

Огляди

MIPS

  • MIPS (Microprocessor without Interlocked Pipelined Stages) - це сімейство архітектур наборів інструкцій для компʼютерів зі скороченим набором інструкцій (RISC)
  • Розроблено MIPS Computer Systems, уперше випущено 1985 року
  • Кілька версій: MIPS I, II, III, IV, V та MIPS32/64. Перші дві версії були лише 32-бітними, але MIPS III додала підтримку 64 бітів.
  • Кілька необовʼязкових розширень, як-от інструкції SIMD і стиснення
  • Дуже вплинула на пізніші RISC-архітектури
  • 2021 року MIPS оголосила, що архітектуру MIPS більше не розробляють, і перейшла на RISC-V (архітектуру з відкритим кодом без ліцензійних відрахувань)
  • Здебільшого використовується у вбудованих системах (наприклад, у маршрутизаторах) і серверах (її застосовували компʼютери Silicon Graphics, відомі своїм використанням для спецефектів у кіно), у суперкомпʼютері NEC Cenju-4, в автомобілі Tesla Model S, у зонді NASA New Horizons, а також для викладання асемблера в університетах і в кількох ігрових консолях (наприклад, оригінальна PlayStation, PlayStation Portable та Nintendo 64)

Асемблер x86-64

  • Розроблено AMD і випущено 1999 року як архітектуру AMD64
  • Це 64-бітна версія набору інструкцій x86, який сягає 1978 року, коли Intel випустила свій мікропроцесор 8086. То був 16-бітний процесор, але згодом 80386 додав 32-бітні інструкції, і цей набір інструкцій став синонімом x86.
  • Головне, що уможливив 64-бітний режим, - це адресація більшого обсягу памʼяті (32-бітна адресація обмежена 4 ГБ), що вже стало вузьким місцем. 64 біти теоретично можуть адресувати 16 ексабайтів, але наразі використовується лише 48 бітів, що дозволяє адресувати 256 ТБ (можна розширити пізніше, коли потрібно)
  • AMD64 розширює набір інструкцій x86 і був розроблений як повністю сумісний із наявними 16- та 32-бітними застосунками через режим сумісності
    • Intel розробила IA-64 без участі AMD. Це був новий, дуже відмінний і зворотно несумісний 64-бітний набір інструкцій. Зрештою переміг AMD64, і Intel реалізувала його власну версію (лише з незначними семантичними відмінностями)
  • Використовується всюди. Від робочих станцій до серверів (зокрема суперкомпʼютерів), від вбудованих систем до ігрових консолей (наприклад, PS5 та Xbox Series X).

WebAssembly

  • Розроблено W3C, організацією зі стандартизації вебтехнологій
  • Цілі проєктування:
    • Швидкість, безпека та переносність
    • Ефективне та переносне представлення
  • Колись швидке виконання в браузері зазвичай забезпечували спеціалізовані плагіни, як-от Flash і Silverlight, бо сам JavaScript погано підходить для високопродуктивних обчислень. Головні недоліки цих плагінів полягали в тому, що вони зазвичай мали багато проблем із безпекою і не були стандартизовані.
    • Mozilla розробила asm.js, підмножину JavaScript, покликану дозволити виконувати код у браузері з чудовими показниками швидкодії, чого досягали завдяки узгодженості типів (жодної динамічної зміни типів) і відсутності збирання сміття. Мови могли компілюватися в asm.js і все одно працювати в браузері з хорошою швидкодією. Але це все ще був JS, тож можливості були обмежені. Звідси й пропозиція нової мови: WASM.
  • Мова, схожа на асемблер тим, що надає набір інструкцій для виконання. Важливо, що вона не привʼязана до конкретного процесора, тож не залежить від платформи й потребує реалізації для кожної платформи (віртуальної машини). Це означає, що WebAssembly насправді є байт-кодом, а не машинним кодом
  • Статично типізована (критична відмінність від JS)
  • Зазвичай використовує попередню (AOT) або динамічну (JIT) компіляцію (але може й інтерпретуватися)
  • Відкритий стандарт, що визначає дві речі:
    • Бінарний формат
    • Текстовий формат (який компілюється в бінарний)
  • Реалізації в усіх основних браузерах
  • Використовується на багатьох вебсторінках, які потребують високої швидкодії, як-от Google Earth, Figma, Unity та Autocad. Також набирає популярності на серверній стороні, наприклад, для запуску мікросервісів, роботи на SaaS-платформах (наприклад, CloudFlare workers) чи в Docker

А з погляду програмування, чим вони різняться?

MIPS

  • Використовує архітектуру «завантаження-збереження» (вона ж регістр-регістр), де інструкції або звертаються до памʼяті, або виконують арифметику, але працюють виключно з даними в регістрах

Асемблер x86-64

  • Використовує архітектуру регістр-памʼять, яка дозволяє виконувати операції з памʼяттю (або з памʼяті), а також із регістрами

WebAssembly

  • Використовує стекову модель програмування (без регістрів) з можливістю читати дані з памʼяті та записувати в неї

Що робить ці мови чудовими?

MIPS

  • Компактність. Увесь набір інструкцій MIPS уміщається на одній сторінці
  • Усталені угоди про виклики допомагають зрозуміти, як користуватися наявними регістрами, наприклад, які застосовувати для передавання аргументів, а які для повернення результатів.
  • Стабільність. Останню версію випущено 2014 року
  • Широко задокументована, особливо в академічній літературі
  • Безліч застосувань у реальному світі. Мільярди пристроїв

Асемблер x86-64

  • Хоча це розширення x64, було додано багато нових можливостей, зокрема:
    • підтримка 64-бітних цілих чисел
    • додаткові регістри
    • інструкції SSE (векторні інструкції)
    • відносний доступ до даних (ефективніший під час використання спільних бібліотек)
    • Біт заборони виконання (засіб безпеки, що заважає виконанню коду в певних сторінках памʼяті)
  • Звичність. Оскільки він розширює набір інструкцій x86, його буде відносно легко опанувати тим, хто вже знайомий із набором інструкцій x86 Ґрунтовна й детальна документація
  • Стабільність. Хоча нові версії додаються регулярно, ядро залишається надзвичайно стабільним і зворотно сумісним

WebAssembly

  • Стекова віртуальна машина WebAssembly лаконічна й проста порівняно з мовами асемблера фізичних процесорів (зокрема RISC). Це робить її відносно легкою ціллю для компіляції.
  • Текстовий формат WebAssembly використовує S-вирази як «синтаксичний цукор», щоб досягти звичного імперативного стилю, який потім перетворюється на стековий код. Форму із S-виразами називають «цукрованою формою», і вона «розцукровується» в іншу форму, еквівалентну тому, що міститься в бінарному файлі. S-вирази будуть знайомі всім, хто колись працював із LISP
  • Тісна взаємодія з JavaScript. Просто передавати дані з JavaScript і назад. Важливе застереження: WASM (поки що) не дозволяє взаємодіяти з DOM
  • Постійно вдосконалюється. Поліпшуються не лише віртуальні машини WASM, а й сам стандарт активно розвивається. Безліч нових можливостей проєктується й розробляється: інструкції, повʼязані з SIMD, збирання сміття, потоки, оптимізації хвостових викликів тощо
  • Безпека. Код перевіряється й виконується в пісочниці, що забезпечує вищий рівень статичної перевірки порівняно з JavaScript чи рідними мовами асемблера. Семантика чітко визначена, тож її легко перевіряти й аналізувати

Найпримітніші особливості

MIPS

  • Ефективність. Процесори MIPS дуже ефективні, що робить їх чудовими для вбудованих систем.
  • Швидкодія. Висока швидкодія, тому MIPS і використовували в суперкомпʼютерах
  • Легко вивчати. Мало інструкцій, і кожна робить лише одну просту річ, тож опанувати її легко. Чудово для навчання.

Асемблер x86-64

  • Потужність. x86-64 удосконалювали десятиліттями, і він має безліч інструкцій, що допомагають зі швидкодією. Приклад цього - SIMD (Single Instruction, Multiple Data), тобто інструкції, які, власне, дозволяють одній інструкції виконуватися паралельно над кількома елементами даних.
  • Повсюдність. Пристрої з x86-64 скрізь. Його реалізують процесори Intel і AMD. Довгий час він був фактичним стандартом
  • Регулярні оновлення. Наприклад, нові векторні інструкції: SSE3-5, AVX, AVX-512 тощо

WebAssembly

  • Ефективність. Бінарний формат компактний, і його можна декодувати, перевірити та скомпілювати за один швидкий прохід. Він також потоковий, що дозволяє розпочати декодування, перевірку й компіляцію якомога раніше, ще до отримання всіх даних. І його можна розпаралелювати. Це робить його ідеальним для високопродуктивних вебзастосунків.
  • Чудова ціль компіляції. Дозволяє коду багатьма мовами працювати в браузері. Більшість провідних мов підтримують компіляцію у бінарні файли WebAssembly, тож код може працювати в браузері без потреби писати JavaScript. Деякі мови компілюють у WebAssembly не код, а середовище виконання, яке потім виконує незмінений байт-код.
  • Легко розгортати й запускати. Потрібна лише віртуальна машина, здатна інтерпретувати байт-код, а вона є в усіх основних браузерах.
  • Не привʼязана до вебу, але може працювати й на серверній стороні. WebAssembly System Interface (WASI) - це інтерфейс (ABI та API), розроблений як переносний на будь-яку платформу. Він схожий на POSIX (стандартні інтерфейси для систем Unix) і надає, зокрема, засоби введення-виведення. Безпека - ключова частина його проєкту, що включає пісочницю й орієнтацію на можливості (потрібно явно просити дозвіл на доступ до файлів чи сокетів). WASI також має потенціал полегшити взаємодію між мовами. Соломон Гайкс, співзасновник Docker, писав 2019 року: «Якби WASM+WASI існували 2008 року, нам не потрібно було б створювати Docker»

Що обрати

  • Тим, хто ніколи не працював із мовою асемблера, WebAssembly, мабуть, найпростіша для старту. Втім, якщо мета - вивчити мову асемблера, що компілюється в машинний код, варто спробувати асемблер MIPS
  • Якщо робоча машина - x86-64 (а це дуже ймовірно), варто спробувати асемблер x86-64
  • Тим, хто знайомий із LISP, сподобається, що WebAssembly використовує S-вирази
  • Для роботи з вебзастосунками WebAssembly - найлогічніший вибір
  • Якщо важлива швидкодія, x86-64 і MIPS - чудові варіанти. А якщо важлива швидкодія у вебі, варто спробувати WebAssembly
Translation missing: uk.number.nth.ordinalized Nov 2023 · Виявилося корисним?