• Исходные коды оригинальной Xbox утекли в онлайн
    0
    Про NT 3.5 друг ссылается на boards.4channel.org/g/thread/75941397/nt-350-source-code.
  • Реверс-инжиниринг неизвестного процессора по единственной программе
    +2
    Потому что именно при размере 20 проявляется заметная глазу структура на гифке из статьи.
    При размере строки 6:
    ...
    (1800) 110111
    (1806) 100001
    (1812) 001011
    (1818) 110000
    (1824) 011000
    (1830) 010010
    (1836) 111100
    (1842) 000110
    (1848) 001001
    (1856) 110001
    ...

    Какая-то мешанина нулей и единиц.
    При размере строки 20:
    ...
    (1800) 11011110000100101111
    (1820) 00000110000100101111
    (1840) 00000110001001110001
    (1860) 00000110000100101111
    (1880) 00000110000100101111
    (1900) 00000110000100101111
    (1920) 00000110001010110011
    (1940) 00000110000100101111
    (1960) 00000110000100101111
    (1980) 00000110000100101111
    ...

    Уже явно какая-то регулярная структура.
  • Реверс-инжиниринг неизвестного процессора по единственной программе
    0
    После окончания CTF организаторы выложили исходники: github.com/koriakin/cpuadventure. Да, эмулятор.
  • Этот ваш хаскель (не) только для факториалов и годен
    +5
    Кроме того, наверняка есть более эффективные алгоритмы решения этой задачи, но представленный результат непродолжительных раздумий тоже сойдёт для этого небольшого воскресного приключения.

    Конечно, есть. Сумма делителей мультипликативна в смысле теории чисел: если n=ab и a,b взаимно просты, то сумма делителей n равна произведению сумм делителей для a и b. Так что достаточно посчитать суммы для степеней простых и перемножить:
        std::vector<int64_t> arr;
        arr.resize(n + 1, 1);
    
        int64_t p;
        for (p = 2; p * p <= n; p++) if (arr[p] == 1) {
            int64_t ppow = p;
            int64_t sum = 1;
            do {
                sum += ppow;
                int64_t q, residue = 1;
                for (int64_t q = ppow; q <= n; q += ppow, residue++)
                    if (residue == p)
                        residue = 0;
                    else
                        arr[q] *= sum;
                ppow *= p; // no overflow here if n**(3/2) < 2**63; we get std::bad_alloc long before this otherwise
            } while (ppow <= n);
        }
        for (; p <= n; p++) if (arr[p] == 1) {
            for (int64_t q = p; q <= n; q += p)
                arr[q] *= 1 + p;
        }
        std::cout << arr.back() << std::endl;
    

    Получается быстрее в 2-3 раза.
  • Оптимизация сравнения this с нулевым указателем в gcc 6.1
    0
    Просто перехватывать SEH-исключения на С и C++ можно было ещё с момента появления этих самых SEH-исключений в Windows 95, через синтаксис __try / __except / __finally.
  • Оптимизация сравнения this с нулевым указателем в gcc 6.1
    +1
    Какие ещё «амбиции компиляторщиков»? В VC++ есть преобразование SEH -> C++ exception: _set_se_translator.
    В Word просто пошли по другому пути: не делать сложных манипуляций при access violation — тем более, что если AV вообще произошло, то в данных вполне может быть каша, а получить документ с кашей намного неприятнее, чем потерять последний сеанс работы — а периодически делать временную копию, пока данные гарантированно целы, при AV вылетать, а после перезапуска предлагать её восстановить.
  • Оптимизация сравнения this с нулевым указателем в gcc 6.1
    +5
    Отдельного внимания заслуживает использование регистра rdi. Вызывающий код обнуляет edi – половину rdi, а вызываемый код ДОВОЛЬНО НЕОЖИДАННО – использует наполовину обнуленный rdi.

    Инструкция xor edi,edi в 64-битном режиме обнуляет весь rdi, так что нет никакого «наполовину обнулённого» регистра.
    В проекте он, конечно, описан, но ведь документацию читают только ламеры ©
  • Все драйверы режима ядра для Windows 10 (1607) теперь должны быть подписаны Microsoft
    0
    Есть ограниченное логирование всех системных вызовов штатными средствами: флаг EVENT_TRACE_FLAG_SYSTEMCALL в https://msdn.microsoft.com/en-us/library/windows/desktop/aa363784(v=vs.85).aspx. «Ограниченное» значит «только адреса вызываемых функций и возвращаемые значения, без аргументов».
    В сыром виде выглядит примерно так:
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039A5E30
    [2]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF96000127A6C
    [2]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = NTSTATUS=      50
    [2]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039F3090
    [2]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [Thread] Context Switch from 4836. to 0.
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = 0xc0000034(STATUS_OBJECT_NAME_NOT_FOUND)
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039C6430
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = STATUS_SUCCESS
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039A5E30
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = 0xc0000034(STATUS_OBJECT_NAME_NOT_FOUND)
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039A7190
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = STATUS_SUCCESS
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF80003990C40
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = STATUS_SUCCESS
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039C6430
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = STATUS_SUCCESS
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039A5E30
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = STATUS_SUCCESS
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039A5E30
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = 0xc0000034(STATUS_OBJECT_NAME_NOT_FOUND)
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039A5E30
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = STATUS_SUCCESS
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Enter SysCallAddress=0xFFFFF800039ACAD0
    [0]FFFFFFFF.FFFFFFFF::08/02/2016-21:25:37.851 [PerfInfoEvent]System Call Exit NtStatus = 0x8000001a(STATUS_NO_MORE_ENTRIES)
    
    Конкретно это — выдача tracelog -start -eflag 1 0x90 && [пауза] && tracelog -stop && tracefmt -tmf system.tmf LogFile.Etl в формате [CPU]PID.TID::time event. PID/TID, впрочем, придётся отслеживать руками по событиям Context Switch.
  • Все драйверы режима ядра для Windows 10 (1607) теперь должны быть подписаны Microsoft
    0
    «Всякие принтеры» и в винде могут работать в юзерспейсе через UMDF. Когда я последний раз проверял, UMDF-драйверы принудительно подписывать было не нужно.
  • HDD посвящается: усмиряем приложение, прожорливое на дисковое время
    0
    В ...\Image File Execution Options\<filename>.exe\ можно создать значение "UseFilter"=dword:00000001 и произвольное количество подключей с произвольными именами, внутри подключей — значение "FilterFullPath"="C:\<полный путь к filename>.exe", тогда настройки будут браться из подключа с FilterFullPath, совпавшим с полным путём (если такого не нашлось, то, как и раньше, из самого IFEO\<filename>.exe\).
  • Разбор задач финала Технокубка 2016
    0
    Если же входил, то ответом для данного i будет k – 1 + gi, где k — порядковый номер данного друга в оптимальном ответе.
    Это же неправда. Контрпример: Малыш живёт на этаже 1000, рост Карлсона 1 (чтобы не заморачиваться с вопросами инициализации), на первом этаже друг роста 4, на втором — друг роста 998, на третьем — друг роста 1000, на четвёртом — друг роста 999, на каждом следующем этаже m — друг роста m+1. Оптимальная стратегия, очевидно, — две пересадки на первом и на третьем этажах. Если же поссориться с другом на третьем этаже, то g3=3 (если доступны только два первых этажа, придётся просить друзей на 2,998,999 этажах), k-1+g3=4, но Карлсон вполне может добраться за три пересадки, этажи 1,4,999.
  • История языков программирования: 100% «чистый» Си, без единого «плюса»
    0
    Разная семантика inline. Программа из двух файлов. test1.c:
    inline void f() {}
    int main() { f(); return 0; }

    test2.c:
    void f() {}

    Валидно в C, ошибка линковки в C++. Если второй файл убрать, то валидно в C++, ошибка линковки в C (точнее, программа не соответствует стандарту, и может быть ошибка линковки в зависимости от настроения компилятора — будет с gcc -O0, не будет с gcc -O2).
    На Википедии есть пример с sizeof('x').
    Молчаливое преобразование к/из void*, как выше уже привели пример, отнюдь не ограничивается «ручным» выделением памяти.
    Ну а если смотреть на новые стандарты, то они вообще по-разному развиваются: _Bool вместо bool, float _Complex, всякие
    #define mysqrt(X) _Generic((X), long double: sqrtl, default: sqrt, float: sqrtf)

  • C++ без new и delete
    –1
    Я же писал: это значит, что memcpy (как и прочие функции) не обязана делать явных проверок своих аргументов. Если попросить memcpy скопировать один байт из одного мусорного указателя в другой, она может упасть (в случае NULL или совсем невалидных указателей) или действительно скопировать один байт, последствия чего в случае некорректного dst-указателя непредсказуемы.
  • C++ без new и delete
    –2
    n=0 — корректное значение длины, а ваша версия memcpy на нём сломается даже при корректных значениях указателей. Попробуйте ещё раз.
    Более того, указатель на конец массива — это валидный указатель, поэтому memcpy вообще не имеет права разыменовывать переданные ей указатели при n=0.
    Код типа
    class MyContainer {
      // если контейнер пуст, то указатель на данные держим нулевым
      size_t Length = 0;
      int* Data = nullptr;
      ...
      void Append(const MyContainer& other) {
        Realloc(Length + other.Length);
        memcpy(Data + Length, other.Data, other.Length * sizeof(int));
        Length += other.Length;
      }
      ...
    }
    довольно типичен. Он работает на всех платформах, он не был сломан до того, как в gcc закоммитили изменение, его не может сломать корректная реализация memcpy, он не сломан при использовании компилятора, думающего о программистах, типа VC2015.
    UB — это не какие-то законы природы, данные нам свыше. UB означает всего лишь «конструкции, которые стандарт пометил словами undefined behaviour». Часть из них действительно отражают то, как устроен компьютерный мир — в неинициализированной переменной может оказаться всё, что угодно, а если она размещена в регистре, то и Itanium-ный Not-a-Thing с исключением при чтении; аналогично при выходе за границы массива. Часть из них отражают законы физики Марса, и джинна выпустили из бутылки, когда фразу «это UB», после которой забыли написать «потому что на Марсе вот так» (signed overflow на системах со странными представлениями отрицательных чисел), начали интерпретировать «поэтому на Земле мы вам делать так тоже запретим» («ну если ваш код вдруг попадёт на Марс, он же уже сломан!»). А часть — просто неудачные формулировки, и интерпретировать фразу со смыслом «memcpy не обязана делать явных проверок своих аргументов на NULL» как «memcpy нельзя передавать NULL даже при копировании нуля байт» — расписка в бессилии сделать что-то приличными средствами.
  • C++ без new и delete
    0
    Вот только не во всякой программе оптимизации кодогенерации могут дать «5-7% каждый год лет 10», а заменять пузырьковую сортировку быстрой компиляторы не умеют. Поэтому GCC и Clang… ломают код. Не, ну правда, "NULL как аргумент memcpy/memmove — это UB, поэтому если указатель засветился в вызове memcpy/memmove, мы выкинем все проверки с ним и весь код обработки NULL, а если вы делали memcpy(NULL, NULL, 0) — мы сломали весь ваш код, но вы сами виноваты" — больше похоже на троллинг, чем на приличную оптимизацию. (Разумеется, в чистом виде memcpy(NULL, NULL, 0) не встречается, но memcpy(p, q, len) без дополнительных проверок, где при нулевом len p или q могут быть нулями, — очень даже.)
  • Фиеричная система счисления, или почему 1 + 10 = 100
    0
    … в которой мимоходом «доказываются» неверные утверждения.
  • C++ без new и delete
    0
    Я писал конкретно про placement new и автоматический вызов деструктора. Это всё-таки пример, заворачивание в какую-нибудь параметризованную конструкцию дало бы лишь на одну конструкцию, в которую нужно вникать при чтении, больше.
  • C++ без new и delete
    +3
    Майерс отлично прокомментировал это свойство программистов на С++ в своём докладе Why C++ Sails When the Vasa Sank.
    Кстати, на Хабре была статья с основными тезисами этого доклада: https://habrahabr.ru/company/infopulse/blog/227529/.
  • C++ без new и delete
    +2
    Тьфу, сконцентировался на deleter и забыл собственно placement new:
    #include <memory>
    #include <type_traits>
    #include <iostream>
    
    class MyClass
    {
    public:
    	MyClass() { std::cout << "constructor\n"; }
    	~MyClass() { std::cout << "destructor\n"; }
    	void DoSomething() { std::cout << "doing something\n"; }
    };
    
    struct DeleterCallingDestructor
    {
    	template<typename T>
    	void operator()(T* ptr) const { ptr->T::~T(); }
    };
    
    int main()
    {
    	std::aligned_storage<sizeof(MyClass), alignof(MyClass)>::type storage;
    	std::unique_ptr<MyClass, DeleterCallingDestructor> ptr(new(&storage) MyClass);
    	ptr->DoSomething();
    	return 0;
    }
  • C++ без new и delete
    +1
    деструктор придётся вызывать вручную, а это легко забыть сделать
    Но зачем? Можно просто подсунуть unique_ptr правильный deleter:
    #include <memory>
    #include <type_traits>
    #include <iostream>
    
    class MyClass
    {
    public:
    	MyClass() { std::cout << "constructor\n"; }
    	~MyClass() { std::cout << "destructor\n"; }
    	void DoSomething() { std::cout << "doing something\n"; }
    };
    
    struct DeleterCallingDestructor
    {
    	template<typename T>
    	void operator()(T* ptr) const { ptr->T::~T(); }
    };
    
    int main()
    {
    	std::aligned_storage<sizeof(MyClass), alignof(MyClass)> storage;
    	std::unique_ptr<MyClass, DeleterCallingDestructor> ptr(new MyClass);
    	ptr->DoSomething();
    	return 0;
    }
  • Фиеричная система счисления, или почему 1 + 10 = 100
    +3
    Упражнение на закрепление материала: https://projecteuler.net/problem=558.
  • Стандартная библиотека Visual Studio 2015 и телеметрия
    +1
    Если линковщик видит два файла, в которых определена одна и та же функция, то действительно будет ошибка линковки. Фокус в том, чтобы линковщик не пытался смотреть на второй из них.
    Выбор файлов для линковки схематично выглядит так:
    — берём все obj-файлы, явно заданные в командной строке (при компиляции из IDE это файлы главного проекта, но не файлы в проектах-зависимостях);
    — пока есть неразрешённые внешние символы, ищем их в lib-библиотеках и добавляем obj-файлы из lib-библиотек.
    При нормальной компиляции линковщик ищет точку входа, находит её в libcmt.lib:exe_main.obj, видит зависимость от __telemetry_main_invoke_trigger и прочих, находит их в libvcruntime.lib:telemetry.obj, подключает telemetry.obj.
    Если же явно реализовать функции в своём коде, то, увидев зависимость от __telemetry_main_invoke_trigger и прочих, линковщик обнаружит, что он уже знает реализации этих функций и в telemetry.obj просто не полезет.
    Нюанс 1: должны быть реализованы действительно все функции из telemetry.obj, которые может вызвать внешний код. Если, условно, в следующем обновлении функция printf будет вызывать какой-нибудь __telemetry_printf_trigger, получится ошибка линковки из-за двойного определения.
    Нюанс 2: если явная реализация находится во вспомогательной библиотеке, то какая именно реализация подхватится, может зависеть от порядка перечисления библиотек в командной строке. Причём навскидку я не в курсе, в каком порядке обрабатываются встроенные библиотеки и считается ли libvcruntime.lib встроенной.
  • Реверс-инжиниринг визуальных новелл
    0
    У меня в анамнезе слишком много копания в коде, чтобы думать о clean-room, и слишком много программирования, чтобы руками заполнять таблицу, которую может сделать скриптик на десяток строчек кода. Но ваш подход тоже заслуживает внимания.
    Тут выше назвали одну конкретную игру, Kami no Rhapsody, это оттуда. Движок версии 4.46.
  • Реверс-инжиниринг визуальных новелл
    0
    Да. В движке обработчики команд довольно любезно начинают с того, что выставляют размер команды типа mov dword ptr [esi+ecx*4+5D804h], 5, так что
    примерно такой скрипт IDA
    auto a,b,aprev,anext,s,f;
    f=fopen("c:\\temp\\eushully_vm_cmdsize.txt","w");
    for (b=0x415303;b!=BADADDR;b=NextHead(b,0x416713)){
      // установка обработчиков: mov dword ptr [esi+0xA4F24+i*4], offset cmd_i
      if (GetOpType(b,0)!=4) continue;
      fprintf(f,"0x%X\t",(GetOperandValue(b,0) - 0xA4F24)/4);
      s=GetOperandValue(b,1);
      aprev=BADADDR;
      for (a=s;a!=BADADDR;a=anext){
        anext=NextHead(a,BADADDR);
        if(!isCode(GetFlags(a))){fprintf(f,"[not a code at %X]\n",a);break;}
        if (GetOpType(a,0) == 4 && GetOperandValue(a,0) == 0x5D804) {
          if (GetOpType(a,1) == 5)fprintf(f,"%d\n",GetOperandValue(a,1));
          else if (GetOpType(a,1) == 1 &&
            GetMnem(aprev) == "mov" &&
            GetOpType(aprev,0) == 1 &&
            GetOperandValue(aprev,0) == GetOperandValue(a,1) &&
            GetOpType(aprev,1) == 5)fprintf(f,"%d\n",GetOperandValue(aprev,1));
          else fprintf(f,"[unknown write type at %x]\n",a);
          break;
        }
        // если обнаружили ветвление, на всякий случай выходим
        if(Rfirst(a)!=anext || Rnext(a,anext)!=BADADDR){a=BADADDR;break;}
        aprev=a;
      }
      if (a==BADADDR) fprintf(f,"[unresolved: %x]\n",s);
    }
    fclose(f);
    


    заполняет таблицу, за исключением нескольких сложных случаев, которые уже можно добить руками.
  • Реверс-инжиниринг визуальных новелл
    0
    Вы меня заинтриговали, скачал, посмотрел. А что там принципиально сложного? Ну, помимо очевидного замечания, что при количестве команд в несколько сотен выяснение всех деталей того, что делает каждая, потребует некоторой усидчивости?
    Таблицы смещений в скриптах в количестве трёх штук — просто адреса команд с опкодами 0x71, 3, 0x8F. Первая — список возможных сообщений для хранения флагов прочитанности/непрочитанности, вторая — список возможных внешних вызовов из скрипта, третья — список возможных вызовов процедур. Подозреваю, что так сделано для большей стабильности сейвов: когда в сейвах стек вызовов хранится как массив индексов в отдельной таблице, а не прямо адресами внутри файла, это не будет плыть при каждом изменении скриптов.
    Для правки текстов кучу смещений изменять не нужно, достаточно дописывать исправленные тексты в конец файла и править только одно смещение — собственно адрес текста.
    Примитивный дизассемблер
    from __future__ import print_function
    import io, sys, struct
    #table generated automatically, minor mistakes are possible
    cmdsizes = (
    0,1,1,3,3,1,5,3,3,1,5,23,1,9,25,3,	#0x0
    9,19,3,9,1,11,5,5,0,0,0,0,0,0,17,25,	#0x10
    13,5,5,5,5,7,9,9,9,0,9,11,11,25,11,9,	#0x20
    11,9,21,13,25,23,7,23,25,0,0,0,0,0,0,0,	#0x30
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x40
    7,7,7,7,7,5,7,7,7,7,7,7,7,7,7,7,	#0x50
    5,7,7,5,5,5,7,7,7,7,7,7,5,1,5,3,	#0x60
    11,3,3,21,3,3,3,3,3,7,7,5,1,5,3,3,	#0x70
    3,3,11,7,3,1,3,1,3,9,13,3,3,5,3,3,	#0x80
    15,3,5,1,1,5,1,11,0,0,0,0,0,0,0,0,	#0x90
    7,1,5,5,0,0,0,0,0,0,5,5,19,1,1,1,	#0xa0
    3,3,5,1,5,3,3,3,1,3,3,3,3,3,3,3,	#0xb0
    3,1,5,3,3,5,5,5,3,1,1,3,5,1,7,1,	#0xc0
    3,1,3,1,9,3,13,3,5,1,13,0,0,0,0,0,	#0xd0
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0xe0
    0,0,0,0,0,0,0,0,0,0,1,5,1,5,3,1,	#0xf0
    1,1,7,3,1,3,3,5,3,5,5,5,5,3,5,3,	#0x100
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x110
    0,0,0,0,0,0,0,0,0,0,0,0,11,15,17,9,	#0x120
    3,3,3,5,7,5,5,3,5,7,13,15,3,7,5,7,	#0x130
    9,3,3,1,5,3,3,13,3,3,15,3,5,13,0,0,	#0x140
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x150
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x160
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x170
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x180
    5,5,5,7,7,7,7,3,7,1,3,1,1,5,5,5,	#0x190
    19,5,3,3,5,3,5,3,1,3,3,5,7,1,7,7,	#0x1a0
    7,3,3,1,1,3,3,3,5,5,5,3,1,3,5,1,	#0x1b0
    3,7,5,5,3,9,5,3,5,7,3,3,3,5,3,3,	#0x1c0
    7,11,5,11,9,1,5,5,7,5,0,0,0,0,0,0,	#0x1d0
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x1e0
    0,0,0,0,1,1,1,5,9,7,3,17,3,9,11,9,	#0x1f0
    3,3,11,9,9,13,15,17,7,11,3,15,1,3,1,7,	#0x200
    3,3,5,7,5,5,5,9,9,9,9,3,1,5,13,15,	#0x210
    13,9,5,17,1,5,11,13,11,11,7,9,7,11,13,11,	#0x220
    3,9,9,11,11,11,9,5,3,13,5,15,1,1,5,5,	#0x230
    9,11,5,1,1,5,5,3,3,7,7,5,5,25,3,21,	#0x240
    21,25,3,5,11,13,11,11,5,1,3,3,17,7,11,9,	#0x250
    9,3,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x260
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x270
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x280
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x290
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x2a0
    0,0,0,0,0,0,0,0,0,0,0,0,23,3,3,7,	#0x2b0
    7,3,13,5,1,5,5,9,9,7,3,3,3,3,3,3,	#0x2c0
    7,7,7,7,7,5,5,5,7,5,17,3,3,5,5,7,	#0x2d0
    7,7,7,7,7,3,5,5,3,3,3,3,5,3,3,23,	#0x2e0
    19,15,13,13,7,9,3,3,5,15,3,3,11,13,0,0,	#0x2f0
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x300
    0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,	#0x310
    21,7,9,11,1,5,9,3,7,5,3,1,13,5,23,3,	#0x320
    5,9,9,11,3,9,11,9,13,15,13,9,5,7,11,7	#0x330
    )
    # list created manually, may be incomplete
    # (cmd in oplabels[i]) == (i-th operand of cmd is an offset)
    oplabels = (
    (0x7B,0x8C,0x8F,0xD5),
    (0x7B,0x8D,0x92,0x95,0xA0,0xA2,0xA3,0xCC,0xCE,0xFB),
    (0xA0,0xCE,0xD4,0x102),
    (0xD4,),
    (0xD6,0x90),
    (0xD6,0x90),
    (0x90,),
    )
    with io.open(sys.argv[1], 'rb') as f:
    	header = struct.unpack('<4s4s6I', f.read(0x20))
    	if header[0] != b'SYS3' and header[0] != b'SYS4':
    		print("invalid signature")
    		sys.exit(1)
    	header2size = struct.unpack('<I', f.read(4))[0]
    	header2 = struct.unpack('<' + str(header2size // 4 - 1) + 'I', f.read(header2size - 4))
    	data = f.read()
    # pass 1: prepare labels
    pos = 0
    maxAddr = 0
    labels = set()
    while pos < len(data) // 4:
    	cmd = struct.unpack_from('<I', data, pos * 4)[0]
    	if cmd >= len(cmdsizes) or cmdsizes[cmd] == 0:
    		break
    	for i in xrange((cmdsizes[cmd] - 1) // 2):
    		optype, operand = struct.unpack_from('<ii', data, (pos + 1 + 2 * i) * 4)
    		if i < len(oplabels) and cmd in oplabels[i] and optype == 0 and operand >= 0:
    			labels.add(operand)
    			maxAddr = max(maxAddr, operand)
    	pos += cmdsizes[cmd]
    	if cmd in (1,2,5) and pos > maxAddr:
    		break
    # pass 2: print
    print("\theader '%s', %d, %d, %d, %d, %d, %d" % header[1:])
    pos = 0
    unprintedLabels = labels
    firstStringOffs, lastStringOffs = -1, -1
    firstArrayOffs, lastArrayOffs = -1, -1
    messageStarts = []
    externalCalls = []
    internalCalls = []
    while pos < len(data) // 4:
    	if pos in labels:
    		print("loc_%08X:" % pos)
    		unprintedLabels.remove(pos)
    	cmd = struct.unpack_from('<I', data, pos * 4)[0]
    	if cmd >= len(cmdsizes) or cmdsizes[cmd] == 0:
    		print("\t[invalid command 0x%X]" % cmd)
    		break
    	if cmd == 0x71:
    		messageStarts.append(pos)
    	if cmd == 3:
    		externalCalls.append(pos)
    	if cmd == 0x8F:
    		internalCalls.append(pos)
    	cmdsize = cmdsizes[cmd]
    	cmdargs = struct.unpack_from('<' + str(cmdsize - 1) + 'i', data, (pos + 1) * 4)
    	print("\tcmd%03X" % cmd, end='')
    	for i in xrange((cmdsize - 1) // 2):
    		if i:
    			print(",", end='')
    		print(" ", end='')
    		if cmdargs[i * 2] == 0:
    			if i < len(oplabels) and cmd in oplabels[i] and cmdargs[i * 2 + 1] >= 0:
    				print("loc_%08X" % cmdargs[i * 2 + 1], end='')
    			elif cmd == 0x64 and i == 1:
    				# second arg of cmd064 is offset of array in data
    				offs = cmdargs[i * 2 + 1]
    				if lastArrayOffs == -1:
    					firstArrayOffs = offs
    				elif lastArrayOffs != offs:
    					print("[Warning: out-of-order array]");
    				arrsize = struct.unpack_from('<I', data, offs * 4)[0]
    				arr = struct.unpack_from('<' + str(arrsize) + 'i', data, (offs + 1) * 4)
    				lastArrayOffs = offs + 1 + arrsize
    				print('<', end='')
    				for j in xrange(arrsize):
    					if j:
    						print(",", end='')
    					print('%d' % arr[j], end='')
    				print('>', end='')
    			else:
    				print('%d' % cmdargs[i * 2 + 1], end='')
    		elif cmdargs[i * 2] == 2:
    			offs = cmdargs[i * 2 + 1] * 4
    			if lastStringOffs == -1:
    				firstStringOffs = offs // 4
    			elif lastStringOffs != offs // 4:
    				print("[Warning: out-of-order string: %08X instead of %08X]" % (offs // 4, lastStringOffs), end='');
    			decoded = b''
    			while True:
    				s = ord(data[offs]) ^ 0xFF
    				if s == 0:
    					break
    				decoded += chr(s)
    				offs += 1
    			lastStringOffs = (offs + 1) // 4 + 1
    			print(b'"' + decoded + b'"', end='')
    		else:
    			print('op%X[0x%X]' % (cmdargs[i * 2], cmdargs[i * 2 + 1]), end='')
    	print()
    	pos += cmdsize
    	# command 5 can be a normal command with size=1 or nofollow-command depending on ???
    	# commands 4,9,0x7C are actually nofollow, but codegen seems to treat them as normal ones
    	if cmd in (1,2,5) and pos > maxAddr:
    		break
    if len(unprintedLabels):
    	print("Warning: not all labels were printed");
    expectedEndAddr = min(len(data) // 4, header2[1], header2[3], header2[5])
    if firstArrayOffs != -1:
    	if lastArrayOffs != expectedEndAddr:
    		print("Warning: range [%08X,%08X) was not printed" % (lastArrayOffs, expectedEndAddr))
    	expectedEndAddr = min(expectedEndAddr, firstArrayOffs)
    if firstStringOffs != -1:
    	if lastStringOffs != expectedEndAddr:
    		print("Warning: range [%08X,%08X) was not printed" % (lastStringOffs, expectedEndAddr))
    	expectedEndAddr = min(expectedEndAddr, firstStringOffs)
    if pos != expectedEndAddr:
    	print("Warning: range [%08X,%08X) was not printed" % (pos, expectedEndAddr))
    if messageStarts != list(struct.unpack_from('<' + str(header2[0]) + 'i', data, header2[1] * 4)):
    	print("Warning: unexpected messageStarts array")
    if externalCalls != list(struct.unpack_from('<' + str(header2[2]) + 'i', data, header2[3] * 4)):
    	print("Warning: unexpected externalCalls array")
    if internalCalls != list(struct.unpack_from('<' + str(header2[4]) + 'i', data, header2[5] * 4)):
    	print("Warning: unexpected internalCalls array")


    В принципе, при некотором желании выдачу дизассемблера выше можно даже скомпилировать назад с помощью fasmg, если пошаманить с его макросами.
  • Так ли нужно избавляться от ветвлений? — На примере sign, abs, min и max
    +1
    Для разнообразия, на AMD:
    AMD Phenom II P820 @1.80GHz
    Visual C++ 2015, /Ox
    Последовательная версия:
    sign: 4.81 vs 5.14
     abs: 3.61 vs 2.40
    mini: 2.40 vs 12.01
    maxi: 2.40 vs 12.00
    minu: 2.40 vs 12.14
    maxu: 2.53 vs 12.73
    Хаотическая версия:
    sign: 20.19 vs -0.00
     abs: 18.07 vs 0.00
    mini: 0.00 vs 9.60
    maxi: -0.00 vs 12.01
    minu: 0.00 vs 12.01
    maxu: 0.04 vs 12.01
    
    g++ 5.2.0, -std=c++11 -O3
    Последовательная версия:
    sign: 9.72 vs 9.59
     abs: 7.20 vs 7.20
    mini: 7.20 vs 14.50
    maxi: 7.19 vs 9.88
    minu: 7.20 vs 7.20
    maxu: 7.20 vs 9.59
    Хаотическая версия:
    sign: 17.34 vs 2.56
     abs: 16.28 vs 0.02
    mini: -0.00 vs 0.00
    maxi: 0.00 vs 3.61
    minu: 20.99 vs 8.91
    maxu: -0.00 vs 3.61
    

    Но, надо отметить, определение empty в последовательной версии некорректно: что gcc, что clang успешно сворачивают цикл с empty в константу. gcc, кстати, в неправильную константу: https://godbolt.org/g/wibi2q.
  • Задача про обезьян и бесконечность
    0
    И в качестве упражнения на закрепление материала: https://projecteuler.net/problem=316.
  • Стандартная библиотека Visual Studio 2015 и телеметрия
    +1
    Извините, ЧТО?
    Я бы предположил, что вы спутали код загрузчика приложений (ntdll.dll/ld-linux.so) и код рантайма конкретной среды программирования, но код загрузчика приложений тоже не имеет никакого отношения к планировщику.
    И не соблаговолит ли прилежный слушатель курса операционных систем и системного программирования просветить невежественную шпану типа меня, каким образом прослушивание такого курса избавляет от вопроса «что делает вызов __telemetry_main_invoke_trigger() непосредственно перед вызовом main()»?
  • Стандартная библиотека Visual Studio 2015 и телеметрия
    0
    Ха. На Windows 10 без отключения телеметрии обновлённая версия детектора показывает, что система таки ведёт все логи. Только не уточняет, куда.
  • Стандартная библиотека Visual Studio 2015 и телеметрия
    0
    Даже если мы линкуем рантайм статически, мы не можем знать, как поведёт себя логирование и телеметрия.
    hello.exe из статьи — вполне готовый бинарник, на его месте может быть любая собранная программа. А logman/tracerpt могут быть запущены совершенно независимо от него и от ведома разработчика hello.exe. В том числе апдейтом Windows. В том числе не трогающем vcruntime140.dll или как она там называется.
  • Стандартная библиотека Visual Studio 2015 и телеметрия
    –1
    Как минимум это занимает ощутимое место в exe-шнике.
  • Стандартная библиотека Visual Studio 2015 и телеметрия
    0
    Да, это появилось только в VS 2015.
  • Включение подсистемы Linux в Windows 10
    +3
    NtCreateProcess/NtCreateProcessEx с ненулевым четвёртым аргументом и нулевым шестым.
  • Включение подсистемы Linux в Windows 10
    +3
    В ядре NT с самого начала была возможность честного форка процесса — с клонированием таблиц страниц и copy-on-write. Она недокументирована и до неё нельзя достучаться через Win32 API, но для отдельной подсистемы это не проблема. Cygwin/MinGW работают через Win32 API, поэтому у них, да, проблемы.
  • 11 неожиданных особенностей языков программирования
    +1
    Обновитесь до Lua 5.3. Будет a&b.
  • Об одной интересной ошибке в Lucene.Net
    0
    Чтобы в Python, где нет операции инкремента, всё равно можно было писать ++a!
    В Lua, кстати, унарного плюса нет.
  • Реверс-инжиниринг «Казаков», часть вторая: увеличение очереди
    +2
    В 32-битном режиме loop контролируется регистром ecx, не cx.
  • Дайджест KolibriOS #11 все новости с последнего выпуска и Google Summer of Code 2016
    0
    Нет. Те, кому нужно, просто берут готовый код.
  • Дайджест KolibriOS #11 все новости с последнего выпуска и Google Summer of Code 2016
    0
    Перед передачей LZMA-распаковщику нужно дописать впереди нулевой байт (LZMA-поток всегда начинается с нулевого байта) и, возможно, bswap-нуть первый dword (а может быть, и нет, не помню точно). Кроме того, в зависимости от флагов после LZMA-потока могут быть данные для постпроцессинга (instruction-relative offset <-> absolute address; постпроцессинг для распаковщика, препроцессинг для упаковщика) E8/E9 и 0F 8x.
  • Какими были ноутбуки 20 лет назад на примере Toshiba libretto 100ct
    0
    i386 как платформы, туда же относится и 486-й, я так понимаю, что нужны пентиумные инструкции минимум теперь для 32-битного ядра
    Неправильно понимаете. Убрали именно поддержку 386, потому что для SMP очень полезны инструкции xadd и cmpxchg, которые появились в 486. А 486-е всё ещё поддерживаются.