LINUX.ORG.RU

X11-приложение на чистом ассемблере под Linux

 , ,


2

5

Наконец закончил перевод очень крутой и интересной статьи, где описывается работа с Х-сервером на чистом ассемблере.

Как сама статья так и перевод - большие и сложные, знаний на такое у меня уже нехватает. Если есть желающие помочь с вычиткой и поиском ошибок - велкам!

На скриншоте обычная Ubuntu и Xfce, самое главное - ч0рное окошко по центру, это и есть та самая тестовая программа из статьи, написанная на чистом ассемблере и вызывающая Х-сервер через unix-сокет.

>>> Просмотр (1366x768, 988 Kb)

★★★

Проверено: hobbit ()
Последнее исправление: hobbit (всего исправлений: 1)
Ответ на: комментарий от gns

Они LynxOS и BlackCat Linux пилили одно время

Так BlackCat тоже они получается делали? Вроде же в Донецке разработчики сидели?

alex0x08 ★★★
() автор топика
Ответ на: комментарий от PPP328

То есть глаза меня не подвели. Тогда смысла в таком коде ровно 0.

Я могу поинтересоваться - что именно Вы бы написали по-другому? Просто интересно ;) Ни в коей мере не пытаюсь умалить усилия автора, и уж тем более переводчика в лице ТС - такие статьи очень полезны, с одной стороны демонстрируют «как реально устроен мир», с другой - там имеются конкретные примеры с конкретным «выхлопом» с которыми можно играться. В оригинале кстати, есть пара глючков (перевод не читал - сорьки, мне оригинал переваривать гораздо проще), довольно неприятных. Мне интересно - кто-нибудь помимо меня их видит? :)

bugfixer ★★★★★
()
Ответ на: комментарий от alex0x08

Смотря когда. Может потом в Донецк передали разработку. Я там работал очень недолго, то-ли в 2004м, то-ли в пятом...

gns ★★★★★
()
Ответ на: комментарий от bugfixer

В оригинале кстати, есть пара глючков (перевод не читал - сорьки, мне оригинал переваривать гораздо проще), довольно неприятных

Сложно сказать что считать оригиналом, поскольку статью несколько раз переделывали, в моем переводе есть вставки от читателей.

Глючки там есть, но сделаны специально для иллюстрации процесса: есть undefined behavior , есть падение в segfault ради демонстрации обработки выхода, есть запуск без показа окна - опять же для демонстрации логики Dispose.

Т.е что-то еще есть?

alex0x08 ★★★
() автор топика
Ответ на: комментарий от Herabora

Спасибо, мы лучше соседнюю ветку с редхатом и ИксПердами сотрем :)

gns ★★★★★
()
Ответ на: комментарий от bugfixer

Ааа так вот оно что ) Вот зачем @PPP328 про константы писал ) Я кстати еще был удивлен что код успешного ответа от Х-сервера это 1 а не обычное 0.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от bugfixer

что именно Вы бы написали по-другому?

Это бездарный мусор, который наглядно демонстрирует, зачем нужен компилятор.

mov rdx, 0 ; Automatic protocol.

xor rdx, rdx — рекомендованный Intel и AMD способ занулить регистр. Это называется zero idiom, оно занимает меньше места, чем mov rdx, 0 и распознаётся на уровне декодирования инструкций.

cmp rax, 0

test rax, rax занимает меньше места и выставляет те же флаги.

cld ; Move forward
mov ecx, 19 ; Length is 19 with the null terminator.
rep movsb ; Copy.

Это гораздо медленнее, чем тупо скопировать через mov 8+8+2+1 байт.

lea rsi, [rsp]

mov rsi, rsp

imul rax, 8 ; sizeof(format) == 8

В этом контексте (флаги не проверяются) эквивалентно shl rax, 3 либо (в синтаксисе AT&T, не силён в интеловском) leaq (,8,%rax), %rax.

  mov BYTE [rsp + 3*4 + 0], 'f'
  mov BYTE [rsp + 3*4 + 1], 'i'
  mov BYTE [rsp + 3*4 + 2], 'x'
  mov BYTE [rsp + 3*4 + 3], 'e'
  mov BYTE [rsp + 3*4 + 4], 'd'

