1. Си / Говнокод #24150

    0

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    12. 12
    13. 13
    14. 14
    15. 15
    16. 16
    17. 17
    18. 18
    19. 19
    20. 20
    21. 21
    22. 22
    23. 23
    24. 24
    25. 25
    26. 26
    27. 27
    28. 28
    29. 29
    30. 30
    31. 31
    32. 32
    33. 33
    34. 34
    35. 35
    36. 36
    37. 37
    38. 38
    39. 39
    40. 40
    41. 41
    42. 42
    43. 43
    44. 44
    45. 45
    46. 46
    47. 47
    48. 48
    49. 49
    50. 50
    51. 51
    52. 52
    53. 53
    54. 54
    55. 55
    char *r_or_mem() {
        if ( get_mod() == 3 )
            return regs [ ( size << 3 ) | ( look & 7 ) ] ;
        else {
            static char buf [ 32 ] ;
            char *s = buf ;
            *s++ = '[' ;
            if ( ! ( look & 4 ) ) {
                *s++ = 'B' ;
                *s++ = ( look & 2 ) ? 'P' : 'X' ;
                *s++ = '+' ;
                *s++ = ( look & 1 ) ? 'D' : 'S' ;
                *s++ = 'I' ;
                if ( mod ) *s++ = '+' ;
            } else {
                if ( ( look & 7 ) == 6 && ! mod ) mod = 2 ;
                else {
                    if ( look & 2 ) {
                        *s++ = 'B' ;
                        *s++ = ( look & 1 ) ? 'X' : 'P' ;
                    } else {
                        *s++ = ( look & 1 ) ? 'D' : 'S' ;
                        *s++ = 'I' ;
                    }
                    if ( mod ) *s++ = '+' ;
                }
            }
            if ( mod ) {
                read_value ( s , mod == 2 ) ;
                s = s + strlen ( s ) ;
            }
            *s++ = ']' ;
            *s = 0 ;
            return buf ;
        }
    }
    
    void checkorder() {
        if ( ! dest ) {
            char *tmp = op1 ;
            op1 = op2 ;
            op2 = tmp ;
        }
    }
    
    void rm ( char *s ) {
        sprintf ( decoded , "%s\t" , s ) ;
        decoded += strlen ( decoded ) ;
        get_ds() ;
        read() ;
        op1 = get_reg() ;
        op2 = r_or_mem() ;
        checkorder() ;
        sprintf ( decoded , "%s , %s" , op1 , op2 ) ;
    }

    Чассть моего дизассемблера для 16-анального x86, что читает операндыы.

    Запостил: yet_another_one_shit, 19 Апреля 2018

    Комментарии (61) RSS

    • Я сам уже непонимаю, что тут напейсал.
      Ответить
      • Ну да, там номер регистра в опкоде как-то хитро кодируется, байт r/m и прочая фигня.
        Ответить
        • Это самая сложная часть дизасма. Всё остальное намного проще, а КОП вообще по табличке.
          Ответить
          • Дойдёшь до SSE -- поседеешь от количества команд. А до этого всё простенькое, да.
            Ответить
            • А я уже на него забил, осталось где-то ещё примерно 16 команд. Хотя хотел ещё и 32-разрядный код дизасмить, но остановился на 16-разрядном. Может быть и продолжу когда-нибудь.
              Ответить
    • А можно ли на Си организовать аналог замыканий, или что-то в этом роде ?
      А то у меня много такого кода, типа:
      //....
      void stosb() { strcpy ( decoded , "STOSB" ) ; }
      void stosw() { strcpy ( decoded , "STOSW" ) ; }
      // и ещё дохуя таких же строчек
      //...
      // а потом таблица функций:
      void (*decode [ 256 ])() = {
          // ...
          stosb , stosw , ....
          //...
      } ;

      А хотелось бы:
      void (*decode [ 256 ])() = {
          //...
          opcode ( "STOSB" ) , opcode ( "STOSW" ) ,...
         //...
      }
      Ответить
      • Ну самый тупой вариант, если параметров не так много и они не сильно разнообразные:
        struct decoder {
            void(*function)();
            const char* param1;
            const char* param2;
        };
        
        void simple_decoder(const char* param1, const char* param2) {
            ...
        }
        
        decoder decoders[256] = {
            // ...
            { &simple_decoder, "STOSB" }
            { &simple_decoder, "STOSW" }
            { &another_decoder, "PARAM1", "PARAM2" }
            { &yet_another_decoder }
            // ...
        }
        
        decoders[b].function(decoders[b].param1, decoders[b].param2);
        Ответить
        • Таки этот вариант мне подходит, правда придется всю табличку переписывать и ещё пару строчек в основном цикле, но зато дохрена строчек можно будет удалить.
          Ответить
        • Таки надо было:
          struct decoder {
              void (*f)(char*);
              //...
          } ;
          , но хуй с ним, и так понятно.
          Ответить
        • Вот я лох ! Как я сам до этого не допёр !
          412 строк превратились в 293.
          Ответить
    • З.Ы. Самая большая проблема в 16-битном дизассемблере в 2018 году — найти что-нибудь, что им можно подизасмить.
      Ответить
      • А через пару-тройку поколений интеловские процы вообще разучатся исполнять 16-битный код.
        Ответить
      • Таки я потом хочу добавить и 32-бита, если руки дойдут, может быть даже и 64. Так что это только начало.
        Ответить
        • Х.з., асм-дизасм скучно писать, сплошная рутина. Лучше интерпретатор запили.
          Ответить
          • Я уже пилил, я много чего пилил: интерпретатор васика, копелятор с паскаля в fasm, форт-систему на fasm, форт-систему на Си, игрушки для КолибриОС.

            ЗЫ. Жалко что на биржах фриланса заказы в основном по вебу, низкоуровневости почти не встречается.
            Ответить
            • Это что-то новое. Я думал, заносчивые обитатели сего сайта брезгуют биржами фриланса.
              Ответить
            • СёмаРиал, а зачем ты начал сходить с ума и нарываться на бан?
              Ответить
              • А ты типа местный шериф?
                Ответить
              • Вот ты мне скажи — ты что долбоёб штоле ?
                Ответить
                • Он и десять лет назад им был.
                  Ответить
                  • Ыхыхы. Посмотрите кто тут у нас. Это же проситель, ежегодно строчащий плаксивые реквесты:
                    Админ, забаньте наконец Борманда.


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

                  Как и ответы вопросом на вопрос.
                  Ответить
                  • Целые сутки думал над ответом ?
                    И снова ты долбоёб — где ты видишь агрессию ?
                    Я Гоано, а не СемаРиал.
                    Ответить
                    • >Я Гоано, а не СемаРиал.
                      Слуш, ты уж оперделись тогда.
                      Ты Гоано, СемаРиал, еще_одно_говно, или dolboeb?

                      http://govnokod.ru/24137#comment412042
                      Ответить
                      • Из-за своей ебнутой очепятки я не ещё_одно_говно, а пока_что_ещё_одно_говно.
                        А насчет dolboeb'а:
                        dolboeb *yet_another_one_shit = new dolboeb()

                        И с чего ты взял, что я СемаРиал ?
                        И кто такой Слуш ?
                        Ответить
      • Огромное количество старых игр
        Ответить
        • Отдизасмить и забабахать точный клон Blood под венду :)
          Ответить
          • Я думаю что ты можешь найти исходные коды на си, но не очень уверен что их наличие поможет тебе написать клон блада под directx или Opengl
            Ответить
          • Blood сделан на движке Build, и там 32 бита
            https://github.com/videogamepreservation/dukenukem3d
            https://github.com/fabiensanglard/vanilla_duke3D/blob/master/SRC/A.ASM#L67
            Ответить
            • Не знал. Я думал что все игры под DOS 16-битные.
              Ответить
              • 640к памяти хватит не всем
                почитай про dos extenders, dos4gw и пр.
                Ответить
              • Нет, это точно не сёмариал.

                Короче, во времена дос были программы для реального режима проца - они могли занимать максимум 600 с чем-то кб оперативы. Кому этого не хватало, сам переводил проц в защищенный режим - так ему была доступна вся оператива. Так появились дос расширители. Недостаток появился, когда появилась win32 - они конкуррировали с осью - главный должен быть только один. Win9x их терпела, но если такие игры висли - гарантированно висла и винда. NT поэтому с ними никогда не дружила и теперь в Blood можно поиграть разве что в досбоксе.

                А 16 бит это 64кбит. Даже в реальном режиме смещение было 32 бита.
                Ответить
                • *кбайт
                  Ответить
                • Смещение (если ты о порции OFFSET адреса) было 16-ти битным так как задавалось регистром в 16 бит: SP, IP итд.

                  Однако значение в сегментном регистре обрезалось, в итоге удавалось адресовать до 20 бит (1мб). Минус область bios, память видеоадаптера итд, в итоге программам доставалось 640К.
                  Туда же загружались (по умолчанию) всякие TSR (резидентные) программы вроде драйвера мыши и русификатора, в итоге программам доставалось еще меньше.

                  Однако всякие гоблины, викинги и принцы персии работали на ура (вероятно они использовали оверлеи: загружали часть данных в память при необходимости)
                  Ответить
                  • Да, от сегмента отрезалось 4 бита и оставшиеся 16 сохранялись. Но 32 бита даже в реальном режиме можно было адресовать? Или дос не позволял?
                    Вот ты похож на сёмуриал.
                    Ответить
                    • > 32 бита даже в реальном режиме можно было адресовать
                      Только через unreal mode — прыгаешь в защищённый режим и возвращаешься обратно оставив limit на 32 бита. Само собой, этот хак работал только на 32-битных процах.
                      Ответить
                    • У первого IBM PC был процессор 8080 у которого физически было 20 дорожек на шине адреса, так что адресовать 32 бита было нельзя никак.

                      У 286 дорожек стало 24 (до 16 мегабайт) , и только у 386 их стало 32 (причем был кастрированный SX который имел 24 дорожки).

                      Так что физически адресовать 32 бита стало можно только в 386, однако для доступа туда из реального режима нужен был или хак unreal mode, или появившиеся в конце 80х спецификации DPMI, VCPI и XMS (himem.sys), да и то: там можно было держать данные (собссно, драйвер их туда копировал) а исполнять там код было нельзя.

                      А до этого еще была борьба за целый сегмент (64К) HMA (см "gate A20"), в общем это всё треш, ад и кошмар.

                      Слава виртуальной памяти, MMU слава.
                      Ответить
    • А что может случиться, если void (*f)(char*) присвоить указатель на void somefunc() и вызвать f(somestr) ?
      Ответить
      • А нихуя ни произойдёт.
        Ответить
        • Да ты что?!
          Ответить
          • Просто дропнет лишний аргумент. Ибо cdecl.

            Почти как джаваскрипт.
            Ответить
            • Никто его не дропнет, стек очистит вызывающий функцию код уже после возврата. Просто я тупнул.
              Ответить
            • Я бы сказал -- как perl:)

              cdecl был не быстр, емнип: там все надо было пихать в стек, даже ты хочешь один байт передать.
              Регистры не использовались
              Ответить
    • Чем-то hde напомнило, правда, тот был под 32 бита и определял длину команды( ты ему точку вхоха, а он тебе - опкоды и смещение начала следующей команды ).
      На самом деле, прикольная либа была.. весом менее 1Кб
      Ответить
    • Я думал, што хоть ктонить критикнёт, это нормально что я в строку пописал вот так:
      *s++ = 'B' ;
      *s++ = ( look & 2 ) ? 'P' : 'X' ;
      *s++ = '+' ;
      *s++ = ( look & 1 ) ? 'D' : 'S' ;
      *s++ = 'I' ;
      if ( mod ) *s++ = '+' ;
      ?
      Ответить
      • Норм.
        Ответить
        • Так красивше:
          sprintf ( s , "%s+%s%s" , look & 2 ? "BP" : "BX" , look & 1 ? "DI" : "SI" , mod ? "+" : "" ) ;
          s += strlen ( s ) ;
          Ответить
          • Паттерн snprintf builder:
            pos += snprintf(buf + pos, size - pos, ...)
            Ответить
            • s += sprintf ( s , "%s+%s%s" , look & 2 ? "BP" : "BX" , look & 1 ? "DI" : "SI" , mod ? "+" : "" ) ;
              Ответить
              • Упорото:
                s += sprintf ( s , "%s+%s%s" , (char*[]){"BP", "BX"}[(look & 2) == 0] , (char*[]){"SI", "DI'}[look & 1] , (char*[]){"+", ""}[mod == 0]) ;
                Ответить
                • > (char*[]){"BP", "BX"}[(look & 2) == 0]
                  Это в нормальном Си так можно?

                  Лямбда C++ выворачивается и превращается в "лямбда-взятие" элемента массива.
                  Ответить
                  • Можна, C99 составной литерал. Я когда про него узнал сразу кинулся проверять:
                    (void(*)()){puts("Lambda!");}() ;
                    Ниработаит :(
                    Ответить

    Добавить комментарий