Так сложилось, что я совсем не знаю ассемблера. Даже несмотря на то, что я разрабатываю компиляторы, на уровень близкий к аппаратуре я почти не спускаюсь. Была пара попыток его выучить, но я просто не находил подходящего материала. В итоге решил что если его нет, то нужно написать самому. В этой заметке я планирую показать как написать простой Hello world на ассемблере.
В данной статье я преследую несколько целей:
Я буду стараться давать минимум теории, т.к. её рассказывают много где, гораздо более подробно и понятно. Поэтому буду описывать только то, что касается данного примера.
Итак, задача: написать программу, выводящую на экран сообщение "Hello, world". В качестве эталона возьмём программу на C:
Сборка и запуск:
Здесь специально не использована стандартная библиотека, а применён системный вызов write. Подробнее про него можно прочесть по команде man 2 write.
В качестве процессора на данной архитектуре применяется Intel Core i5, операционная система - Gentoo GNU/Linux, синтаксис AT&T. По моей любимой привычке сначала напишем программу, а потом будем думать.
Сборка и запуск:
Теперь попытаемся понять что произошло.
Краткое описание синтаксиса:
На каждой строчке находятся команды (statement). Команда начинается с нуля и более меток, после которых находится ключевой символ, обозначающий тип команды. Всё что начинается с точки `.' является директивой ассемблера. Всё что начинается с буквы является инструкцией ассемблера и транслируется в машинный код. Комментарии бывают многострочными `/**/' и однострочными `#'.
Директивы
Далее идёт директива
Директива
Директива
После метки
Данная программа написана под процессор Intel архитектуры amd64 (она же x86_64). Это 64-х битное расширение архитектуры IA-32. Описание самой архитектуры процессора находится в [intel1]. Подробное описание команд процессора находится в [intel2].
Итак, в данной программе мы оперируем регистрами - внутренней памятью процессора. Архитектура amd64 содержит очень мало регистров - всего 16 64-х разрядных регистров общего назначения: RAX, RBX, RCX, RDX, RBP, RSI, RDI, RSP, R8D-R15D.
Операция
Далее идёт операция
Понятно, что помимо номеров нам нужны ещё аргументы этих вызовов. Их можно найти следующим образом:
Но в целом таблицами, подготовленными хорошими людьми пользоваться удобнее.
Итак, видно, что вызов write требует 3 аргумента. Первый - это дескриптор файла вывода. Он кладётся на регистр rdi. Мы на rdi кладём 1, что является дескриптором stdout. На регистр rsi кладётся указатель на адрес строки. И на регистр rdx кладётся длина строки. Всё, теперь, когда все регистры подготовлены, можно делать syscall и нам будет выведено сообщение.
Далее нужно выйти из программы. Для этого используется системный вызов exit. Он имеет номер 60 и требует код возврата в качестве первого аргумента. Мы завершаемся с кодом 0, как и положено успешно выполненной программе.
Не устали? Теперь внезапно рассмотрим sparc. Меня эта платформа интересует, т.к. одна из линеек процессоров Эльбрус основана на этой архитектуре. Я тестировался на процессорах TI UltraSparc III+ (Cheetah+) с ОС Gentoo и процессорах Эльбрус R1000 c ОС Эльбрус. Итак, смотрим:
Сборка и запуск:
Вроде как отличий немного. Синтаксис as был описан в блоке amd64, разве что здесь однострочные комментарии задаются символом
Данные регистры называются r регистрами и используются для целочисленных вычислений. Плавающие регистры называются f регистрами, они расположены отдельно, и о них мы сегодня говорить не будем. Интересно отметить, что сама архитектура предполагает от 64 до 528 r регистров, но регистровое окно содержит только 24. Чтение %g0 всегда возвращает 0, а запись в него не даёт эффекта. Вообще на спарке регистры сделаны очень круто, но их очень долго описывать, советую прочитать документацию [sparcv9].
Переходим к инструкциям. Начнём с инструкции
Синтетические инструкции не являются частью стандарта, но входят в информационное приложение к нему, так что их можно смело использовать.
Следующая инструкция
В данной статье я преследую несколько целей:
- Изучить основы работы с ассемблером
- Сравнить ассемблеры процессоров различных архитектур и, как следствие, показать разные аппаратные особенности
- Написать материал по которому новички далее смогут самостоятельно продолжить изучение ассемблера
1. Введение
Я буду стараться давать минимум теории, т.к. её рассказывают много где, гораздо более подробно и понятно. Поэтому буду описывать только то, что касается данного примера.
Итак, задача: написать программу, выводящую на экран сообщение "Hello, world". В качестве эталона возьмём программу на C:
#include <unistd.h>
int main()
{
const char * msg = "Hello, world\n";
write(0, msg, 13);
return 0;
}
Сборка и запуск:
$ gcc t.c && ./a.out
Hello, world
Здесь специально не использована стандартная библиотека, а применён системный вызов write. Подробнее про него можно прочесть по команде man 2 write.
2. amd64
В качестве процессора на данной архитектуре применяется Intel Core i5, операционная система - Gentoo GNU/Linux, синтаксис AT&T. По моей любимой привычке сначала напишем программу, а потом будем думать.
.section .data
hello_str:
.string "Hello, world\n"
.set hello_str_len, . - hello_str - 1
.section .text
.globl _start
_start:
# Здесь подготавливаем и вызываем write
mov $1, %rax
mov $1, %rdi
mov $hello_str, %rsi
mov $hello_str_len, %rdx
syscall
# Здесь подготавливаем и вызываем exit
mov $60, %rax
mov $0, %rdi
syscall
Сборка и запуск:
$ as tt.s -o tt.o && ld tt.o && ./a.out
Hello, world
Теперь попытаемся понять что произошло.
Краткое описание синтаксиса:
На каждой строчке находятся команды (statement). Команда начинается с нуля и более меток, после которых находится ключевой символ, обозначающий тип команды. Всё что начинается с точки `.' является директивой ассемблера. Всё что начинается с буквы является инструкцией ассемблера и транслируется в машинный код. Комментарии бывают многострочными `/**/' и однострочными `#'.
Директивы
.section
обозначают начало секций. Секция - это диапазон адресов без пробелов, содержащий в себе данные, предназначенные для одной цели [as]. Объектный файл, сгененрированный as имеет как минимум три секции: .text
, .data
, .bss
. Внутри объектного файла по адресу 0 располагается секция .text
, за ней идёт секция .data
, а за ней секция .bss
. Все адреса as вычисляет как (адрес начала секции) + (смещение внутри секции). Итак, что же означают секции:- .data - в этой секции обычно хранятся константы
- .text - в этой секции обычно хранятся инструкции программы
- .bss - содержит обнулённые байты и применяется для хранения неинициализированной информации
.data
у нас стоит метка hello_str
, которая указывает на начало строки.Далее идёт директива
.string
. Это псевдо операция, копирующая байты в объектник.Директива
.set
присваивает символу значение выражения. Т.о. мы говорим что символ hello_str_len
равен выражению . - hello_str - 1
. Символ `.
' означает текущий адрес. Вычитая из него адрес метки hello_str
получаем длину строки с завершающим нулём. Чтобы он не попал на печать вычитаем 1.Директива
.globl
говорит что данный символ должен быть виден ld. Т.е. теперь символ _start
сможет быть слинкован. Это нужно, т.к. вход в программу осуществляется именно через этот символ.После метки
_start
начинаются непосредственно ассемблерные инструкции. И теперь опять вернёмся к теории.Данная программа написана под процессор Intel архитектуры amd64 (она же x86_64). Это 64-х битное расширение архитектуры IA-32. Описание самой архитектуры процессора находится в [intel1]. Подробное описание команд процессора находится в [intel2].
Итак, в данной программе мы оперируем регистрами - внутренней памятью процессора. Архитектура amd64 содержит очень мало регистров - всего 16 64-х разрядных регистров общего назначения: RAX, RBX, RCX, RDX, RBP, RSI, RDI, RSP, R8D-R15D.
Операция
mov
предназначена для копирования первого операнда во второй (заметьте, что это особенность синтаксиса AT&T, и интеловский синтаксис имеет обратный порядок операндов). Мы можем скопировать константу, значение общего или сегментного регистра или значение из памяти. Копировать можно в общий или сегментный регистр или память. Для обозначения констант используется символ $
, а для регистров - %
Чуть позже станет понятно что куда и зачем мы копировали.Далее идёт операция
syscall
. Она делает системный вызов. Системный вызов - это функция из ядра ОС. Каждый системный вызов производится по номеру. Он должен находиться в регистре rax
. Номера системных вызовов можно посмотреть в таблицах [syscall1][syscall2]. Но можно выяснить самому. Их конкретное местоположение зависит от дистрибутива. В моём случае они, например, находятся в файле /usr/include/asm/unistd_64.h. Вот выдержка из этого файла:
...
#define __NR_read 0
#define __NR_write 1
#define __NR_open 2
...
#define __NR_execve 59
#define __NR_exit 60
#define __NR_wait4 61
...
Понятно, что помимо номеров нам нужны ещё аргументы этих вызовов. Их можно найти следующим образом:
$ cd /usr/src/linux/
$ grep -rA3 'SYSCALL_DEFINE.\?(write,' *
fs/read_write.c:SYSCALL_DEFINE3(write, unsigned int, fd, const char __user *, buf,
fs/read_write.c- size_t, count)
fs/read_write.c-{
fs/read_write.c- struct fd f = fdget_pos(fd);
Но в целом таблицами, подготовленными хорошими людьми пользоваться удобнее.
Итак, видно, что вызов write требует 3 аргумента. Первый - это дескриптор файла вывода. Он кладётся на регистр rdi. Мы на rdi кладём 1, что является дескриптором stdout. На регистр rsi кладётся указатель на адрес строки. И на регистр rdx кладётся длина строки. Всё, теперь, когда все регистры подготовлены, можно делать syscall и нам будет выведено сообщение.
Далее нужно выйти из программы. Для этого используется системный вызов exit. Он имеет номер 60 и требует код возврата в качестве первого аргумента. Мы завершаемся с кодом 0, как и положено успешно выполненной программе.
3. Sparc v9
Не устали? Теперь внезапно рассмотрим sparc. Меня эта платформа интересует, т.к. одна из линеек процессоров Эльбрус основана на этой архитектуре. Я тестировался на процессорах TI UltraSparc III+ (Cheetah+) с ОС Gentoo и процессорах Эльбрус R1000 c ОС Эльбрус. Итак, смотрим:
.section .data
hello_str:
.ascii "Hello, world\n"
.set hello_str_len, . - hello_str
.global _start
.section .text
_start:
! Подготавливаем и вызываем write
mov 1, %o0
set hello_str, %o1
mov hello_str_len, %o2
mov 4, %g1
ta 0x10
! Подготавливаем и вызываем exit
mov 0, %o0
mov 1, %g1
ta 0x10
Сборка и запуск:
$ as -Av9 -64 t1.s -o t1.o && ld -Av9 -m elf64_sparc t1.o && ./a.out
Hello, world
Вроде как отличий немного. Синтаксис as был описан в блоке amd64, разве что здесь однострочные комментарии задаются символом
!
, поэтому его опускаем и переходим сразу к отличиям. Сразу скажу, что речь идёт о Sparc v9 если не оговорено другое. v9 является 64-х битным расширением архитектуры sparc v8. Начнём с регистров. Их здесь больше чем в amd64 - целых 32 общего назначения, доступных пользователю. Сами регистры называются %r0 - %r31, но у них есть логическое разделение:Название | Имя внутри окна | Имя r-регистра |
---|---|---|
Глобальные (global) | %g0 - %g7 | %r0 - %r7 |
Выходные (out) | %o0 - %o7 | %r8 - %r15 |
Локальные (local) | %l0 - %l7 | %r16 - %r23 |
Входные (in) | %i0 - %i7 | %r24 - %r31 |
Данные регистры называются r регистрами и используются для целочисленных вычислений. Плавающие регистры называются f регистрами, они расположены отдельно, и о них мы сегодня говорить не будем. Интересно отметить, что сама архитектура предполагает от 64 до 528 r регистров, но регистровое окно содержит только 24. Чтение %g0 всегда возвращает 0, а запись в него не даёт эффекта. Вообще на спарке регистры сделаны очень круто, но их очень долго описывать, советую прочитать документацию [sparcv9].
Переходим к инструкциям. Начнём с инструкции
mov
. От интела эта инструкция отличается тем, что её нет в Спарке. Sparc - это RISC архитектура с малым количеством команд, но для удобства программистов ассемблер поддерживает синтетические инструкции. В частности приведённый mov
возможно будет оттранслирован следующим образом (есть несколько способов трансляции в зависимости от аргументов):mov 1, %o1
-> or %g0, 1, %o1
Синтетические инструкции не являются частью стандарта, но входят в информационное приложение к нему, так что их можно смело использовать.
Следующая инструкция
set
, являющаяся синонимом к инструкции setuw
, которая тоже является синтетической инструкцией. Её раскрытие возможно выглядит следующим образом:set hello_str %o2 | -> |
|
sethi
поместит старшие 22 бита hello_str
(т.е. её адрес) на регистр %o2. Инструкция or
поместит туда младший остаток. Обозначения %hi и %lo нужны для взятия старших и младших битов соответственно. Такие сложности возникают из-за того что инструкция кодируется 32 битами, и просто не может включать в себя 32-х битную константу.Далее мы кладём значение 4 на глобальный регистр %g1. Можно догадаться что это номер вызова write. Системный возов будет искать номер вызова именно там.
Операция
ta
инициирует системное прерывание. Её аргументом является тип системного прерывания. Скажу честно - я не нашёл нормального описания системных вызовов для v9, а то что туда надо подавать 0x10 выяснил случайно из архивов какой-то переписки. Поэтому придётся просто это запомнить :)Далее производятся аналогичные действия для вызова exit, думаю их пояснять не нужно.
UPD:
Спасибо уважаемому Анониму за версию данной программы для SunOS 5.10:
.section ".text"
.global _start
_start:
mov 4,%g1 ! 4 is SYS_write
mov 1,%o0 ! 1 is stdout
set .msg,%o1 ! pointer to buffer
mov (.msgend-.msg),%o2 ! length
ta 8
mov 1,%g1 ! 1 is SYS_exit
clr %o0 ! return status is 0
ta 8
.msg:
.ascii "Hello world!\n"
.msgend:
Запуск:
$ as t1.s -o t1.o && ld t1.o && ./a.out
Hello world!
4. Эльбрус
Ну и, собственно, жемчужина коллекции - процессор Эльбрус. Работа проводилась на процессоре Эльбрус-4С, который имеет архитектуру команд v3 (наше внутреннее обозначение). Управляется машина ОС Эльбрус. Про сам Эльбрус можно почитать в [elbrus], про какую-либо документацию, находящуюся в открытом доступе мне неизвестно.
Как и Sparc, архитектура Эльбруса рассчитана в первую очередь на то что оптимальный код выдаст компилятор. Но в отличает от Sparc, ассемблер Эльбруса вообще не предназначен для людей. Итак, вот наш пример:
.section ".data"
$hello_msg:
.ascii "Hello, world\n\000"
.section ".text"
.global _start
_start:
! Подготавливаем вызов write
{
sdisp %ctpr1, 0x3
addd, 0 0x0, 13, %b[3]
addd, 2 0x0, [ _f64, _lts1 $hello_msg ], %b[2]
addd, 1 0x0, 0x1, %b[1]
addd, 3 0x0, 0x4, %b[0]
}
! Вызываем write
{
call %ctpr1, wbs = 0x4
}
! Подготавливаем вызов exit
{
sdisp %ctpr2, 0x1
addd, 0 0x0, 0x0, %b[1]
addd, 1 0x0, 0x1, %b[0]
}
! Вызываем exit
{
call %ctpr2, wbs = 0x4
}
Сборка и запуск:
$ las t.s -o t.o && ld t.o && ./a.out
Hello, world
Начнём с изменения синтаксиса.
Мы видим что к синтаксису добавились фигурные скобки. Процессоры Эльбрус основаны на VLIW архитектуре, а значит могут исполнять множество статически спланированных команд за такт. Набор таких команд называется широкой командой (ШК) и заключается в фигурные скобки. Остальной синтаксис более или менее идентичен.
Если посмотреть на команду сборки, то вместо as используется las. Это наш местный ассемблер, но сейчас идёт процесс перехода на gas, поэтому скоро он станет неактуален (отдел, занимающийся ассемблером уже сейчас ругается если я его использую, но в дистрибутиве пока именно он).
Чтобы процессор мог исполнять много команд за такт, ему нужно много регистров. Согласен, что их никогда не бывает много, но для программы на Эльбрусе регистровый файл содержит 256 регистров общего назначения размером 64 бита. Из них 224 предназначены для процедурного стека, а 32 являются глобальными регистрами. В Эльбрусе нет отдельных регистров для плавающих вычислений, все они выполняются на одном конвейере и хранятся в общих регистрах. Именование регистров идёт следующим образом:
- %r<номер> - прямоадресуемые регистры текущего окна. <номер> является индексом относительно базы текущего окна
- %b[<номер>] - вращаемые регистры текущего окна. <номер> - индекс относительно текущей базы
- %g<номер> - глобальные регистры. <номер> является индексом относительно базы текущей глобальной области
- s одинарный формат регистра - 32 бита (Single)
- d двойной формат регистра - 64 бита (Double)
- x расширенный двойной регистра - 80 бит (Extended)
- q квадро формат регистра - 128 бит (Quadro)
Итак теперь переходим к самой программе. Думаю первые несколько строк и так понятны, поэтому рассмотрим сразу первую ШК:
_start:
{
sdisp %ctpr1, 0x3
addd, 0 0x0, 13, %b[3]
addd, 2 0x0, [ _f64, _lts1 $hello_msg ], %b[2]
addd, 1 0x0, 0x1, %b[1]
addd, 3 0x0, 0x4, %b[0]
}
Рассмотрим первую команду
sdisp %ctpr1, 0x3
. А чтобы понять что это такое и что оно делает нужно ещё немного рассказать про механизм работы переходов в Эльбрусе. В процессорах Эльбрус вызов функции является дорогим удовольствием, поэтому переходы следует готовить заранее. Для этого существует два типа команд - ctp (подготовка перехода) и ct - фактический переход. Нам доступно три регистра перехода: %ctpr1-%ctpr3, т.е. за раз мы можем подготовить три маршрута для прыжка. Существует несколько команд подготовки перехода, нас здесь интересует sdisp
. Эта команда подготавливает переход для системного вызова. Первым аргументом идёт регистр перехода, по которому мы будем совершать прыжок. Вторым аргументом - точка входа в операционную систему, нам она нужна равной 3 (64-х битный вход в ОС).Далее рассмотрим команды
addd
. Как я уже говорил, ассемблер Эльбруса не предназначен для людей, и общепринятых мнемоников здесь пока нет. Так в ассемблере нет команды MOV
. Чтобы положить значение на регистр применяется команда add
. Она производит сложение регистров или констант и записывает их в регистр.Для Эльбруса одновременно доступно 6 арифметико-логических каналов (АЛК), т.е. за такт мы можем производить до 6 сложений. Итак, в первой операции мы кладём число 13 в регистр %b[3] - это длина нашей строки. (В версиях для других архитектур мы вычисляли это программно, и в Эльбрусе можно сделать также, но для las у меня это так и не получилось, хотя в gas всё заработало). Далее на регистр %b[2] мы кладём адрес начала нашего сообщения. Затем в %b[1] кладём идентификатор устройства вывода, и, наконец, в %b[0] кладём номер системного вызова. В целом аналогия с другими архитектурами прослеживается.
Далее может возникнуть вопрос зачем в команде
addd
третья d. В мнемониках команд, реализованных для нескольких форматов операндов, последняя буква обозначает используемый формат. В данном случае мы работаем в double формате, т.е. с полноценным 64-х битным регистром.Отдельно рассмотрим команду
addd, 2 0x0, [ _f64, _lts1 $hello_msg ], %b[2]
, которая, как можно догадаться, кладёт в регистр %b[2] адрес печатаемого сообщения. Для того чтобы закодировать адрес в памяти используется аргумент [ _f64, _lts1 $hello_msg ]
. Квадратные скобки означают взятие адреса. Внутри расположен длинный литерал. Его содержимое означает следующее:- _f64 - формат литерала. В данном случае мы говорим что это литерал размера 64 (хотя он уместится и в 32 бита)
- _lts1 - литеральный слог, кодирующий константное значение. Всего доступно 4 литеральных слога, так что в одной ШК мы не сможем поместить более 4 длинных литералов (в случае формата _f64 - не более 2).
- $hello_msg - идентификатор, обозначающий нашу метку
Во второй ШК у нас производится операция
call %ctpr1, wbs = 0x4
, которая вызывает функцию, переход на которую подготовлен на регистре %ctpr1. т.е. вызывается наш write. Второй аргумент задаёт смещение для новой базы регистрового окна. Здесь я не буду объяснять что это значит, т.к. это займёт много времени, просто пока придётся запомнить что это должно быть так (на самом деле это очень частный случай и нужно понимать как его высчитывать)В третьей ШК мы аналогичным образом подготавливаем переходы для вызова exit, и в четвёртой ШК мы его вызываем.
Всё, проще некуда.
Послесловие
Как я уже говорил в начале, данный материал появился потому что я не смог найти чего-то подобного в сети. На самом деле многое я взял из этого [0xax] блога - описание примера на x86 и вообще саму идею. Для остальных архитектур пришлось изворачиваться :) Позже, во время работы над заметкой, я нашёл это [mechasm] неплохое описание, но оно уже было неактуально.
Вообще я планировал написать эту заметку за неделю-две и перейти на следующий пример. Более того хотел ещё включить описание llvm IR. Но внезапно простенькая заметка про hello world заняла у меня несколько месяцев. Преимущественно из-за Эльбруса. Тут оказалось много нового и непонятного при почти полном отсутствии читабельной документации. И тут хотелось бы сказать огромное спасибо многим моим коллегам, которые терпеливо в течении долгого времени разъясняли мне простейшие вещи.
В данной заметки могут быть неточности, ошибки и вообще фиг знает что, поэтому если что-то не так - пишите, я поправлю :)
Источники
[intel1] Intel® 64 and IA-32 Architectures Software Developer’s Manual Volume 1: Basic Architecture
[intel2] Intel® 64 and IA-32 Architectures Software Developer’s Manual Combined Volumes: 1, 2A, 2B, 2C, 3A, 3B, 3C and 3D
[syscall1] Таблица системных вызовов linux
[syscall2] Другая таблица системных вызовов linux
[as] Мануал по ассемблеру
[0xax] Серия постов про написание hello world на ассемблере amd64. Во многом при написании заметки я смотрел именно в этот пост, там весьма подробное и доходчивое описание с замечаниями в комментах
[mechasm]Аналогичный пост на русском, который я нашёл не сразу и не пользовался им. Но стиль изложения мне нравится
[sparcv9]The SPARC Architecture Manual Version 9
[sparcv9asm] SPARC Assembly Language Reference Manual
[oracle] Актуальная документация от Oracle
[sparcasmbook]SPARC Architecture, Assembly Language Programming, and C. Очень хороший учебник по ассемблеру и по спарку
[elbrus] Микропроцессоры и вычислительные комплексы семейства «Эльбрус»
Круто выглядит, синтаксис практически явушный.
ОтветитьУдалить> нужно ещё немного рассказать про механизм работы переходов в Эльбрусе. В процессорах Эльбрус вызов функции является дорогим удовольствием
А в чем проблема то, ну описали в начале процедуру/функцию, ну вызвали - ровно точно такой же подход разве не в любом (практически) современном языке?
Мы никакую процедуру нигде не описывали. И ассемблер всё же не совсем обычный язык. Суть в том что для того чтобы переключить исполнение на другую функцию нужны определённые затраты. В случае с Эльбрусом, процессор не умеет предсказывать куда мы заранее пойдём, поэтому мы готовим переходы заранее (в данном случае инструкцией sdisp). Т.о. получается что сам sdisp позволит процессору подгрузить заранее инструкции на исполнение, а call вообще не будет затрачивать времени на переход. Если посмотреть в ассемблер intel или sparc, то там такой инструкции нет.
УдалитьА где можно получить удаленный логин на эльбрус?
ОтветитьУдалитьПолучение удалённого логина - штука довольно неофициальная. Можете попробовать написать на адрес mcst@mcst.ru. Сразу дам совет - представьтесь, напишите какие тесты хотите запускать, куда пойдут результаты. Тогда Вам может быть даже ответят.
УдалитьСпасибо. А можно где-то получить cross toolchain для эльбруса или qemu image эльбруса?
ОтветитьУдалитьОчень похоже на сюжет фильма Terminator 3, где герои приходят к выводу, что core of Skynet does not exist at all. :)
Сейчас нет, но очень может быть что вскоре ситуация поменяется.
УдалитьА Вы, простите, в чём именно сомневаетесь? В существовании кросового компилятора, существовании Эльбрус ОС или существовании процессора Эльбрус? )))
Начал писать на mcst@mcst.ru, а потом подумал и остановился. Эльбрус поставлен на защиту кумовского капитализма от всего остального мира. Не дай Бог китайци на фабрике засунут закладку в эльбрус, тогда кумовской капитализм отрежет головы даже тем, кто знал как написать "hello world" на асме. :)
ОтветитьУдалитьНе очень понял что Вы имели ввиду, но могу сказать что во-первых Эльбрусы не производятся в Китае, а во-вторых я бы очень хотел посмотреть на процесс добавления закладки в процессор на этапе напыления транзисторов )
УдалитьВозможно ето все и существует, но не в состоянии military quality.
ОтветитьУдалитьПроцесс закладывания закладки может происходить приблизительно так: платят большие деньги кому-то, кто на каком-то этапе подготовки layout-а добавляет простенький MUX подключенный к шине команд и реагируюший на VLIW="010101...010101". По приходе такого длинного слова MUX отрубает что-нибудь. Человек, который ето сделал пропадает с панамским паспортом в кармане. :)
Идея эльбруса такая: без формальных доказательств предположили, что multi-issue superscalar не сможет выполнять больше 6 инструкций параллельно, взяли и выбросили из процессора ту часть, которая пытается динамически накормить все ALU - ломать не строить; потом начали себя расхваливать, какие мы молодци, пускай все себе делают сложные процессоры, а мы из нашего процессора все выбросили - наш компилятор и двоичный транслятор, получающий доступ к состоянию процессора, сделает всю работу еще лучше (опять без формальных доказательств); потом начали себя расхваливать и за ето тоже. А компилятор не смог сделать ето лучше, он делает хуже и не потому, что компилятор плохой, а потому, что есть принципиальные ограничения, которые не позволят компилятору сделать ето лучше. На динамических языках программирования и динамических задачах (где много ветвлений, а не тупое перемалывание массива чисел) он бессилен. Да есть специальный узкий круг задач, когда компилятор может запаковать VLIW полностью и может быть добиться возможного одновременного выполнения 23 инструкций за такт. Но тогда ето всего лишь специализированный процессор для такого узкого круга задач, а не универсальный как изначально было claimed. И что теперь делать? За потраченные деньги могут надавать по голове. Надо все скрывать, надо прикрываться секретностью и продолжать по Райкину "запускать дурочку" дальше. :) Очень хотелось бы, чтобы все ето было не так...
Довольно странные допущения, причём вообще все. Если Вас интересуют какие-то реальные тесты, то вот отличная серия статей с хабра про тестирование Эльбрусов и потом наши комментарии, которые мы дали тем ребятам после публикации их результатов.
УдалитьЕсли рассматривать вариант с подкупом и встраиванием MUX, то это нужно будет подкупать кого-нибудь и сотрудников МЦСТ, что вообще мягко говоря сомнительно :) А за то что их поставят на фабрике я бы не особо беспокоился.
Я не сказал бы что VLIW бессилен на динамических языках, но да, определённые проблемы есть. Не знаю, получится ли сделать их работу быстрее чем на x86, но сделать их скорость сопоставимой можно.
Да, забить широкую команду сложно, особенно если идёт программа с большим количеством ветвлений. Это прям антипаттерн для нас. Тем не менее есть способы решения этих проблем. Например есть предикатный режим, есть спекулятивное исполнение. В конце концов есть if-conversion, который умеет делать из большого количества ветвлений один большой гиперузел (т.е. линейный участок).
Из практики могу сказать что под Эльбрусом вполне себе крутится линукс под xfce, где я работаю в QtCreator. Так что думаю такие предположения несколько беспочвенны.
Ну и да, кто кому и за какие деньги по голове надаёт? МЦСТ - коммерческая фирма, выполняющая определённые заказы. Если бы кого-то что-то не устраивало или появился бы кто-то получше, заказывали бы у него. Тут всё прозрачно вроде как.
Мы все сидим под Qtcreator-om. У нас на одном Xeon-сервере под ESX-виртуализацией сидит 125 человек под своими Унихами с Х-сами и каждый под своим Qtcreator-om в VNC-сессии - не в этом дело. Динамически можно делать больше, чем статически. Даже если прятать if-ы в предикатные инструкции, то что делать, если есть много вложенных if-ов и т.д. и т.п...
ОтветитьУдалитьЧто сделали на ARM-е. Каждое ведро имеет два подведра. Одно подведро - полный dynamic multi-issue superscalar, а другое - простое, как двери. При сильной загрузке работает первое подведро, а при низкой - второе с целью energy-safe.
Скажите как эксперт, вращающийся в Бабаяновских кругах, а Бабаяноский-team когда-либо рассматривал следующую идею эльбруса (Эльбрус с большой буквы для меня звучит как гора, что-то вроде земля и Земля как планета): не напихивать die чисто Бабаяновскими-VLIW-ведрами, а сделать каждое ведро из двух подведер: полного традиционного dynamic multi-issue superscalar и чисто Бабаяновского. Рафинированные подходы нигде не работают идеально, зато отлично работают гибридные. Пусть даже их instruction set будет уникальнейший отечественный, если того так требует импортозамещение, но 80% кода, которым компилятор не смог заполнить VLIW (ну не смог, и ладненько), отработает на dynamic multi-issue superscalar-е, а 20% кода будет помечено как "удачно заполненный VLIW" отработает на Бабаяновском ведре. Все будут щасливы, и правило 20/80 тоже там где надо. :)
Идея пар-ядер big.LITTLE это от бедности, а не от изобретательности.
УдалитьТо что канает для карманных вычеслителей уже не канает для больших и мощных CPU, тут можно только переизобретать P/S/C-State's
> Динамически можно делать больше, чем статически.
УдалитьНет. Ровно столько же.
> Даже если прятать if-ы в предикатные инструкции, то что делать, если есть много вложенных if-ов и т.д. и т.п...
Страдать. Причём независимо от архитектуры. Много ветвлений в горячем коде - очень тревожный звоночек и скорей всего люди, которые писали данный код просто не думали о производительности.
Вообще мы имеем такую ситуацию с языками программирования и софтом отчасти потому что в своё время IA64 не смог победить. Но код часто можно переписать по-человечески. Можно и не переписывать, просто работать будет чуть медленнее.
> Скажите как эксперт, вращающийся в Бабаяновских кругах
Боюсь, вы немного отстали от жизни. Бабаян ушёл в 2004 и не возвращался. Уже выросло несколько поколений специалистов, не имеющих к нему никакого отношения. Я - где-то третье или четвёртое поколение. Я даже не берусь сказать какой процент его работы находится в современных Эльбрусах.
Касательно пар-ядер, мне о таких исследованиях внутри МЦСТ ничего не известно. Идея, конечно, интересная и даже заманчивая, но надо понимать что приведёт к куче других проблем, поэтому не факт что будет лучше. Это только на пальцах всё легко и просто :)
Вообще если интересует что у нас планируют выпускать, то в сети есть презенташки с road map'ами до 2021 года. Там идёт движение в сторону увеличения количества ядер на процессоре. Пока из того что известно - планируется Эльбрус-32С с техпроцессом 10нм в районе 20-ого года.
"Нет. Ровно столько же." - не может быть такого. Это же противоречит вашему "IA64 не смог победить".
УдалитьВложенные if-ы будет трудно запретить в демократическом обществе - будут думать: ето Хрущев опять учит художников, что нужно рисовать. :)
Бабаян - это имя нарицательное. Например, страна может еще долго оставаться ленинской даже после ухода Ленина. Как за 10 лет может смениться 3 поколения? :)
"движение в сторону увеличения количества ядер" не имеет ничего общего с улучшениями заполнения VLIW. Ваш компилятор имеет road map? Он будет распараллеливать по ядрам статически или динамически на виртуальной машыне потока данных (что-то как в TERAFLUX, TALM/Trebuchet, BMDFM, etc.)?
> "Нет. Ровно столько же." - не может быть такого. Это же противоречит вашему "IA64 не смог победить".
УдалитьНе вижу противоречия. А под динамикой Вы вообще что понимаете? Out-Of-Order или динамические языки? В обоих случаях множество решаемых задач одинаково.
> Вложенные if-ы будет трудно запретить в демократическом обществе...
Если даже goto до конца не добили... Но кому нужна скорость - быстро от них откажутся.
> Бабаян - это имя нарицательное.
Ну оно как бы должно что-то означать. Я не понимаю что под этим подразумевается и причём он вообще здесь )
> "движение в сторону увеличения количества ядер" не имеет ничего общего с улучшениями заполнения VLIW.
Я нигде обратного не утверждал. Пример я привёл чтобы Вы понимали в каком направлении движутся мысли наших инженеров. В любом случае я очень далёк от аппаратной части.
> Ваш компилятор имеет road map?
Не такой дальносрочный как процессор, но да имеет. К сожалению не могу в сети найти презентацию с отчётом за 2015 год и планом на 2016. Но вообще в сети довольно много материалов про наш компилятор - нужно только поискать )
> Он будет распараллеливать по ядрам статически
Да.
> или динамически на виртуальной машыне потока данных (что-то как в TERAFLUX, TALM/Trebuchet, BMDFM, etc.)?
Эммм, Вы сравниваете компилятор с TERAFLUX, например? А ничего что это система из кучи слоёв абстракций, которая рассчитана на системы, которые "скорей всего" появятся в будущем? Т.е. какой-то сферический конь в вакууме. А уж откуда в Сишном компиляторе VM взялось - вообще непонятно.
А вообще я бы предложил завязывать с обсуждением общефилософских вопросов в посте про Hello world :)
Очередная вершина Эльбруса. Виртуозам ПиАра посвящается
Удалитьhttp://worldcrisis.ru/crisis/2169645
> Очередная вершина Эльбруса. Виртуозам ПиАра посвящается
УдалитьСпасибо, поржал. Обожаю пропагандистские статьи, пишущиеся людьми, не разбирающимися в предмете :)
Почему VLIW это плохо.
Удалитьhttp://thesz.livejournal.com/1448450.html
Теперь не просто про VLIW вообще, а про новый планируемый Эльбрус конкретно.
http://thesz.livejournal.com/1448727.html
И почему меня все пытаются убедить что Эльбрус - это плохо или что его вообще не существует о_О
Удалить> Почему VLIW это плохо.
> http://thesz.livejournal.com/1448450.html
Сложности в создании VLIW систем обозначены, ок, во многом вполне справедливо. Но вот дальше начинается треш, а именно необоснованные предположения касательно производительности, подсчёты на пальцах и вообще цифры с потолка (это я про плотность кода).
> Теперь не просто про VLIW вообще, а про новый
> планируемый Эльбрус конкретно.
> http://thesz.livejournal.com/1448727.html
Ну как будут серийные образцы 8С - так и посмотрим. Нет смысла гадать на кофейной гуще.
А вообще мне всё это читать очень забавно потому что пишут люди, которые не в теме. Не, конкретно товарищ thesz вроде довольно умный и даже в смежной области работает, но это всё теоретические рассуждения от человека, который не измерял реальную производительность Эльбрусов и не анализировал результаты.
Лично у меня нет оснований считать что VLIW системы - тупиковый путь развития, даже на десктопах. Ну т.е. да, на кривом софте оно будет работать медленнее но при повышении частоты даже этого не будет заметно пользователю. А перспектив у VLIW систем вообще, и у Эльбруса в частности (там из киллер-фич не только VLIW если что) предостаточно.
Скажите, а можно объяснить постоянные теоретические рассуждения тем, что проект Эльбруса представлен как теоретический проект в основном в виде каких-то ссылок на результаты, полученные где-то. А возможно ли такое, что если Эльбрус станет доступен практически, то количество теоретических рассуждений будет уменьшаться?
УдалитьЕсли Эльбрус изначально задуман, как проект для военных и для "узкого круга ограниченных людей", то зачем тогда о нем писать в технических новостях общего назначения?
Конкретной ссылке в интернете доверять нельзя, оценку делать можно статистикой. Почему 80% ссылок на Эльбрус негативные, а только 20% - позитивные. В чем тут может быть проблема?
И еще. А как можно утверждать, что статически можно сделать столько же, сколько и динамически? Вы действительно так считаете?
> Скажите, а можно объяснить постоянные теоретические рассуждения тем, что проект Эльбруса представлен как теоретический проект в основном в виде каких-то ссылок на результаты, полученные где-то.
УдалитьНельзя. Как минимум потому что утверждение "что проект Эльбруса представлен как теоретический проект" неверно и даже противоречит последней части фразы, т.к. теоретический проект не может давать непосредственно практических результатов. То что о нём мало информации в сети и мало у кого данная машина есть в наличие - да, хотя за последние пол года было несколько интересных заметок от людей, получивших данные машины в свои руки.
> А возможно ли такое, что если Эльбрус станет доступен практически, то количество теоретических рассуждений будет уменьшаться?
Он вполне доступен практически уже гораздо более широкому кругу лиц чем, скажем, лет 5 назад. Пока это приводит к появлению редких, но вполне адекватных статей от пользователей. Тем не менее мне что-то подсказывает что при попадании машины к обычным пользователям количество даже не просто теоретических а хотя бы минимально технических грамотных рассуждений будет составлять примерно нулевой процент из общего потока информации.
> Если Эльбрус изначально задуман, как проект для военных и для "узкого круга ограниченных людей", то зачем тогда о нем писать в технических новостях общего назначения?
Откуда взялось утверждение что он изначально задуман для военных?
> Конкретной ссылке в интернете доверять нельзя, оценку делать можно статистикой. Почему 80% ссылок на Эльбрус негативные, а только 20% - позитивные. В чем тут может быть проблема?
Хороший вопрос. Я думаю он из области психологии, но для начала можно уточнить как Вы получили эти цифры?
> И еще. А как можно утверждать, что статически можно сделать столько же, сколько и динамически? Вы действительно так считаете?
А можно процитировать высказывание, на основе которого Вы сделали данный вывод?
PS. Друзья, это статья про ассемблер, причём не только Эльбрусовский. Вопросы, не относящиеся к теме мешают людям, которые хотят почитать обсуждение данного примера ассемблера. Пожалуйста, найдите другой пост для вопросов общего характера про Эльбрус.
Да, есть много других политических блогов, на которых ничего не узнаешь. Пишу тут, потому что хочется узнать из первых рук мнение профи, кто пишет на ассемблере под эльбрус. Давайте, чтобы было все в порядке, я буду спрашивать общий вопрос и сразу что-то по ассемблеру. (Если так плохо, то напишите, чтобы я больше не писал вообще, и я больше писать не буду).
УдалитьОднажды к Путину на передачу Ярмольник привел Шевчука из ДДТ. Шевчук спросил Путина, почему все так плохо. В ответ получил, что не надо все уравнивать, были отдельные частные хорошие случаи, про которые не надо забывать, и начал их перечислять в качестве ответа. У Вас ответы очень похожие - на вопрос о тенденции, Вы отвечаете перечислениями частных случаев, которые не меняют этой тенденции. (80% случаев - это тенденция :)
Вот я взял у себя для сравнения одну машину с эльбрусом и одну с Итаниумом (обе VLIW).
debian|e2k $ lcc -v
lcc:1.19.11:Dec-13-2014:e2k-2c+-linux
Thread model: posix
gcc version 4.4.0 compatible.
linux|ia64 $ gcc -v
Thread model: posix
gcc version 5.3.0 (GCC)
Написал на C "Hello, world":
#include
int main(void){
printf("Hello, world.\n");
return 0;
}
Получил ассемблерный код для обеих машин. Как можно посчитать, где плотность кода лучше?
Когда я компилирую большие проекты, то код под IA-64 всегда раза в 2 больше, чем под x86-64, а код под e2k еще в 1.2 больше, чем под IA-64. Если полученный бинарный файл заархивировать zip-ом, то его размер говорит о плотности кода (с учетом того, что заархивированный файл более-менее отражает информационную энтропию)?
debian|e2k $ lcc -S tt.c
debian|e2k $ cat tt.s
.file "tt.c"
.section ".text"
.global $main
$main:
.ignore ld_st_style
.ignore strict_delay
$#__local_label_in_main__0:
{
disp %ctpr1, $printf
setwd wsz = 0x8, nfx = 0x1
setbn rsz = 0x3, rbs = 0x4, rcur = 0x0
getsp,0 _f32s,_lts1 0xfffffff0, %dr2
}
addd,0,sm 0x0, [ _lts0 $.LC.00000000 ], %db[0]
{
nop 2
std,2,sm 0x0, %dr2, %db[0]
}
{
ipd 3
call %ctpr1, wbs = 0x4
}
{
nop 5
return %ctpr3
adds,0,sm 0x0, 0x0, %r0
}
{
ct %ctpr3
ipd 3
}
.size $main, . - $main
.type $main, @function
.weak $elbrus_compiler_v1.19.11_Dec_13_2014
.set $elbrus_compiler_v1.19.11_Dec_13_2014, 0
.section ".rodata"
.local $.LC.00000000
.type $.LC.00000000, @object
.size $.LC.00000000, 0xf
.align 1
$.LC.00000000:
.ascii "Hello, world.\n\000"
linux|ia64 $ gcc -S tt.c
linux|ia64 $ cat tt.s
.file "tt.c"
.pred.safe_across_calls p1-p5,p16-p63
.section .rodata
.align 8
.LC0:
stringz "Hello, world."
.text
.align 16
.global main#
.type main#, @function
.proc main#
main:
.prologue 14, 32
.save ar.pfs, r33
alloc r33 = ar.pfs, 0, 4, 1, 0
.vframe r34
mov r34 = r12
.save rp, r32
mov r32 = b0
mov r35 = r1
.body
addl r36 = @ltoffx(.LC0), r1
;;
ld8.mov r36 = [r36], .LC0
br.call.sptk.many b0 = puts#
mov r1 = r35
mov r14 = r0
;;
mov r8 = r14
mov ar.pfs = r33
mov b0 = r32
.restore sp
mov r12 = r34
br.ret.sptk.many b0
;;
.endp main#
.ident "GCC: (GNU) 5.3.0"
Ваш комментарий меня крайне улыбнул :) Но про политику лучше не надо ;) Давайте на Ваш вопрос про информационный фон я отвечу чуть попозже и, пожалуй, создам для этого отдельный пост, а сейчас отвечу на техническую часть.
Удалить> Получил ассемблерный код для обеих машин. Как можно посчитать, где плотность кода лучше?
Короткий ответ - не знаю.
Длинный - немного распишу. Для начала нужно определить что понимать под "плотностью кода". Я вижу это как среднее количество реально исполненных инструкций за такт - IPC. Для x86 есть утилита perf, которая умеет данный параметр отображать (кстати очень советую на неё взглянуть людям, утверждающим что intel умеет 4 или уже 8 инструкций за такт). В Эльбрусе данная утилита есть, но конкретно эта функциональность на сколько мне известно не работает. Это связано со сложностями работы с широкой командой. Какое её состояние в Итаниуме я не знаю.
В своё время у меня была мысль написать статический анализатор ассемблера как раз для подсчёта IPC, но тут есть следующая проблема - предикатный код. Если просто считать количество инструкций в ШК, то мы не сможем различить те, которые реально исполнятся и те, для которых предикат будет ложным.
> Когда я компилирую большие проекты, то код под IA-64 всегда раза в 2 больше, чем под x86-64, а код под e2k еще в 1.2 больше, чем под IA-64.
Это нормально. cisc'овская система команд покомпактнее будет и с плотностью кода это не очень связано.
Но тут хочу сразу сделать оговорку. Вы собираете бинарник вообще без оптимизаций, а для VLIW процессоров это всё равно что интерпретатор запускать. Понятно что для данного примера это значения не имеет, но вообще когда будете делать подобные сравнения используйте хотя бы `-O3 -fwhole -ffast'.
> Если полученный бинарный файл заархивировать zip-ом, то его размер говорит о плотности кода (с учетом того, что заархивированный файл более-менее отражает информационную энтропию)?
Думаю что это крайне сомнительно. Во-первых здесь будут влиять особенности системы команд. Во-вторых возьмём такой пример: получили мы 10 копий цикла в следствие оптимизации, где одна из копий будет плотно забита, и в рантайме ходить будем преимущественно по ней. А остальные 9 получились не очень, но нужны на всякий случай. Но при архивации мы получим низкую плотность, которая не соответствует фактическому исполнению.
Кстати, 19 ветка компилятора довольно старая, все результаты замеров с её участием я буду отрицать ;)
А вот то что у Вас есть Итаниум - это очень круто, можно поиграться с машинками ) Если уж быть совсем честным, то у меня есть подозрение что под IA-64 лучше использовать интеловский компилятор, ибо я сильно сомневаюсь в качестве оптимизаций gcc (это утверждение взято с потолка и нуждается в проверке).
Спасибо. У меня на Итаниуме можно загружаться под HP-UX и компилировать родным aCC от HP. Оптимизирует он лучше чем gcc по скорости. Но и aCC, и gcc раздувают код своими unrolling-ами почти одинаково. Интеловский по-моему нужен только для native Phi (icc -mmic).
УдалитьВопрос. А что такое компиляция в защищенном режиме (lcc -mprt128). Получается 32-битный код, что ето еще такое?
Ооо, -mptr128 - это тот самый защищённый режим - одна из киллер-фич. Подробные материалы есть на сайте МЦСТ, но если в кратце, то он позволяет падать если мы сделали например выход за границу массива или работаем с не инициализированными значениями. И всё это поддерживается аппаратно.
УдалитьНапример:
$ cat t.c
#include
int main()
{
int i;
printf("%d\n", i);
return 0;
}
Видно что у нас используется не инициализированная переменная. Смотрим что будет если это запустить:
ubuntu $ gcc t.c && ./a.out
-1216794636
e2s $ lcc t.c && ./a.out
-5867840
e2s $ lcc t.c -mptr128 && ./a.out
Illegal instruction
Кстати, а откуда у Вас e2s если не секрет? И раз уж Вы так хотите пообщаться то почему от анонимного пользователя? Может у Вас тоже есть интересный бложик, я бы почитал )
Блин, блоггеровские комментарии не поддерживают тэг code. Надо что-то нормальное для комментов прикручивать...
УдалитьSorry, я неправильно спросил. А как получить 64-битовый код защищенного режима? С опцией -mprt128 он получается 32-битовым, а других опций нет?
УдалитьВообще такой режим врядли нужен. В таком режиме весь open source будет валиться. Любая alligned struct при копировании будет иметь неинициализированные байты в padding-ах. Такое тоже происходит на x86 если в llvm включить все возможные sanitizer-ы или взять valgrind.
Е2к-машина - ето же обычное дело, она же уже давным-давно выпускается серийно. :)
Sorry, никаких блогов я не веду. Если чесно, то мне вообще страшно касаться тем с засекреченной системой команд, я даже выхожу через какие-то proxy-сервера в Европе на всякий случай. Кто знает, а вдруг при диктатуре дадут команду 66 убрать всех кто слышал что-либо краем уха. :)
Как-то момент с 32-х битным кодом не заметил. А можно пример (исходник и ассемблер)? Пока не очень понятно о чём именно речь.
Удалить> Вообще такой режим врядли нужен.
Напротив, если программа в этом режиме падает, то это повод бить тревогу и искать ошибку в коде.
> В таком режиме весь open source будет валиться.
Будет валиться кривой код (ну иногда и не очень, но по большей части именно код, содержащий ошибки). Пишите письма разработчикам пакетов ;)
> Такое тоже происходит на x86 если в llvm включить все возможные sanitizer-ы или взять valgrind.
Их как раз для этого и сделали. Кстати защищённый режим Эльбруса сыграл в создании sanitaizer'ов некоторую роль ;)
> Е2к-машина - ето же обычное дело, она же уже давным-давно выпускается серийно. :)
Ура! Всегда мечтал дожить до этого момента!
> Если чесно, то мне вообще страшно касаться тем с засекреченной системой команд, я даже выхожу через какие-то proxy-сервера в Европе на всякий случай. Кто знает, а вдруг при диктатуре дадут команду 66 убрать всех кто слышал что-либо краем уха. :)
Система команд не секретна. А я всё думал кто ж меня постоянно из Германии и Франции смотрит :)
Вообще мне очень интересно откуда у Вас машина ) Т.е. Вы либо студент, либо у Вас к ней доступ через третьи руки. Я больше склоняюсь ко второму варианту.
$ uname -srvp
ОтветитьУдалитьSunOS 5.10 Generic_137137-09 sparc
$ as -V
as: SunOS 5.10 118683-10 Patch 03/14/2013
$ ed
a
.section .data
hello_str:
.ascii "Hello, world\n"
.set hello_str_len, . - hello_str
.global _start
.section .text
_start:
mov 1, %o0
set hello_str, %o1
mov hello_str_len, %o2
mov 4, %g1
ta 0x10
mov 0, %o0
mov 1, %g1
ta 0x10
.
w t1.s
268
q
$ as t1.s -o t1.o
as: "t1.s", line 1: error: quoted-string operand required
as: "t1.s", line 4: error: unknown opcode ".set"
as: "t1.s", line 4: error: statement syntax
as: "t1.s", line 8: error: quoted-string operand required
as: "t1.s", line 11: error: location counter not on word boundary
$ uname -srvp
УдалитьSunOS 5.9 Generic_112233-11 sparc
$ as --version
GNU assembler 2.11.2
Copyright 2001 Free Software Foundation, Inc.
This program is free software; you may redistribute it under the terms of
the GNU General Public License. This program has absolutely no warranty.
This assembler was configured for a target of `sparc-sun-solaris2.8'.
$ as t.s -o t.o
$ ld t.o -o a.out
$ ./a.out
Illegal Instruction (core dumped)
Рассмотрим проблему, возникшую у Вас. Видно, что Вы используете as от Sun, а я использую ассемблер GNU. Их синтаксис может различаться (что мы и наблюдаем).
Теперь о проблеме, возникшей у меня с падением приложения. Тут по-видимому в SunOS используются другие номера системных вызовов, и данная программа делает не очень понятно что (в моих примерах везде использовался Linux).
Я пока не буду смотреть как это делать под SunOS просто потому что каждый дополнительный вариант программы занимает довольно много времени, а под SunOS ещё и документации значительно меньше.
Но если Вы портируете этот пример и напишете как это сделать, то будет очень круто ;)
$ ed
Удалитьa
.section ".text"
.global _start
_start:
mov 4,%g1 ! 4 is SYS_write
mov 1,%o0 ! 1 is stdout
set .msg,%o1 ! pointer to buffer
mov (.msgend-.msg),%o2 ! length
ta 8
mov 1,%g1 ! 1 is SYS_exit
clr %o0 ! return status is 0
ta 8
.msg:
.ascii "Hello world!\n"
.msgend:
.
w t1.s
283
q
$ as t1.s -o t1.o && ld t1.o && ./a.out
Hello world!
Спасибо, добавил к посту
УдалитьПриятно посмотреть, что Эльбрус выполняет сразу столько операций сложений. А почему в SPARC и x86 эти операции совсем не нужны?
УдалитьИнтересно, а что напечатает Эльбрус после того как его компилятор проанализирует все зависимости данных?
Удалитьint a;
a=1;
a=a+(a=10);
printf("a=%d\n", a);
a=1;
a=a*2+(a=10);
printf("a=%d\n", a);
printf("a=%d, a=%d\n", a=2, a*2);
> Интересно, а что напечатает Эльбрус после того как его компилятор проанализирует все зависимости данных?
УдалитьВы же понимаете, что программа содержит UB и результат может быть абсолютно произвольным?
> Приятно посмотреть, что Эльбрус выполняет сразу столько операций сложений. А почему в SPARC и x86 эти операции совсем не нужны?
УдалитьПотому что в Эльбрусовской системе команд отсутствует инструкция MOV (как и в Спарковской, между прочим). Т.е. здесь addd выполняет роль MOV, только и всего.
А прокомментируйте пожалуйста вот это:
ОтветитьУдалить> Каким образом, в рантайме, «Эльбрус» будет собирать потоки из различных, не взаимосвязанных, процессов ?
> > Не знаю, а как сейчас работает?
> А сейчас оно не работает, на каждый процесс свой контекст.
Что здесь имеется в виду? Что в ОС или скажем в JVM на эльбрусе нельзя обеспечить взаимодействие между одновременно работающими приложениями (как я понимаю) и на сколько это соответствует действительности?
Вы вырвали какой-то кусок обсуждения из непойми откуда (не, я знаю что с ЛОРа, но всё же), и хотите у меня узнать что имел ввиду его автор? :)
УдалитьТак вот: не знаю, спросите у автора. Я не очень понял про какое взаимодействие идёт речь. Если зададите конкретный вопрос - постараюсь ответить (про JVM - вообще мало что могу рассказать, но недавно на явовской конференции доклад был про портирование).
Современные технологии не стоят на месте и вот уже в данный момент в нашем ежедневном мире крепко закрепилось это понятие как 3D печать. Вообще сама 3D печать была придумана фирмой Charles Hull и была еще в 1984г. Сейчас же разработка 3D печати стала так известной и обширной трехмерная печать, что исполненье задачи по творению какой-то составной либо модели может быть реально воплощена в жизнь не только на крупном предприятии, но и у вас дома. Сама технология 3D печати – это последовательное выполнение действий, коие приведут к творенью изделия
ОтветитьУдалить