Зачем, если можно через два mov это сделать?

  ; Compute padding and packet u32 count with division and modulo 4.
  mov eax, edx ; Put dividend in eax.
  mov ecx, 4 ; Put divisor in ecx.
  cdq ; Sign extend.
  idiv ecx ; Compute eax / ecx, and put the remainder (i.e. modulo) in edx.
  ; LLVM optimizer magic: `(4-x)%4 == -x & 3`, for some reason.
  neg edx
  and edx, 3 
  mov r9d, edx ; Store padding in r9.

Особая одарённость, сложно это даже как-то прокомментировать.

  cld ; Move forward
  mov ecx, r8d ; String length.
  rep movsb ; Copy.

Это очень неоптимально, см. как реализован memcpy в glibc.

  ; Read the server response: read(2).
  ; Use the stack for the read buffer.
  ; The X11 server first replies with 8 bytes. Once these are read, it replies with a much bigger message.
  mov rax, SYSCALL_READ
  mov rdi, rdi
  lea rsi, [rsp]
  mov rdx, 8
  syscall

  cmp rax, 8 ; Check that the server replied with 8 bytes.
  jnz die
  ; Read the rest of the server response: read(2).
  ; Use the stack for the read buffer.
  mov rax, SYSCALL_READ
  mov rdi, rdi
  lea rsi, [rsp]
  mov rdx, 1<<15
  syscall
  
  cmp rax, 0 ; Check that the server replied with something.
  jle die

SOCK_STREAM так не работает.

Note: There is an optimization method that uses rbp as a standard register (with a C compiler, that’s the flag -fomit-frame-pointer), which means we lose the information about the call stack. My advice is: never do this, it is no worth it.

-fomit-frame-pointer это умолчание на x86-64.

cudeta
()
Последнее исправление: cudeta (всего исправлений: 1)
Ответ на: комментарий от cudeta

Спасибо за столь крутой разбор ) Я точно не владею ассемблером настолько чтобы представлять какая инструкция быстрее )

Нет желания спомпоновать все эти правки в отдельную оптимизированную версию? Врядли получится явно увидеть разницу глазами на современном железе, но все же, для общего развития у аудитории?

alex0x08 ★★★
() автор топика
Ответ на: комментарий от cudeta

-fomit-frame-pointer это умолчание на x86-64.

Это умолчание много где, начиная с определённых -OX.

bugfixer ★★★★★
()
Ответ на: комментарий от cudeta

Это бездарный мусор

Я же не просто так спросил :)

bugfixer ★★★★★
()
Ответ на: комментарий от cudeta

Это бездарный мусор, который наглядно демонстрирует, зачем нужен компилятор.

То как я это вижу - Ваши претензии сводятся к двум:

  • неоптимальности связанные с bit tricks (const load vs self-xor’ing etc).
  • неоптимальности связанные с неиспользованием loop-unrolling.

И то и другое можно списать на наглядность демонстрации.

Что мне реально трудно объяснить это

mov cx, WORD [rsp + 16] ; Vendor length (v).
movzx rcx, cx

Есть мысли зачем так сделали? Или я чего-то совсем не понимаю?

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

зачем так сделали?

По крайней мере видна идея: берём из памяти слово в cx, расширяем нулем до rcx (не спрашивайте зачем, в процитированной фрагменте этого нет).

Встречный вопрос: вместо этого кода ожидалось куда более очевидное что?

bormant ★★★★★
()
Ответ на: комментарий от gns

Да я понимаю, насчёт переносимости-то. Тем более асм под *никсы пока для меня не существует.

sparkie ★★★★★
()
Ответ на: комментарий от bugfixer

Я выше написал как минимум то, что сразу в глаза бросилось. Вообще на асме с иксами надо работать не вот так, а создав кучу STRUC, чтобы в каждую функцию передавалось именно то, что объявлено в спеках.

