Я достаточно давно решил ознакомится с ассемблером архитектуры Arm. По большей части для ознакомления и понимания внутренних процессов архитектуры. Чем больше я изучал литературу и различные источники, тем больше я понимал, что нужна практика. Я решил вспомнить ассемблер для x86-х машин и заодно потренироваться на архитектуре Arm.

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

Памятка. Для теста кода я использую Linux. Точнее, если у вас Windows то вам надо будет использовать WSL или виртуальную машину. А если у вас Mac, то есть вероятность, что вы сможете сделать всё точно так же как и на Linux. Не сможете? Не переживайте, просто создайте виртуальную машину Linux.

Сначала надо было определиться с выбором ассемблера. Выбор из ассемблеров достаточно большой: Masm, Nasm, Yasm, Fasm, Gas и другие. Мне же требовался ассемблер, который будет на архитектуре x86 создавать код под любую платформу. И я остановился на ассемблере Gas, по той причине, что это был единственный ассемблер удовлетворяющий моим условиям. Но в настоящий момент, как видно из обновлений по форуму, Fasm так же стал поддерживать архитектуру Arm64 (до этого были ошибки с компиляцией под данную архитектуру). Но всё же я буду использовать Gas, ведь у меня уже давно подготовлено к разработке на данном ассемблере.

Но вы можете попробовать и Fasm. )))

Это видео с общей информацией, кода в нём ни какого нет. Видео сделано давно, помидорами просьба не кидаться.

https://youtu.be/Wk4o7OjXmEw - ссылка на всякий случай, что-то не хочет без ВПН ни чего грузить...

Ни каких эмуляторов использовать не будем, не считая эмуляторов, которые будут исполнять наш код под нашей архитектурой. Это будут эмуляторы от Qemu: qemu-arm и qemu-aarch64. Данные эмуляторы смогут выполнять код только в командной строке, поэтому не надейтесь что вы сможете исполнить код для какого-либо графического окна. Для тестов кода это вполне подойдёт. Кстати, данные файлы могут находиться в Android-SDK (или NDK?), но я могу ошибаться.

Здесь я выкладываю весь код, и два эмулятора, о которых писал выше. Не забываем, эти эмуляторы для Linux, если вы используете Windows или Mac, то вам надо будет либо найти их под данные системы, либо собрать самим... Ни то ни другое не утешительно...

не забудьте, если качаете архив.

Пароль 456123. Пришлось поставить потому что внутри лежат исполняемые файлы для Linux.

Важно! В примерах идут вызовы для ОС Linux! Для того чтоб код идущий в примерах работал с Windows или Mac вам придётся найти информацию самим и переделать эти примеры.
А так же вы можете поделиться этой информацией с другими. ))) Если найдёте её.

Для того чтоб переходить к изучению кода, что вы скачаете по ссылке выше, вам надо знать ассемблер для всех четырёх перечисленных архитектур: x86/x86_64/Arm32/Arm64. Я, как обычно, выкладываю информацию не совсем для новичков.

Установите binutils для нужных архитектур, в данном случае это: i686, x86_64, arm-eabihf (arm-eabi) и aarch64.

Почитайте литературу и источники, если это необходимо.

Различная информация по ассемблерам.
Ассемблер aarch64.
Ассемблер Arm.
Linux x86_64.
Полезно будет почитать книгу "Рудольф Марек. Ассемблер на примерах." раздел "Программирование в Linux".

Думаю на просторах интернета не мало информации, потому поищите. Не забывайте основную документацию, которые предоставляют производители процессоров и создатели архитекрур.

В данном видео пробегаюсь по настройке необходимых инструментов и пробегаюсь по коду Hello World для разных архитектур.

https://youtu.be/c9iC8GW-7mQ - ссылку дублирую.

Это достаточно важная информация с системными вызовами Linux под разные архитектуры!

Для себя я создал Makefile и настроил его немного. Просьба не судить сильно, но я не специалист в этих вопросах, вероятно можно было сделать и лучше.

