четверг, 12 мая 2016 г.

Пишем "Hello, world" на ассемблере

Так сложилось, что я совсем не знаю ассемблера. Даже несмотря на то, что я разрабатываю компиляторы, на уровень близкий к аппаратуре я почти не спускаюсь. Была пара попыток его выучить, но я просто не находил подходящего материала. В итоге решил что если его нет, то нужно написать самому. В этой заметке я планирую показать как написать простой Hello world на ассемблере.

В данной статье я преследую несколько целей:
  • Изучить основы работы с ассемблером
  • Сравнить ассемблеры процессоров различных архитектур и, как следствие, показать разные аппаратные особенности
  • Написать материал по которому новички далее смогут самостоятельно продолжить изучение ассемблера
Содержание:
  1. Введение
  2. amd64
  3. sparc v9
  4. Эльбрус
  5. Послесловие
  6. Источники

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 %hi(hello_str), %o2
or %o2, %lo(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] Микропроцессоры и вычислительные комплексы семейства «Эльбрус»

38 комментариев:

  1. Анонимный16 мая 2016 г., 7:30

    Круто выглядит, синтаксис практически явушный.

    > нужно ещё немного рассказать про механизм работы переходов в Эльбрусе. В процессорах Эльбрус вызов функции является дорогим удовольствием
    А в чем проблема то, ну описали в начале процедуру/функцию, ну вызвали - ровно точно такой же подход разве не в любом (практически) современном языке?

    ОтветитьУдалить
    Ответы
    1. Мы никакую процедуру нигде не описывали. И ассемблер всё же не совсем обычный язык. Суть в том что для того чтобы переключить исполнение на другую функцию нужны определённые затраты. В случае с Эльбрусом, процессор не умеет предсказывать куда мы заранее пойдём, поэтому мы готовим переходы заранее (в данном случае инструкцией sdisp). Т.о. получается что сам sdisp позволит процессору подгрузить заранее инструкции на исполнение, а call вообще не будет затрачивать времени на переход. Если посмотреть в ассемблер intel или sparc, то там такой инструкции нет.

      Удалить
  2. Анонимный19 мая 2016 г., 22:05

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

    ОтветитьУдалить
    Ответы
    1. Получение удалённого логина - штука довольно неофициальная. Можете попробовать написать на адрес mcst@mcst.ru. Сразу дам совет - представьтесь, напишите какие тесты хотите запускать, куда пойдут результаты. Тогда Вам может быть даже ответят.

      Удалить
  3. Анонимный20 мая 2016 г., 9:08

    Спасибо. А можно где-то получить cross toolchain для эльбруса или qemu image эльбруса?
    Очень похоже на сюжет фильма Terminator 3, где герои приходят к выводу, что core of Skynet does not exist at all. :)

    ОтветитьУдалить
    Ответы
    1. Сейчас нет, но очень может быть что вскоре ситуация поменяется.

      А Вы, простите, в чём именно сомневаетесь? В существовании кросового компилятора, существовании Эльбрус ОС или существовании процессора Эльбрус? )))

      Удалить
  4. Анонимный20 мая 2016 г., 10:14

    Начал писать на mcst@mcst.ru, а потом подумал и остановился. Эльбрус поставлен на защиту кумовского капитализма от всего остального мира. Не дай Бог китайци на фабрике засунут закладку в эльбрус, тогда кумовской капитализм отрежет головы даже тем, кто знал как написать "hello world" на асме. :)

    ОтветитьУдалить
    Ответы
    1. Не очень понял что Вы имели ввиду, но могу сказать что во-первых Эльбрусы не производятся в Китае, а во-вторых я бы очень хотел посмотреть на процесс добавления закладки в процессор на этапе напыления транзисторов )

      Удалить
  5. Анонимный20 мая 2016 г., 13:38

    Возможно ето все и существует, но не в состоянии military quality.

    Процесс закладывания закладки может происходить приблизительно так: платят большие деньги кому-то, кто на каком-то этапе подготовки layout-а добавляет простенький MUX подключенный к шине команд и реагируюший на VLIW="010101...010101". По приходе такого длинного слова MUX отрубает что-нибудь. Человек, который ето сделал пропадает с панамским паспортом в кармане. :)

    Идея эльбруса такая: без формальных доказательств предположили, что multi-issue superscalar не сможет выполнять больше 6 инструкций параллельно, взяли и выбросили из процессора ту часть, которая пытается динамически накормить все ALU - ломать не строить; потом начали себя расхваливать, какие мы молодци, пускай все себе делают сложные процессоры, а мы из нашего процессора все выбросили - наш компилятор и двоичный транслятор, получающий доступ к состоянию процессора, сделает всю работу еще лучше (опять без формальных доказательств); потом начали себя расхваливать и за ето тоже. А компилятор не смог сделать ето лучше, он делает хуже и не потому, что компилятор плохой, а потому, что есть принципиальные ограничения, которые не позволят компилятору сделать ето лучше. На динамических языках программирования и динамических задачах (где много ветвлений, а не тупое перемалывание массива чисел) он бессилен. Да есть специальный узкий круг задач, когда компилятор может запаковать VLIW полностью и может быть добиться возможного одновременного выполнения 23 инструкций за такт. Но тогда ето всего лишь специализированный процессор для такого узкого круга задач, а не универсальный как изначально было claimed. И что теперь делать? За потраченные деньги могут надавать по голове. Надо все скрывать, надо прикрываться секретностью и продолжать по Райкину "запускать дурочку" дальше. :) Очень хотелось бы, чтобы все ето было не так...

    ОтветитьУдалить
    Ответы
    1. Довольно странные допущения, причём вообще все. Если Вас интересуют какие-то реальные тесты, то вот отличная серия статей с хабра про тестирование Эльбрусов и потом наши комментарии, которые мы дали тем ребятам после публикации их результатов.

      Если рассматривать вариант с подкупом и встраиванием MUX, то это нужно будет подкупать кого-нибудь и сотрудников МЦСТ, что вообще мягко говоря сомнительно :) А за то что их поставят на фабрике я бы не особо беспокоился.

      Я не сказал бы что VLIW бессилен на динамических языках, но да, определённые проблемы есть. Не знаю, получится ли сделать их работу быстрее чем на x86, но сделать их скорость сопоставимой можно.

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

      Из практики могу сказать что под Эльбрусом вполне себе крутится линукс под xfce, где я работаю в QtCreator. Так что думаю такие предположения несколько беспочвенны.

      Ну и да, кто кому и за какие деньги по голове надаёт? МЦСТ - коммерческая фирма, выполняющая определённые заказы. Если бы кого-то что-то не устраивало или появился бы кто-то получше, заказывали бы у него. Тут всё прозрачно вроде как.

      Удалить
  6. Анонимный20 мая 2016 г., 22:59

    Мы все сидим под 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 тоже там где надо. :)

    ОтветитьУдалить
    Ответы
    1. Анонимный22 мая 2016 г., 19:23

      Идея пар-ядер big.LITTLE это от бедности, а не от изобретательности.
      То что канает для карманных вычеслителей уже не канает для больших и мощных CPU, тут можно только переизобретать P/S/C-State's

      Удалить
    2. > Динамически можно делать больше, чем статически.

      Нет. Ровно столько же.

      > Даже если прятать if-ы в предикатные инструкции, то что делать, если есть много вложенных if-ов и т.д. и т.п...

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

      Вообще мы имеем такую ситуацию с языками программирования и софтом отчасти потому что в своё время IA64 не смог победить. Но код часто можно переписать по-человечески. Можно и не переписывать, просто работать будет чуть медленнее.

      > Скажите как эксперт, вращающийся в Бабаяновских кругах

      Боюсь, вы немного отстали от жизни. Бабаян ушёл в 2004 и не возвращался. Уже выросло несколько поколений специалистов, не имеющих к нему никакого отношения. Я - где-то третье или четвёртое поколение. Я даже не берусь сказать какой процент его работы находится в современных Эльбрусах.

      Касательно пар-ядер, мне о таких исследованиях внутри МЦСТ ничего не известно. Идея, конечно, интересная и даже заманчивая, но надо понимать что приведёт к куче других проблем, поэтому не факт что будет лучше. Это только на пальцах всё легко и просто :)

      Вообще если интересует что у нас планируют выпускать, то в сети есть презенташки с road map'ами до 2021 года. Там идёт движение в сторону увеличения количества ядер на процессоре. Пока из того что известно - планируется Эльбрус-32С с техпроцессом 10нм в районе 20-ого года.

      Удалить
    3. Анонимный23 мая 2016 г., 22:54

      "Нет. Ровно столько же." - не может быть такого. Это же противоречит вашему "IA64 не смог победить".

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

      Бабаян - это имя нарицательное. Например, страна может еще долго оставаться ленинской даже после ухода Ленина. Как за 10 лет может смениться 3 поколения? :)

      "движение в сторону увеличения количества ядер" не имеет ничего общего с улучшениями заполнения VLIW. Ваш компилятор имеет road map? Он будет распараллеливать по ядрам статически или динамически на виртуальной машыне потока данных (что-то как в TERAFLUX, TALM/Trebuchet, BMDFM, etc.)?

      Удалить
    4. > "Нет. Ровно столько же." - не может быть такого. Это же противоречит вашему "IA64 не смог победить".

      Не вижу противоречия. А под динамикой Вы вообще что понимаете? Out-Of-Order или динамические языки? В обоих случаях множество решаемых задач одинаково.

      > Вложенные if-ы будет трудно запретить в демократическом обществе...

      Если даже goto до конца не добили... Но кому нужна скорость - быстро от них откажутся.

      > Бабаян - это имя нарицательное.

      Ну оно как бы должно что-то означать. Я не понимаю что под этим подразумевается и причём он вообще здесь )

      > "движение в сторону увеличения количества ядер" не имеет ничего общего с улучшениями заполнения VLIW.

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

      > Ваш компилятор имеет road map?

      Не такой дальносрочный как процессор, но да имеет. К сожалению не могу в сети найти презентацию с отчётом за 2015 год и планом на 2016. Но вообще в сети довольно много материалов про наш компилятор - нужно только поискать )

      > Он будет распараллеливать по ядрам статически

      Да.

      > или динамически на виртуальной машыне потока данных (что-то как в TERAFLUX, TALM/Trebuchet, BMDFM, etc.)?

      Эммм, Вы сравниваете компилятор с TERAFLUX, например? А ничего что это система из кучи слоёв абстракций, которая рассчитана на системы, которые "скорей всего" появятся в будущем? Т.е. какой-то сферический конь в вакууме. А уж откуда в Сишном компиляторе VM взялось - вообще непонятно.

      А вообще я бы предложил завязывать с обсуждением общефилософских вопросов в посте про Hello world :)

      Удалить
    5. Анонимный11 июня 2016 г., 0:19

      Очередная вершина Эльбруса. Виртуозам ПиАра посвящается
      http://worldcrisis.ru/crisis/2169645

      Удалить
    6. > Очередная вершина Эльбруса. Виртуозам ПиАра посвящается

      Спасибо, поржал. Обожаю пропагандистские статьи, пишущиеся людьми, не разбирающимися в предмете :)

      Удалить
    7. Анонимный13 июля 2016 г., 23:54

      Почему VLIW это плохо.
      http://thesz.livejournal.com/1448450.html

      Теперь не просто про VLIW вообще, а про новый планируемый Эльбрус конкретно.
      http://thesz.livejournal.com/1448727.html

      Удалить
    8. И почему меня все пытаются убедить что Эльбрус - это плохо или что его вообще не существует о_О

      > Почему VLIW это плохо.
      > http://thesz.livejournal.com/1448450.html

      Сложности в создании VLIW систем обозначены, ок, во многом вполне справедливо. Но вот дальше начинается треш, а именно необоснованные предположения касательно производительности, подсчёты на пальцах и вообще цифры с потолка (это я про плотность кода).

      > Теперь не просто про VLIW вообще, а про новый
      > планируемый Эльбрус конкретно.
      > http://thesz.livejournal.com/1448727.html

      Ну как будут серийные образцы 8С - так и посмотрим. Нет смысла гадать на кофейной гуще.

      А вообще мне всё это читать очень забавно потому что пишут люди, которые не в теме. Не, конкретно товарищ thesz вроде довольно умный и даже в смежной области работает, но это всё теоретические рассуждения от человека, который не измерял реальную производительность Эльбрусов и не анализировал результаты.

      Лично у меня нет оснований считать что VLIW системы - тупиковый путь развития, даже на десктопах. Ну т.е. да, на кривом софте оно будет работать медленнее но при повышении частоты даже этого не будет заметно пользователю. А перспектив у VLIW систем вообще, и у Эльбруса в частности (там из киллер-фич не только VLIW если что) предостаточно.

      Удалить
    9. Анонимный14 июля 2016 г., 13:28

      Скажите, а можно объяснить постоянные теоретические рассуждения тем, что проект Эльбруса представлен как теоретический проект в основном в виде каких-то ссылок на результаты, полученные где-то. А возможно ли такое, что если Эльбрус станет доступен практически, то количество теоретических рассуждений будет уменьшаться?

      Если Эльбрус изначально задуман, как проект для военных и для "узкого круга ограниченных людей", то зачем тогда о нем писать в технических новостях общего назначения?

      Конкретной ссылке в интернете доверять нельзя, оценку делать можно статистикой. Почему 80% ссылок на Эльбрус негативные, а только 20% - позитивные. В чем тут может быть проблема?

      И еще. А как можно утверждать, что статически можно сделать столько же, сколько и динамически? Вы действительно так считаете?

      Удалить
    10. > Скажите, а можно объяснить постоянные теоретические рассуждения тем, что проект Эльбруса представлен как теоретический проект в основном в виде каких-то ссылок на результаты, полученные где-то.

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

      > А возможно ли такое, что если Эльбрус станет доступен практически, то количество теоретических рассуждений будет уменьшаться?

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

      > Если Эльбрус изначально задуман, как проект для военных и для "узкого круга ограниченных людей", то зачем тогда о нем писать в технических новостях общего назначения?

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

      > Конкретной ссылке в интернете доверять нельзя, оценку делать можно статистикой. Почему 80% ссылок на Эльбрус негативные, а только 20% - позитивные. В чем тут может быть проблема?

      Хороший вопрос. Я думаю он из области психологии, но для начала можно уточнить как Вы получили эти цифры?

      > И еще. А как можно утверждать, что статически можно сделать столько же, сколько и динамически? Вы действительно так считаете?

      А можно процитировать высказывание, на основе которого Вы сделали данный вывод?

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

      Удалить
    11. Анонимный14 июля 2016 г., 17:14

      Да, есть много других политических блогов, на которых ничего не узнаешь. Пишу тут, потому что хочется узнать из первых рук мнение профи, кто пишет на ассемблере под эльбрус. Давайте, чтобы было все в порядке, я буду спрашивать общий вопрос и сразу что-то по ассемблеру. (Если так плохо, то напишите, чтобы я больше не писал вообще, и я больше писать не буду).
      Однажды к Путину на передачу Ярмольник привел Шевчука из ДДТ. Шевчук спросил Путина, почему все так плохо. В ответ получил, что не надо все уравнивать, были отдельные частные хорошие случаи, про которые не надо забывать, и начал их перечислять в качестве ответа. У Вас ответы очень похожие - на вопрос о тенденции, Вы отвечаете перечислениями частных случаев, которые не меняют этой тенденции. (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"

      Удалить
    12. Ваш комментарий меня крайне улыбнул :) Но про политику лучше не надо ;) Давайте на Ваш вопрос про информационный фон я отвечу чуть попозже и, пожалуй, создам для этого отдельный пост, а сейчас отвечу на техническую часть.

      > Получил ассемблерный код для обеих машин. Как можно посчитать, где плотность кода лучше?

      Короткий ответ - не знаю.

      Длинный - немного распишу. Для начала нужно определить что понимать под "плотностью кода". Я вижу это как среднее количество реально исполненных инструкций за такт - 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 (это утверждение взято с потолка и нуждается в проверке).

      Удалить
    13. Анонимный14 июля 2016 г., 23:53

      Спасибо. У меня на Итаниуме можно загружаться под HP-UX и компилировать родным aCC от HP. Оптимизирует он лучше чем gcc по скорости. Но и aCC, и gcc раздувают код своими unrolling-ами почти одинаково. Интеловский по-моему нужен только для native Phi (icc -mmic).
      Вопрос. А что такое компиляция в защищенном режиме (lcc -mprt128). Получается 32-битный код, что ето еще такое?

      Удалить
    14. Ооо, -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 если не секрет? И раз уж Вы так хотите пообщаться то почему от анонимного пользователя? Может у Вас тоже есть интересный бложик, я бы почитал )

      Удалить
    15. Блин, блоггеровские комментарии не поддерживают тэг code. Надо что-то нормальное для комментов прикручивать...

      Удалить
    16. Анонимный15 июля 2016 г., 20:18

      Sorry, я неправильно спросил. А как получить 64-битовый код защищенного режима? С опцией -mprt128 он получается 32-битовым, а других опций нет?

      Вообще такой режим врядли нужен. В таком режиме весь open source будет валиться. Любая alligned struct при копировании будет иметь неинициализированные байты в padding-ах. Такое тоже происходит на x86 если в llvm включить все возможные sanitizer-ы или взять valgrind.

      Е2к-машина - ето же обычное дело, она же уже давным-давно выпускается серийно. :)

      Sorry, никаких блогов я не веду. Если чесно, то мне вообще страшно касаться тем с засекреченной системой команд, я даже выхожу через какие-то proxy-сервера в Европе на всякий случай. Кто знает, а вдруг при диктатуре дадут команду 66 убрать всех кто слышал что-либо краем уха. :)

      Удалить
    17. Как-то момент с 32-х битным кодом не заметил. А можно пример (исходник и ассемблер)? Пока не очень понятно о чём именно речь.

      > Вообще такой режим врядли нужен.

      Напротив, если программа в этом режиме падает, то это повод бить тревогу и искать ошибку в коде.

      > В таком режиме весь open source будет валиться.

      Будет валиться кривой код (ну иногда и не очень, но по большей части именно код, содержащий ошибки). Пишите письма разработчикам пакетов ;)

      > Такое тоже происходит на x86 если в llvm включить все возможные sanitizer-ы или взять valgrind.

      Их как раз для этого и сделали. Кстати защищённый режим Эльбруса сыграл в создании sanitaizer'ов некоторую роль ;)

      > Е2к-машина - ето же обычное дело, она же уже давным-давно выпускается серийно. :)

      Ура! Всегда мечтал дожить до этого момента!

      > Если чесно, то мне вообще страшно касаться тем с засекреченной системой команд, я даже выхожу через какие-то proxy-сервера в Европе на всякий случай. Кто знает, а вдруг при диктатуре дадут команду 66 убрать всех кто слышал что-либо краем уха. :)

      Система команд не секретна. А я всё думал кто ж меня постоянно из Германии и Франции смотрит :)

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

      Удалить
  7. Анонимный23 мая 2016 г., 12:37

    $ 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

    ОтветитьУдалить
    Ответы
    1. $ 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 ещё и документации значительно меньше.

      Но если Вы портируете этот пример и напишете как это сделать, то будет очень круто ;)

      Удалить
    2. Анонимный24 мая 2016 г., 12:05

      $ 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!

      Удалить
    3. Спасибо, добавил к посту

      Удалить
    4. Анонимный25 мая 2016 г., 11:52

      Приятно посмотреть, что Эльбрус выполняет сразу столько операций сложений. А почему в SPARC и x86 эти операции совсем не нужны?

      Удалить
    5. Анонимный25 мая 2016 г., 12:49

      Интересно, а что напечатает Эльбрус после того как его компилятор проанализирует все зависимости данных?
      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);

      Удалить
    6. > Интересно, а что напечатает Эльбрус после того как его компилятор проанализирует все зависимости данных?

      Вы же понимаете, что программа содержит UB и результат может быть абсолютно произвольным?

      Удалить
    7. > Приятно посмотреть, что Эльбрус выполняет сразу столько операций сложений. А почему в SPARC и x86 эти операции совсем не нужны?

      Потому что в Эльбрусовской системе команд отсутствует инструкция MOV (как и в Спарковской, между прочим). Т.е. здесь addd выполняет роль MOV, только и всего.

      Удалить
  8. Анонимный25 мая 2016 г., 14:37

    А прокомментируйте пожалуйста вот это:

    > Каким образом, в рантайме, «Эльбрус» будет собирать потоки из различных, не взаимосвязанных, процессов ?
    > > Не знаю, а как сейчас работает?
    > А сейчас оно не работает, на каждый процесс свой контекст.

    Что здесь имеется в виду? Что в ОС или скажем в JVM на эльбрусе нельзя обеспечить взаимодействие между одновременно работающими приложениями (как я понимаю) и на сколько это соответствует действительности?

    ОтветитьУдалить
    Ответы
    1. Вы вырвали какой-то кусок обсуждения из непойми откуда (не, я знаю что с ЛОРа, но всё же), и хотите у меня узнать что имел ввиду его автор? :)

      Так вот: не знаю, спросите у автора. Я не очень понял про какое взаимодействие идёт речь. Если зададите конкретный вопрос - постараюсь ответить (про JVM - вообще мало что могу рассказать, но недавно на явовской конференции доклад был про портирование).

      Удалить