PPP328 ★★★★★
()
Ответ на: комментарий от bugfixer

неоптимальности связанные с bit tricks (const load vs self-xor’ing etc).

В случае с imul vs shl ещё можно сказать, что это bit trick.

Но в остальных случаях это просто объективно лучшие способы сделать те вещи, которые он делает. Почему лучшие, я объяснил.

Вот это нельзя списать на «наглядность демонстрации»:

  ; Compute padding and packet u32 count with division and modulo 4.
  mov eax, edx ; Put dividend in eax.
  mov ecx, 4 ; Put divisor in ecx.
  cdq ; Sign extend.
  idiv ecx ; Compute eax / ecx, and put the remainder (i.e. modulo) in edx.
  ; LLVM optimizer magic: `(4-x)%4 == -x & 3`, for some reason.
  neg edx
  and edx, 3 
  mov r9d, edx ; Store padding in r9.

Ну хорошо, допустим, он не понимает, что X % 4 == X & 3. Поэтому считает остаток от деления на 4 с помощью деления (это медленее в 46—161 раз, в зависимости от железа).

Но почему знаковое деление (idiv, а не div) и cdq? В этом нет никакого смысла.

Самое смешное, что после этого он говорит, что «LLVM мне сказал, что (4-x)%4 == -x & 3», и поэтому делает

  neg edx
  and edx, 3 
Но весь этот код эквивалентен этим двум операциям.

cudeta
()
Последнее исправление: cudeta (всего исправлений: 1)

Я конечно всё понимаю, красивая надпись «Hello, world!» на фоне оригинального окна ярко чёрного цвета. Есть, что показать в галерее.

@hobbit, @alex0x08, Почему бы это обсуждение не сохранить в разделе «Статьи?» Тем более обсуждение уже давно перешло в «вот как это надо писать на ассемблере.»

VIT
()
Ответ на: комментарий от VIT

Не думал что будет такой интерес, все же это не Rust под NixOS с Waylandом. Могу перенести, но ввиду особенностей движка для статей - картинок не будет.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Мне кажется картинки тут вообще не нужны, а вот обсуждение быстро исчезнет в потоке новых творений арчеводов и убунтят.

VIT
()
Ответ на: комментарий от Extraterrestrial

ты же квай гон джинн, используй силу для определения тян

А потом можешь рассказывать что пацан был зачат медихлорианами)

pihter ★★★★★
()