Makefile для helloGas.
CC64 = as
LC64 = gcc
CC32 = /usr/i686-linux-gnu/bin/as
LC32 = /usr/i686-linux-gnu/bin/ld
CCA64 = /usr/aarch64-linux-gnu/bin/as
LCA64 = /usr/aarch64-linux-gnu/bin/ld
CCA32 = /usr/arm-linux-gnueabihf/bin/as
LCA32 = /usr/arm-linux-gnueabihf/bin/ld
RA64 = ../qemu/qemu-aarch64
RA32 = ../qemu/qemu-arm
default: bX64 rX64
help:

bX64: HelloX64.asm
	$(CC64) -g HelloX64.asm -o HelloX64.o
	$(LC64) -s HelloX64.o -o HelloX64 -no-pie
rX64: HelloX64
	clear
	./HelloX64
bX32: HelloX32.asm
	$(CC32) HelloX32.asm -o HelloX32.o
	$(LC32) HelloX32.o -o HelloX32
rX32: HelloX32
	clear
	./HelloX32
bA64: HelloA64.asm
	$(CCA64) -g HelloA64.asm -o HelloA64.o
	$(LCA64) HelloA64.o -o HelloA64
rA64: HelloA64
	clear
	$(RA64) -L /usr/aarch64-linux-gnu/ -g 1234 ./HelloA64
bA32: HelloA32.asm
	$(CCA32) -g HelloA32.asm -o HelloA32.o
	$(LCA32) HelloA32.o -o HelloA32
rA32: HelloA32
	clear
	$(RA32) ./HelloA32
rgA32: HelloA32
	clear
	$(RA32) -L /usr/arm-linux-gnueabihf/ -g 1234 HelloA32

Данный Makefile настраивался для архитектуры x86_64. Если вы ведёте разработку на других архитектурах, возможно нужны правки. А так же некоторые параметры в файле просто для тестирования были сделаны и их можно убрать или добавить какие-то свои параметры.

Давайте обратим внимание на сборку проекта. Это: bX64, bX32, bA32 и bA64; где b - build, X - x86, A - ARM. Так же и с запуском: rX64, rX32, rA32 и rA64; где r - это run. Всё остальное надеюсь понятно.

В остальном многие (многие - это не все!) лучше меня разбираются, а если вы не разбираетесь в этом, то придётся всё подучить. На данный момент я тут не помощник, уж извините. Но забегая вперёд, можете что-то посмотреть тут, это хоть и относится больше к отладке, но важная информация там так же есть. Так же смотрите документацию по Qemu, в частности загляните сюда. Вероятно это вам поможет разобраться во всём (честно говоря, я уже что-то подзабыл, наверняка надо будет вспомнить и мне).

Да, загляните ещё в эту тему, именно там я начал выкладывать всю информацию и что-то мог упустить здесь.

Давайте быстро взглянем код для Hello World:

x86
// cpu x86_64

.global _start

.section .data
msg:	.ascii	"Hello World!\n"
len = . - msg		# вычисляется длина строки

.section .text
_start:
	mov $4, %eax	# 4 - write
	mov $1, %ebx	# 1 - stdout
	lea msg, %ecx	# адрес сообщения
	mov $len, %edx	# длина сообщения - обязателен префикс '$' перед len
	int $0x80
	
	mov $1, %eax	# 1 - exit
	xor %ebx, %ebx	# 0 - Return
	int $0x80

x86_64
// cpu x86_64

.global _main

.section .data
msg:	.ascii	"Hello World!\n"
len = . - msg		# вычисляется длина строки

.section .text
_main:
	mov $len, %rdx	# длина сообщения - обязателен префикс '$' перед len
	mov $msg, %rsi	# адрес сообщения
	mov $1, %rdi	# 1 - stdout
	mov $1, %rax	# 1 - write
	syscall

	xor %rdi, %rdi
	mov $60, %rax
	syscall

Arm32
// cpu ARM32

.global _start

.section .data
msg:	.ascii	"Hello World!\n"
len = . - msg

.section .text
_start:
	mov r0, #1		// 1 - stdout
	ldr r1, =msg	// загружаем адрес строки
	mov r2, #len	// длина строки - интересная ситуация... требует префикс '#'
	mov r7, #4		// write
	swi 0

	mov r0, #0		// код возврата
	mov r7, #1		// exit
	swi 0

Arm64
// cpu ARM64

.global _start

.section .data
msg:	.ascii	"Hello World!\n"
len = . - msg