Очень круто! Но высокий порог вхождения и длительность разработки отталкивают энтузиастов. (((

nuxster ★★★
()
Ответ на: комментарий от arax

Так если сравнивать

mov cx, WORD [rsp + 16] ; Vendor length (v).
movzx rcx, cx
и
movzx rcx, WORD [rsp + 16] ; Vendor length (v).
то не велика и разница.

Думал правда что-то существенное, а так... Ну да, неоптимально — движений больше, результат тот же.
Зачем? Ну такой вот автор асмописатель.

bormant ★★★★★
()
Ответ на: комментарий от bormant

то не велика и разница.

А ты как хотел, что бы из двух строчек оно в ноль превратилось? :D
Просто видя двухстрочный вариант, закрадываются сомнения, что тут есть какое-то колдунство, про это изначальный вопрос от bugfixer скорее всего и был.

PS

Скорее всего это было использовано для демонстрации вот этого утверждения из статьи:

ecx is the 32 bit form of the register rcx, meaning we only set here the lower 32 bits of the 64 bit register. This handy table lists all of the forms for all of the registers. But be cautious of the pitfall case of only setting a value in part of a register, and then using the whole register later. The rest of the bits that have not been set will contain some past value, which is hard to troubleshoot. The solution is to use movzx to zero extend, meaning setting the rest of the bits to 0. A good way to visualize this is to use info registers within gdb, and that will display for each register the value for each of its forms, e.g. for rcx, it will display the value for rcx, ecx, cx, ch, cl.

arax ★★
()
Последнее исправление: arax (всего исправлений: 4)
Ответ на: комментарий от arax

для визуализации вот этого утверждения

cx - 16-разрядный, так что не совсем этого ;)

bormant ★★★★★
()
Ответ на: комментарий от arax

But be cautious of the pitfall case of only setting a value in part of a register, and then using the whole register later.

И «partial register stall». Я даже не знаю что в этом контексте хуже.

bugfixer ★★★★★
()
Ответ на: комментарий от cumvillain

А зачем тогда вообще писать на ассемблере, если можно написать на Си

memcpy(dst, "fixed", 5);

и компилятор развернёт в два mov'а?

cudeta
()
Ответ на: комментарий от cudeta

Или не развернёт. Или не в два. Или не только mov’a.

VIT
()
Ответ на: комментарий от cudeta

А зачем тогда вообще писать на ассемблере

Потому что автор показал технодемку, а ты начал её разбирать как будто он предлагает новый оптимизированный SHA2 для x86 и говорит что он на 100500 процентов быстрее существующего.

cumvillain
()
Ответ на: комментарий от cumvillain

Представь, что некий «математик» опубликовал какую-то статью, ценность которой якобы заключается в том, что он доказал какое-то уже доказанное утверждение, но с нуля, из аксиом.

И вот часть этой статьи заключается в том, что он 50 страниц доказывал некое утверждение. Ему сказали, что оно доказывается в одну строчку следующим образом: «…», а если он написал эту портянку, то он, судя по всему, не разбирается в предмете и никогда не решал не то что реальных задач, а задач из учебника.

На что поступает ответ, что, мол, «это демка». Демка или нет, она демонстрирует то, что автор не разбирается в этой области, ну то есть простейших вещей из учебника не знает.

А ценность такой статьи очень сомнительна. Ну вывел из аксиом, и что? То, что это можно вывести из аксиом, все и так знали. Кому и что она должна продемонстрировать? Зачем?

cudeta
()
Ответ на: комментарий от cudeta

Зачем?

Ради фана. Тебя уязвляет факт написания статьи из разряда «я взял буханку хлеба, клей с палками и сделал троллейбус». Тут вопрос «почему?» и он скорее к тебе, чем к автору статьи.

cumvillain
()

Вот всегда так: один напишет интересную статью, а потом более умные тыкают на допущенные им ошибки, однако от этих более умных статей не дождешься (хотя возможно это следствие большего ума).

Virtuos86 ★★★★★
()
Ответ на: комментарий от Virtuos86

Они не более умные а более трусливые - боятся что их код точно также будут разбирать. Вообще тред показателен, в который раз иллюстрирует простую мысль что докопаться можно хоть до столба.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Они не более умные а более трусливые

Теперь пинать будут тебя, потому что я ничего подобного благоразумно не озвучил 😊.

Virtuos86 ★★★★★
()

Тема прикольная и познавательная для «младших мнс»

так же прикольно quine на (f|n|m)asm'ах

ещё более прикольные трюки с определением на чём едем путём пробинга переписывания для обнаружения насколько длинен кэш предчтения

ну али классический:

mov cs,ax

который почти всегда аппаратное прерывание

во времена оные теперь уже «будущее в прошедшем»

была «идея» расширения опкодов вешая свой обработчик того прерывание которое аппаратно дёргается когда проц не может распарсить опсод очередной команды

очень просто(скорее кратко) прикручиваеся типофорт -на уровень свободного опкода префикса - с заинлайненой хурмой

т.е по итогу обработчик своих вставок

и обычный асм - смешивать но не взбалтывать

ваще легендарная статья (https://dl.acm.org/doi/pdf/10.1145/362248.362270)( Bell, James R. (1973). «Threaded code». Communications of the ACM. 16 (6): 370–372) из https://en.wikipedia.org/wiki/Threaded_code

есть ещё более «лучше одеваться» признак специфичности графа связей в IT:

(https://dl.acm.org/doi/pdf/10.1145/360825.360849)(Dewar, Robert B. K. (June 1975). «Indirect Threaded Code». Communications of the ACM. 18 (6): 330–331) https://en.wikipedia.org/wiki/Robert_Dewar

вот такая многоножка

qulinxao3 ★☆
()
Ответ на: комментарий от romanlinux

Счастливые часов не наблюдают (ц)

alex0x08 ★★★
() автор топика
Ответ на: комментарий от cudeta

А ценность такой статьи очень сомнительна.

Кардинально несогласен. Кому действительно интересно - довольно много может из нее извлечь.

bugfixer ★★★★★
()
Ответ на: комментарий от alex0x08

Они не более умные а более трусливые - боятся что их код точно также будут разбирать.

Вы передёргиваете. Например абсолютно весь мой код ревьюится, как мин двумя людьми (своя специфика - это не прихоть). И, я спешу заметить - это мои коллеги, мы делаем общее дело, и их мнение для меня будет гораздо более весомо чем мнение любого анонима с ЛОРа. И я в таких review вижу только плюсы - зачастую концентрируешься на конкретной проблеме и глаз «замыливается». Но в паблик доступе Вы этот код однозначно никогда не увидите, так что «избиения младенцев» не будет :)

Вообще тред показателен, в который раз иллюстрирует простую мысль что докопаться можно хоть до столба.

Докопаться всегда можно, вопрос целесообразности и грани «good enough». Кто-то к этому приходит раньше, кто-то позже, кто-то вообще никогда…

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Например абсолютно весь мой код ревьюится, как мин двумя людьми

Речь не про вас и ваших коллег и уж тем более не про ревью кода как процесс - я сам занимаюсь ревью по работе еще и написал специальный софт.

Просто на ЛОРе есть ярко выраженная тенденция «осуждаю но не использую и не знаю», что мешает адекватному восприятию реальности. Получается что вот такой разборщик сам абсолютно нихрена не знает, зато очень уверенно выкатывает претензии.

alex0x08 ★★★
() автор топика
Последнее исправление: alex0x08 (всего исправлений: 1)
Ответ на: комментарий от X512

Wayland вообще ни чего не умеет. Это должны уметь композиторы, типа mutter или kwin.

rugir
()
Ответ на: комментарий от alex0x08

Получается что вот такой разборщик сам абсолютно нихрена не знает, зато очень уверенно выкатывает претензии.

Я не знаю кого конкретно Вы сейчас имеете в виду, но если мы говорим о господине @cudeta (от него звучали одни из самых жёстких претензий) - то я таки думаю что в x86 asm он ориентируется лучше меня. Другой вопрос что я не считаю, как бы как сказать - отклонения от его стандартов идеала asm чем-то криминальным. Тем более в контексте этой статьи. Тут же главное было «удочку закинуть»: кому не интересно мимо пройдут, а для тех кому интересно - это уже серьёзное подспорье.

bugfixer ★★★★★
()
Ответ на: комментарий от bugfixer

Ну вот например:

Наверное ты не так понял мой комментарий. На ассемблере я писать могу, в том смысле что бы сделать программу и она запускалась и работала. Но я не вижу смысла писать на ассемблере, не умея при этом писать на нем лучше чем GCC, если не умеешь, то проще инвестировать свои знания в С.

В статье я не вижу ничего интересного по этому поводу. Я думаю что такие статьи это лучше чем ничего, но смысла не вижу, это ЛОР, тут «нинужно» пишут под всем, это же не значит что я за тотальную аннигиляцию.

Я вот тоже толком не умею писать на ассемблере но от чего-то посчитал статью настолько интересной что аж перевел.

alex0x08 ★★★
() автор топика
Ответ на: комментарий от alex0x08

Ну вот например

Забейте, не стОит оно того. Пусть человек думает, не важно даже что он сейчас думает - со временем у него пройдёт. Лучше сконцентрируйтесь на условных «детишках» и передаче знаний / образовательном процессе (хотя бы в формате «заинтересовать») - вот это реально важно.

bugfixer ★★★★★
()
Последнее исправление: bugfixer (всего исправлений: 1)
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.