.section .text
_start:
	mov x0, #1		// 1 - stdout
	ldr x1, =msg	// адрес
	mov x2, len 	// длина строки
	mov x8, #64		// системный вызов write
	svc 0			// программное прерывание, сгенерированное пользователем.
					// (вызов супервизора...)
	
	mov x0, #0		// код возврата
	mov x8, #93		// указание на закрытие программы Exit - Terminate
	svc 0

Просматривая код, можно увидеть, что сильно он не отличается для разных архитектур. Данный код отличается системными вызовами и тем, как ассемблер работает с комментариями. Если для архитектур Arm комментарии начинаются с "//", то для архитектур x86 они начинаются с "#"... С чем это связано непонятно... Ассемблер вроде один Gas. Но вот такие вещи запоминать приходится.

Код тем сильнее начинает отличаться, чем больше становится приложение которое мы разрабатываем.

Так же надо не забывать про то, что регистры для архитектур Arm разные. Если для 32-х битных это регистры r0-r15, то для 64-х битных это регистры x0-x31 (w0-w31 их нижняя часть, что так же расходится с первоначальными регистрами).

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

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

В каждом видео я делал разбор кода. Каждый код немного документирован и человеку, который уже знаком с ассемблером, не составит труда разобраться. По крайней мере я на это надеюсь.

Процедуры read/write. (https://youtu.be/r7A0RfLG0l4 - дублирую).

отладка. Выше скидывал ссылку и скину ещё ниже, где рассмотрим отладку немного другую. Но возможно кому-то полезно будет. (https://youtu.be/eUiFfLebXM8 - дублирую).

Давайте немного заденем отладку.

Есть графический отладчик EDB. Это достаточно простой отладчик и разобраться с ним проблем практически не возникает. Но! Этот отладчик работает с архитектурами x86, x86_64 и Arm32... Arm64 он не поддерживает... Так же, для использования данного отладчика вам надо иметь реальную машину на данной архитектуре или как минимум эмулятор с работающей графической оболочкой...

Да, я создавал эмуляторы Arm. Но графическая оболочка на Arm32 не запустилась, на Arm64 работает.

И, из-за всего вышеперечисленного, я искал способ, который будет работать везде. И я нашёл его. Всё было сделано очень давно и достаточно хорошо расписано. Потому я остановился на отладчике GDB. Ознакомьтесь обязательно если вы так же решили использовать GDB для отладки.

Ещё одно видео где делал функции StrToInt/StrToUInt. А так же, на 25-й минуте разбираю отладку используя GDB.

Думаю на этом стоит заканчивать статью. Информации всегда много и... всегда мало. Мало, по той причине, что люди, которые знают эту информацию, думают что о ней знают и другие. А может не хотят просто делиться или считают что в этом нет необходимости. Но необходимость есть. Я потратил очень немало времени на сбор капли в море. И сколько ещё капель не собрал?

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

Надеюсь информация была полезной для вас! Всего хорошего!

Комментарии (34)


  1. kovserg
    24.03.2024 13:19
    +2

    Помимо x86 и arm есть еще mips, sh, blackfin и более чудные архитектуры с регистровыми окнами типа powerpc, байкалов и xtensa(https://sachin0x18.github.io/posts/demystifying-xtensa-isa/). Обычно ассемблер используют для вставок кода который нельзя написать на более высокоуровневых языках. И тут более важной информацией будет ABI или как передаются параметры в подпрограмму.


    1. Seenkao Автор
      24.03.2024 13:19

      Это достаточно важная информация с системными вызовами Linux под разные архитектуры!

      Но думаю это стоит расписать в отдельной теме. Здесь же я больше основывался именно на ассемблере.


    1. Armmaster
      24.03.2024 13:19
      +2

      Байкал это обычный Arm. Про регистровые окна вы видимо Эльбрус имели ввиду


    1. strvv
      24.03.2024 13:19

      Из всех вышеупомянутых можно немного вспомнить про мипс, он еще в атеросах и мтк еще появляется и хтенца, но ес32/8266 это своеобразная хтенца, более того там и риск-в есть.


    1. mpa4b
      24.03.2024 13:19

      С какого момента powerpc стал с регистровыми окнами? Я что-то пропустил? С регистровыми окнами НЯЗ только спарки, из того что как-то живо и не экзотически-проприетарное типа икстенз и эльбрусов всяких.


      1. kovserg
        24.03.2024 13:19

        Да ошибся. Spark, Эльюрус, Itanium и Xtensa используют регистровые окна. Я просто к тому что abi может быть весьма не тривиальным.


  1. SamOwaR
    24.03.2024 13:19

    Порядок операндов в gas для инструкции MOV на x86 выглядит как-то очень непривычно после "классического" ассемблера.


    1. sert
      24.03.2024 13:19

      Это синтаксис AT&T.

      Насчёт различий архитектур, есть хорошая книга: Revers engineering для начинающих.


      1. firehacker
        24.03.2024 13:19

        Непонятно, почему это недоразумение вообще существует. Есть Intel-синтаксис, и, какое совпадение, Intel же эту архитектуру и породила. То есть мы имеем синтаксис от отцов архитектуры, и некий альтернативный вариант, который непонятно почему вообще прижился.


        1. Seenkao Автор
          24.03.2024 13:19

          Это "недоразумение" существовало и использовалось ещё на PDP11.

          вырезка из https://en.wikipedia.org/wiki/X86_assembly_language#Syntax (перевод)

          язык ассемблера x86 имеет две основные синтаксические ветви: Intel syntax и AT & T syntax. Синтаксис Intel доминирует в мире DOS и Windows, а синтаксис AT & T доминирует в мире Unix, поскольку Unix был создан в AT & T Bell Labs.


          1. netch80
            24.03.2024 13:19

            Это "недоразумение" существовало и использовалось ещё на PDP11.

            Это само по себе не основание для переноса такого порядка на X86, при том, что для MIPS, ARM, RISC-V и прочих тот же gas использует порядок "результат первым".

            В данном случае те люди, что сделали порт на 80386 для AT&T V86, заложили диверсию, которую, возможно, сами осознали, но было уже поздно.

            Самая "мякотка" в этой диверсии в ситуациях типа:

            0000000000000000 <.text>:
               0:   0f a4 d8 0a             shld   $0xa,%ebx,%eax
               4:   0f ac d8 0a             shrd   $0xa,%ebx,%eax
            
            0000000000000000 <.text>:
               0:   0f a4 d8 0a             shld   eax,ebx,0xa
               4:   0f ac d8 0a             shrd   eax,ebx,0xa

            Разворачивать все аргументы, а не только переносить приёмник вперёд... для shld, shrd в какой последовательности стоят аргументы - критично для понимания - а тут такая пакость возникла.


            1. Seenkao Автор
              24.03.2024 13:19

              Для меня синтаксис AT&T более удобен. Я к нему быстрее привык, чем к синтаксису Intel. И это при том, что большую часть времени я сидел именно на синтаксисе Intel.

              Думаю это не нам решать, по какой причине Unix системы остались на синтаксисе AT&T, а не перешли на соседний.


              1. netch80
                24.03.2024 13:19
                +1

                Для меня синтаксис AT&T более удобен. Я к нему быстрее привык, чем к синтаксису Intel.

                Попробуйте понять, почему вы думаете, что он вам более удобен. При том, что:

                1) Требуется после чтения родных Intel источников каждый раз мысленно разворачивать порядок аргументов.
                2) В некоторых случаях требуется делать замены логики в именовании, как в соотношении fsub :: fsubr.
                3) Некоторые команды переименованы вопреки всякой логике, причём не получено от этого никакой пользы (ну-тко чем отличается ctlq от clto? Почему вообще не решили назвать как sexto и sexti, чтобы никто не путался?)
                4) Порядок аргументов не соответствует подавляющему большинству конкурирующих ISA.

                Стоит ли оно того?

                Думаю это не нам решать, по какой причине Unix системы остались на синтаксисе AT&T, а не перешли на соседний.

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


                1. Seenkao Автор
                  24.03.2024 13:19

                  Эээ... вообще-то и нам, и кому угодно.

                  Нет, не нам. Нам лишь решать использовать этот синтаксис или нет.

                  почему вы думаете

                  Не надо заниматься игрой слов. Если вам этот синтаксис не удобен, то это не значит что он не удобен другим. Все ваши "недочёты", нивелируются человеком который читает код и понимает разницу между синтаксисом AT&T и Intel.

                  А люди, которые читают код, иногда даже не обращают внимания на каком ЯП этот код написан. Потому что важна логика кода и что он делает, а не сам код.

                  Вы решили запретить (нам - кому именно нам?) исследовать историю?

                  Извиняюсь, что? ))) Зачем в очередной раз играть словами? Если я вам пишу, про то что: "не нам решать, что делать разработчику", но вы решили за разработчика что: "он должен делать так как вы сказали"!


                  1. netch80
                    24.03.2024 13:19

                    Нам лишь решать использовать этот синтаксис или нет.

                    Именно. Поэтому, несмотря на то, что GCC и Clang по умолчанию используют AT&T syntax, и в ассемблерных кусках в ядрах и libc всяких Linux и *BSD в основном они - как только мы выходим за пределы этого поддомена, наблюдается существенный разворот в сторону Intel стиля. Я как-то анализировал наличную кодобазу в исходниках, где (в основном во всяком мультимедиа и криптографии) любят ассемблерные файлы.

                    Если вам этот синтаксис не удобен, то это не значит что он не удобен
                    другим. Все ваши "недочёты", нивелируются человеком который читает код и
                    понимает разницу между синтаксисом AT&T и Intel.

                    Кто занимается тут игрой слов, вопрос спорный, но я попытаюсь перейти к конструктиву. А он такой, что пропорция тех, кто предпочитает Intel, очень заметная, и за пределами тех, кто исторически с самого начала привык к AT&T, его (AT&T) очень мало хотят.

                    А с учётом резкого падения части X86 в разработках, где требуется ассемблер, будет падать ещё больше. Держать в голове постоянно выкрутки порядка - сложно.

                    Все ваши "недочёты", нивелируются человеком который читает код и
                    понимает разницу между синтаксисом AT&T и Intel.

                    Можно читать не обращая внимание на язык. А можно - обращая, и это полезнее. Потому что от языка может зависеть, например, реакция на целочисленное переполнение, или отличие && в C от and у Паскаля может давать код, который просто так не перенесётся (в любую из сторон).

                    Недочёты нивелируются, да. Но это лишняя затрата умственных сил, порой резко заметная.

                    Зачем в очередной раз играть словами?

                    Я отвечал на ваш вопрос - "зачем перешли", а не "зачем его использовать", "зачем сохранять" и всё такое. Там, где вы видите игру слов, я вижу минимально корректный учёт того, что действительно сказал собеседник. "Игра слов" выглядит иначе.

                    но вы решили за разработчика что: "он должен делать так как вы сказали"!

                    Они сами и решают, без меня (см. соседний комментарий). В MIPS, ARM, RISC-V, куче других не только приёмник первый - это не было бы проблемой, если бы единообразно в пределах ISA он был последним - но Unix мир не меняет то, что сделано у соседей. Диверсия введена только для x86 (и, ещё раз повторюсь, не только в плане порядка аргументов). И тем не менее куда ни глянь где nasm, fasm, другие аналоги - Intel порядок тотально.


                    1. Seenkao Автор
                      24.03.2024 13:19

                      Кто занимается тут игрой слов, вопрос спорный, но я попытаюсь перейти к конструктиву.

                      Проблема в том, что вы выше, уже за меня всё решили. Удобнее это мне или нет.

                      Но это лишняя затрата умственных сил, порой резко заметная.

                      Человеку надо тратить умственные силы, чтоб "не засиживаться на месте". Голова человека должна работать и человек должен осознавать свои ошибки и уметь их исправлять.

                      Так что зачастую, лишний раз пошевелить мозгами не помешает.

                      Я отвечал на ваш вопрос - "зачем перешли", а не "зачем его использовать", "зачем сохранять" и всё такое.

                      Тогда не соизволите объяснить, каким образом ваше мнение должно было учитываться при переходе/не переходе с одного синтаксиса на другой? Для разработчиков Unix в то время.


                      1. netch80
                        24.03.2024 13:19

                        Тогда не соизволите объяснить, каким образом ваше мнение должно было учитываться при переходе/не переходе с одного синтаксиса на другой? Для разработчиков Unix в то время.

                        А это как раз у вас тут образцовая, 300%ная демагогия. Потому что речь не о ситуации, типа, пришёл покупатель земельного участка и вдруг "почему тут сарай? я хотел именно тут пасеку", а продавец, поставивший этот сарай 40 лет назад, не мог представить себе подобного желания.

                        Нет, аргументы в пользу сохранения порядка аргументов (и вообще синтаксиса в целом) Intel они полностью и безоговорочно были понятны и тогда, и в их принципиальной корректности сомнений не было. А вот почему для конкретной команды исполнителей вес этих аргументов оказался ниже веса аргументов за сохранение того, к чему они привыкли в случае VAX, PDP-11 или, как предположил mpa4b@, M68k, несмотря на потенциальные проблемы при будущем расширении активно развивающейся архитектуры - вот это как раз хороший предмет для исторического исследования. И вот это вы почему-то пытаетесь заткнуть откровенной подтасовкой, типа, что здесь моё мнение, а не аргументация.

                        Человеку надо тратить умственные силы, чтоб "не засиживаться на месте

                        Но на что-то полезное. Решение кросвордов, например (пример маргинальный, но показательный) слишком малоэффективно для целей написания программ. Разворот аргументов каждый раз в голове - из этой же серии.

                        Проблема в том, что вы выше, уже за меня всё решили. Удобнее это мне или нет.

                        Я за вас ничего не решал. Вы можете для себя переделать любой язык и любой ассемблер как угодно. Посмотрите, например, на ассемблер Go для x86. Он совершенно несовместим ни с Intel, ни с AT&T - там, например, регистр зовётся AX независимо от размера данных в операции. Но его авторы имели свои цели (которые как раз озвучили), и там хотя бы известно, как они описали свои причины. И они не стараются доказать, что это лучший вариант... В случае же AT&T vs. Intel "народная" любовь статистически именно на стороне Intel, и этому причины не только в том, что владелец архитектуры гнёт в эту сторону.


                      1. Seenkao Автор
                        24.03.2024 13:19

                        Я за вас ничего не решал.

                        Точнее это я сам себе писал?

                        Попробуйте понять, почему вы думаете, что он вам более удобен.

                        или мне привиделось?

                        Посмотрите, например, на ассемблер Go

                        Ну тогда можно было тогда взять (для примера) кроссплатформенный ассемблер FasmG. Зачем брать для этого ЯВУ?

                        А это как раз у вас тут образцовая, 300%ная демагогия.

                        Нападение лучшее средство защиты. Это ведь я писал:

                        Цитата: "Эээ... вообще-то и нам, и кому угодно."

                        в ответ на мои слова, цитата: "Думаю это не нам решать, по какой причине Unix системы остались на синтаксисе AT&T, а не перешли на соседний."

                        ... и опять же скажем что мы ни за кого ни чего не решаем... всё по стандарту...

                        Думаю пора завязывать этот диалог.


                1. Seenkao Автор
                  24.03.2024 13:19

                  clto

                  сами придумали команду?

                  В синтаксисе AT&T специально к командам "прицепили" буквы: b, w, l, q, s, t.

                  Странно что вы не жалуетесь на формат команд SIMD-инструкций. Ведь это ближе к AT&T синтаксису, а не Intel.


                  1. netch80
                    24.03.2024 13:19

                    сами придумали команду?

                    cwtd. Опечатался немного, потому что там логики 0 целых фиг десятых. И вы тут таки неправы:

                    В синтаксисе AT&T специально к командам "прицепили" буквы: b, w, l, q, s, t.

                    потому что эта группа команд этим правилам не следует аж никак:

                    AT&T:

                       0:   66 98                   cbtw   
                       2:   98                      cwtl   
                       3:   48 98                   cltq   
                       5:   66 99                   cwtd   
                       7:   99                      cltd   
                       8:   48 99                   cqto 

                    Но Intel:

                       0:   66 98                   cbw    
                       2:   98                      cwde   
                       3:   48 98                   cdqe   
                       5:   66 99                   cwd    
                       7:   99                      cdq    
                       8:   48 99                   cqo

                    Логики нет у обоих, но у Intel хоть как-то ровнее. И, повторюсь, названные вами суффиксы не работают:))

                    Я бы их соответственно назвал: sexti8, sexti16, sexti32, sexto16, sexto32, sexto64 (или альтернативно: sexti ax,al; sexti eax,ax; sexti rax,eax; sexto dx,ax; sexto edx,eax; sexto rdx,rax). Но я тут не решаю.

                    Странно что вы не жалуетесь на формат команд SIMD-инструкций. Ведь это ближе к AT&T синтаксису, а не Intel.

                    В чём именно ближе? Вот с ходу из доки Intel:

                    66 0F 58 /r ADDPD xmm1, xmm2/m128
                    Add packed double precision floating-point values from xmm2/mem to xmm1 and store result in xmm1.

                    VEX.128.66.0F.WIG 58 /r VADDPD xmm1,xmm2, xmm3/mem
                    Add packed double precision floating-point values from xmm3/mem to xmm2 and store result in xmm1.

                    Приёмник снова первый. Где тут "ближе к AT&T"?

                    Кстати, вы вспомнили SIMD?

                      15:   c5 f0 5c c2             vsubps xmm0,xmm1,xmm2
                      15:   c5 f0 5c c2             vsubps %xmm2,%xmm1,%xmm0

                    Почему вычитаемое слева от уменьшаемого? ;))


                    1. Seenkao Автор
                      24.03.2024 13:19

                      Логики нет у обоих, но у Intel хоть как-то ровнее.

                      cbtw или cbw - byte to word
                      cwtl или cwde - word to longword
                      cltq или cdqe - longword to qword

                      В чём ровнее? Для AT&T я даже не задумываюсь о том, какое идёт расширение.

                      В чём именно ближе?

                      В том, что стали просто буквы использовать, а не полномасштабные команды. Если следовать логике Intel, то все команды должны быть расписаны чуть ли не в длинную цепочку каждое слово отдельно (это субъективное мнение).


                      1. netch80
                        24.03.2024 13:19

                        Для AT&T я даже не задумываюсь о том, какое идёт расширение.

                        Какая логика вам объясняет, когда писать cwtl, а когда - cwtd?

                        В том, что стали просто буквы использовать, а не полномасштабные команды.

                        Вы имеете в виду, наверно, указание размера одиночного аргумента в векторных командах. Да, оно там неизбежно, но размер полного набора аргументов по-прежнему определяется регистром. "Полномасштабные команды" это с указаниями типа "dword ptr"? Если нет, уточните.

                        И я там в последний момент дописал вопрос, вы могли не заметить. Intel:

                           a:   39 d8                   cmp    eax,ebx
                          15:   c5 f0 5c c2             vsubps xmm0,xmm1,xmm2

                        Но AT&T:

                            a:   39 d8                   cmp    %ebx,%eax
                           15:   c5 f0 5c c2             vsubps %xmm2,%xmm1,%xmm0

                        Как так получилось, что уменьшаемое справа от вычитаемого? Ссылка на историю появления от PDP-11 тут не сработает: у PDP-11, даже, когда в "sub p, q" было вычитание p из q, при этом "cmp p, q" вычитало q из p.


                      1. Seenkao Автор
                        24.03.2024 13:19

                        Какая логика вам объясняет, когда писать cwtl, а когда - cwtd?

                        Довольно странный вопрос. Вы знаете что делает команда cwtl? cwtd?

                        Вы не видите различия их конечной работы? Или конечный результат eax против dx:ax ни чего не значит?

                        Как так получилось, что уменьшаемое справа от вычитаемого?

                        Да, такие моменты обескураживают. Но видятся достаточно логичными. Если у Intel операнд-приёмник идёт первым, а операнд-источник последним, то при полном развороте (когда два источника, один приёмник) для синтаксиса AT&T будет достаточно правильно поменять местами именно все операнды, а не какой-то один (но это лишь догадки с моей стороны).

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


                      1. netch80
                        24.03.2024 13:19

                        Довольно странный вопрос. Вы знаете что делает команда cwtl? cwtd?

                        Пожалуйста, не делайте вид, что не поняли вопрос. Я не про понимание семантики, а про то, как из семантики дальше выводится конкретная буква окончания аббревиатуры. Тут понять невозможно, надо просто запомнить.

                        то при полном развороте (когда два источника, один приёмник) для
                        синтаксиса AT&T будет достаточно правильно поменять местами именно
                        все операнды, а не какой-то один (но это лишь догадки с моей стороны).

                        О! Извините, но, вероятно, вы себя тут сами засокра́тили (от имени Сократ). Получается, что синтаксис Intel всё равно исходный, и выяснение вопроса, как правильно, начинается с него... а затем зачем-то развернуть весь порядок.

                        Ведь в данном случае надо просто последовательно считать значения один за другим, не меняя в дальнейшем их местами.

                        Для чего именно? Для вычитания всё равно требуются оба аргумента, чтобы начать реальную операцию...


                      1. Seenkao Автор
                        24.03.2024 13:19

                        Тут понять невозможно, надо просто запомнить.

                        И? Это везде так. И в синтаксисе Intel тоже надо запоминать. Что вы пытаетесь тогда доказать?

                        Получается, что синтаксис Intel всё равно исходный

                        Где я писал обратное?

                        Для чего именно?

                        Для компилятора.

                        Я повторяюсь? Я ведь уже это написал?!

                        Последовательность байтов. Достаточно развернуть последовательность и получим тот же самый код, только из другого синтаксиса (вы точно программист?).

                        Возможно это мои догадки, но пока тут с вами демагогией занимаюсь, пришло на ум что синтаксис AT&T более правильный по отношению к компилятору. Надо будет изучить этот вопрос и более точно всё узнать. Наверняка не просто так была развёрнута последовательность источников и приёмника.


                      1. mpa4b
                        24.03.2024 13:19

                        Ссылка на историю появления от PDP-11 тут не сработает

                        А ссылка например на 68k сработает?


                      1. netch80
                        24.03.2024 13:19

                        Ну, возможно, да. Просто обычно в источниках пишут, что AT&T синтаксис был взят по аналогии с PDP-11. Я думаю, это уже натяжка, но на этом не акцентировал, а предполагал скорее VAX, на котором таки были образцовые Unix системы по состоянию на 1985. M68k тут как-то побоку, но как источник сомнительных решений типа "cmp p,q это источник флагов согласно q-p" вполне может прокатить...


                      1. mpa4b
                        24.03.2024 13:19

                        Между прочим, это не "сомнительные решения", а основа большинства дешёвых (т.е. не всяких там вендорлоков типа VAX) unix-машин 80ых. Так что влияние 68k может быть даже больше, чем кривенького vax.


    1. netch80
      24.03.2024 13:19
      +1

      Можно включить Intel syntax.

      Вообще так называемый AT&T syntax, происходящий от прямого переноса логики PDP-11 на X86 ребятами, сделавшими вначале AT&T V86, и что перешло в SCO и затем во все юниксы на X86 - да, штука немного странная. Эффекты не только в порядке аргументов - например, в некоторых командах FPU. Но в реальности достаточно легко привыкаешь.


  1. Refridgerator
    24.03.2024 13:19

    если у вас Windows то вам надо будет использовать WSL или виртуальную машину. А если у вас Mac, то есть вероятность, что вы сможете сделать всё точно так же как и на Linux. Не сможете? Не переживайте, просто создайте виртуальную машину Linux.

    А можно мне всё-таки без Линукса и WSL просто писать на ассемблере прямо в вижуал студии? Ну пожалуйста.


    1. Seenkao Автор
      24.03.2024 13:19

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


    1. unreal_undead2
      24.03.2024 13:19
      +1

      masm вроде в студию до сих пор входит, так что по крайней мере под текущую архитектуру писать никто не мешает.


  1. chnav
    24.03.2024 13:19

    Лично для меня ассемблер больше для понимания логики программ и реверса. Иногда (редко) приходилось инжектировать код, но и в этом случае обычно достаточно написать на C/C++, компильнуть, просмотреть ASM в листинге и обрезать весь обвес. А вот чтобы прямо писать на ассемблере с макросами с чистого листа так и осталось в глубинах времён DOS.

    PS: ещё любопытно изучать как работают разные оптимизации на одном и том же исходном Сишном коде.


    1. firehacker
      24.03.2024 13:19

      Зачем что-то обрезать? __declspec(naked).

      Когда у людей ассемблер полотно ассоциируется с DOS, в этом есть что-то глубоко порочное.