связка Visual C++ 2017 с MASM

Тема в разделе "WASM.BEGINNERS", создана пользователем kol1978, 18 фев 2025 в 07:20.

  1. kol1978

    kol1978 Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    31
    Что бы было максимальна понятна суть вопроса попробую начать из далека :
    - так как вопрос по содержанию книги...
    Пример связки NASM использует синтаксис Intel:
    файл - nano hello.S:
    Код (Text):
    1. global _start           ; делаем метку метку _start видимой извне
    2.  
    3. section .data   ; секция данных
    4. message: db "Hello world!",10  ; 10 после строки — это код символа перевода строки, то есть при выводе будет происходит>
    5.  
    6. section .text           ; объявление секции кода
    7. _start:                 ; объявление метки _start - точки входа в программу
    8.     mov rax, 1          ; 1 - номер системного вызова функции write
    9.     mov rdi, 1          ; 1 - дескриптор файла стандартного вызова stdout
    10.     mov rsi, message    ; адрес строки для вывод
    11.     mov rdx, 15         ; количество байтов
    12.     syscall             ; выполняем системный вызов write
    13. mov     edi, 0
    14.     mov rax, 60         ; 60 - номер системного вызова exit
    15.     syscall             ; выполняем системный вызов exit(0)
    Чтобы запустить его:
    nasm -f elf64 -o hello.o hello.S
    ld -o hello hello.o
    ./hello
    Переделка для GCC - nano hello_N.S:
    Код (Text):
    1.         .intel_syntax noprefix
    2.         .data
    3. message: .string "Hello world!"
    4.  
    5.         .globl  main
    6.         .text
    7. main:
    8.         mov rax, 1
    9.         mov rdi, 1
    10.         mov rsi, message
    11.         mov rdx, 15
    12.         syscall
    13.         mov edi, 0
    14.         mov rax, 60
    15.         syscall
    16. l
    Компиляция : gcc -no-pie -masm=intel hello_N.S -o hello
    Далее файл на СИ - nano hello.c:
    Код (Text):
    1.  
    2. компиляция #include <unistd.h>
    3.  char message[] = "Hello, world!\n";
    4. int main()
    5. {
    6.    write(1, message, sizeof(message));
    7.   _exit(0);
    8. }
    9.  
    Получаем ассемблер gcc -S -masm=intel hello.c -o hello_.s :
    Код (Text):
    1.  
    2. .intel_syntax noprefix
    3. message:
    4.         .string "Hello, world!\n"
    5.         .text
    6.         .globl  main
    7. main:
    8.         mov     edx, 15
    9.         lea     rax, message[rip]
    10.         mov     rsi, rax
    11.         mov     edi, 1
    12.         call    write
    13.         mov     edi, 0
    14.         call    _exit
    15.  
    в синтаксисе по умолчанию это :
    Код (Text):
    1.  
    2. message:
    3.         .string "Hello, world!\n"
    4.         .text
    5.         .globl  main
    6. main:
    7.         movl    $15, %edx
    8.         leaq    message(%rip), %rax
    9.         movq    %rax, %rsi
    10.         movl    $1, %edi
    11.         call    write
    12.         movl    $0, %edi
    13.         call    _exit
    14.  
    Компилируем gcc -masm=intel hello_.s -o hello_
    Запускаем:
    ./hello_
    это что бы бала понятна речь про "связку" - Си и ассемблера:
    Код (Text):
    1.  
    2. gcc -S hello.c -o hello.s
    3. gcc hello.s -o hello_c
    4. gcc -S -masm=intel hello.c -o hello_.s
    5. gcc -S -masm=att hello.c -o hello.S
    6. gcc -masm=intel hello_.s -o hello_
    7. gcc -masm=att hello.S -o hello
    8.  
    И так вопрос:
    Сказано :
    а так же
    так же мне известно :
    в ассемблере GAS мы можем работать с 8-разрядными, 16-разрядными, 32-разрядными и 64-разрядными числами. Для каждого из этих типов чисел предназначен свой суффикс:
    q: для 64-разрядных чисел
    l: для 32-разрядных чисел
    w: для 16-разрядных чисел
    b: для 8-разрядных чисел
    инструкции mov, которая копирует данные, есть следующие вариации:
    movq: для копирования 64-разрядных чисел
    movl: для копирования 32-разрядных чисел
    movw: для копирования 16-разрядных чисел
    movb: для копирования 8-разрядных чисел
    Вопрос: "любое указанное 32 битное непосредственное значение перед использованием расширяется до 64 бит" - это особенность компилятора Микрософт? и (или) что именно происходит по аналогии с GCC?
     
    Последнее редактирование: 18 фев 2025 в 11:04
  2. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    251
    Тип, режим и управление памятью были полностью переработаны с появлением х64.
    Если на х32 память была плоская "Flat", то на х64 уже длинная/большая "Long".
    Вот некоторые аппаратные особенности Intel и AMD, которые не зависят от компиляторов.

    На х32 блок управления памятью MMU в цп полностью зависел от записей в таблице GDT (копируются в шадов сегм.рег CS..GS), где задавались база и лимиты сегментов-кода/данных/стека. Если не брать во-внимание атрибуты, то вирт.база для всех сегментов выставлялась в нуль, а лимит/размер на макс 4Gb. Например код адресовался парой CS:EIP, данные DS:ESI, а стек SS:ESP. Примерно так выглядела таблица GDT на WinXP x32:
    Код (Text):
    1. kd> dg 0 80
    2.                                      P Si Gr Pr Lo
    3. Sel     Base     Limit      Type     l ze an es ng Flags
    4. ----  -------- --------  ----------  - -- -- -- -- --------
    5. 0000  00000000 00000000  <Reserved>  0 Nb By Np Nl 00000000
    6. 0008  00000000 ffffffff  Code RE Ac  0 Bg Pg P  Nl 00000c9b
    7. 0010  00000000 ffffffff  Data RW Ac  0 Bg Pg P  Nl 00000c93
    8. 0018  00000000 ffffffff  Code RE Ac  3 Bg Pg P  Nl 00000cfb
    9. 0020  00000000 ffffffff  Data RW Ac  3 Bg Pg P  Nl 00000cf3
    10. 0028  80042000 000020ab  TSS32 Busy  0 Nb By P  Nl 0000008b
    11. 0030  ffdff000 00001fff  Data RW Ac  0 Bg Pg P  Nl 00000c93
    12. 0038  7ffdd000 00000fff  Data RW Ac  3 Bg By P  Nl 000004f3
    13. 0040  00000400 0000ffff  Data RW     3 Nb By P  Nl 000000f2
    14. 0048  00000000 00000000  <Reserved>  0 Nb By Np Nl 00000000
    15. 0050  80551380 00000068  TSS32 Avl   0 Nb By P  Nl 00000089
    16. 0058  805513e8 00000068  TSS32 Avl   0 Nb By P  Nl 00000089
    17. 0060  00022f40 0000ffff  Data RW Ac  0 Nb By P  Nl 00000093
    18. 0068  000b8000 00003fff  Data RW     0 Nb By P  Nl 00000092
    19. 0070  ffff7000 000003ff  Data RW     0 Nb By P  Nl 00000092
    20. 0078  80400000 0000ffff  Code RE     0 Nb By P  Nl 0000009a
    21. 0080  80400000 0000ffff  Data RW     0 Nb By P  Nl 00000092
    22. kd>
    При такой схеме, чтобы вычислить нужный адрес MMU требовалось много времени, поэтому на х64 от неё отказались, в пользу "RIP-относительной" адресации. Теперь в режиме Long в GDT для сегмента-кода лимит отсутствует, и в дефолте MMU высчитывает адрес относительно текущего значения RIP + Mem32 (см.флаги в предпоследнем столбце ниже), хотя в режиме совместимости с х32 всё остаётся по прежнему.
    Код (Text):
    1. 0: kd> dg 0 80
    2.                                                         P Si Gr Pr Lo
    3. Sel         Base               Limit           Type     l ze an es ng Flags
    4. ----  -----------------  -----------------  ----------  - -- -- -- -- --------
    5. 0000  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    6. 0008  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    7. 0010  00000000`00000000  00000000`00000000  Code RE Ac  0 Nb By P  Lo 0000029b
    8. 0018  00000000`00000000  00000000`ffffffff  Data RW Ac  0 Bg Pg P  Nl 00000c93
    9. 0020  00000000`00000000  00000000`ffffffff  Code RE Ac  3 Bg Pg P  Nl 00000cfb
    10. 0028  00000000`00000000  00000000`ffffffff  Data RW Ac  3 Bg Pg P  Nl 00000cf3
    11. 0030  00000000`00000000  00000000`00000000  Code RE Ac  3 Nb By P  Lo 000002fb
    12. 0038  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    13. 0040  00000000`00b9b000  00000000`00000067  TSS32 Busy  0 Nb By P  Nl 0000008b
    14. 0048  00000000`0000ffff  00000000`0000f800  <Reserved>  0 Nb By Np Nl 00000000
    15. 0050  ffffffff`fffdc000  00000000`00003c00  Data RW Ac  3 Bg By P  Nl 000004f3
    16. 0058  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    17. 0060  00000000`00000000  00000000`ffffffff  Code RE     0 Bg Pg P  Nl 00000c9a
    18. 0068  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    19. 0070  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    20. 0078  00000000`00000000  00000000`00000000  <Reserved>  0 Nb By Np Nl 00000000
    21. 0080  Unable to get descriptor
    22. 0: kd>
    При "RIP-Relative-Addressing" аргумент всегда должен быть 32-битный (прыжки на +/- 2 Gb от текущего RIP), поэтому чтобы получить валидный адрес, инженерам нужно было перестраховаться - в частности так при записи 32-бит значения в 64-бит регистр, они решили аппаратно сбрасывать старшую часть х64 в нуль (иначе там может остаться мусор). Таким образом это аппаратная фишка, а компиляторы всех мастей просто вынуждены подстраиваться под неё (причём только в режиме Long64).

    Кстати это наблюдается и вашем примере выше:
     
    Последнее редактирование: 18 фев 2025 в 12:53
    kol1978 нравится это.
  3. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    509
    Это вообще не про компилятор, а про процессор.
    i86 развивался в несколько этапов.
    Пока он был 16-битным в нём все команды строго по опкоду делились на две группы - работают они с байтом или со словом (16 бит).
    При этом ортогональным слоем идут режимы адресации с помощью байта ModR/M. В них смещение offset тоже может иметь размер или байта или слова и это задаётся в самом байте ModR/M отдельно.

    Когда придумали i386 решили схитрить и сделали понятие слова переменным - все инструкции по опкоду как и раньше делятся на то работают они с байтом или со словом, но что такое слово теперь:
    а) выставляется по дефолту в глобальных настройках проца (чисто практически всегда выставляется 32 бита в реальных применениях)
    б) может быть переопределено префиксом, причём префикса два - один изменяет на действие следующей инструкции битность слов между 16/32 для данных, а другой - для адресов.
    В связи с этим один и тот же опкод может сделать mov eax, [ecx+$10] так и mov ax, [ecx+$00000010] так и mov eax, [cx+$0010] смотря какие префиксы перед ним натыкаешь.
    Последний вариант из этих трёх ныне скорее дань бурному, но далёкому прошлому и на практике не применяется по тем же причинам по которым в 64-битном режиме не рекомендуется использовать 32-битную адресацию, только в еще более жёстких рамках.

    Так вот - когда придумывали i86_64, то схалявили еще сильнее и не стали вводить 64-битных смещений. Все режимы адресации с 64-битной базой идут максимум с 32-битным смещением. Только какие то специализированные опкоды mov и jmp могут работать с 64-битным immediate (и оно играет роль не offset, а именно прямого адреса, т.е. это всё идёт мимо блока ModR/M ).
    Поэтому такие ограничения.
    Зато. Зато действительно вместо режима адресации offset без базы (что в i386 было прямым адресом) в i86_64 работает режим относительной адресации относительно IP (RIP=relative ip). offset таким образом становится 32-битным смещением.
    Если память не изменяет к абсолютной адресации вроде бы тоже можно вернуться скомбинировав биты в ModR/M, но она получается охватит только первые 4Гб и в сущности неполноценна, но даже могу ошибаться в том, что она возможна, не помню сейчас точно.
    Замечу что и в режиме i86_64 всегда доступны байтовые смещения - они всё так же ортогонально-равноправны смещениям словами.

    P.S.

    Ах и да - в процессе перехода на i86_64 инженеры еще поняли такую штуку, что по многим причинам желательно работая с 32-битным регистром не сохранять ему верхние 32-бита 64-битного значения, а тупо обнулять. Тогда во первых разрываются зависимости для всякого рода register renaming с одной строны, а с другой более плотный код можно получать по возможности используя 32-битные операнды, но всегда имея ввиду, что их тут же можно начать склонять как 64-битные без знака.

    P.P.S.

    Опять не всё полностью описал - в общем глобальный смысл совершённого при переходе с i86 на i86_64 было то, что размеры immediate внедрённых в уже существовавшие опкоды всё так же сохраняются либо 8 либо 16 либо 32 бита. Под immediate тут понимаются и offset-ы в modR/M и непосредственные данные для загрузки. Поэтому если даже делаешь старый опкод mov eax, $FFFFFFFF с префиксом REX чтобы выйти на 64-битный mov rax, $FFFFFFFF, то это всё равно будут 32 бита непосредственных данных - а вот непосредственные данные уже расширяются в таких случаях со знаком.
     
    Последнее редактирование: 18 фев 2025 в 15:31
    shanya0xff и Mikl___ нравится это.
  4. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    515
    128 бит процессор будет за нашей жизни, господа?
     
  5. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    251
    ..думаю, что нет.
    это как раньше гонялись за частотой, но как упёрлись в потолок 4-5 ГГц оказалось, что лучше добавлять ядра. Пружина хард'эволюции растянулась уже до упора, и теперь будет наоборот сжиматься в обратную сторону, т.е. нужно что-то новое, а 64-бита скалярных + 512 векторных AVX и сейчас хватает с избытком. Ну будут у нас оски весом в пару-тройку терабайт, да 5-гиговый калькулятор - массовому рынку это нах не нужно, и производители это прекрасно понимают.
     
    kol1978 нравится это.
  6. alex_dz

    alex_dz Active Member

    Публикаций:
    0
    Регистрация:
    26 июл 2006
    Сообщения:
    515
    посмотрим... все зависит как быстро хардвер погонит вперед
    вот на днях прочитал что Самсунг уже соорудил планку памяти 1 Террабайт
    пока еклюзив и стоит как паровоз, но все же ...
    на серверных материнках слотов десятки по память, гляди так за пару-тройку лет к Петабайту РАМ-а доберемся :)
    интересно правда зачем....
     
  7. kol1978

    kol1978 Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    31
    Парни всем спасибо за ответы! Просьба, Marylin, alex_dz, alex_dz (и так далее) – пишите строго по теме…очень прошу, мне интересно поговорить – кроме шуток, но в такой смеси трудно что то полезное понять… В СССР был спроектирован и запущен 1000 разрядный процессор, но так как на момент разработки полупроводники отставали и не было возможности создать надёжную интегралку…по итогу в 90х все увезли в США в месте с коробками из под ксерокса. Так что у «них» это все есть и софт для этого может запилить только нейросеть, но это скажем военные компьютеры (задача от военных ссср - переводить на лету вражеско-китайские переговоры), это не для простых «юзеров».
    --- Сообщение объединено, 19 фев 2025 в 05:41 ---
    "leaq message(%rip), %rax ;//<------ RIP relative!!!" -
    давайте с этим поспорю... - это позиционно независимый код и (%rip) просто обычная косвенная адресация от рег. указателя инструкций, эксплуатируется исключительно ОС и её загрузчиком, т.е. (%rip) можно убрать но тогда использовать -no-pie флаг при компиляции (можно наверное несколькими способами – это не суть…)

    Если на х32 память была плоская "Flat" – с этим тоже трудно не спорить… 4 контура защиты (в защищенном режиме – привилегированные инструкции/команды и т.д.) были уже на 386…и то что unix(не каждая) могла использовать только два из них – ядра и пользовательский , это вопрос к ОС (плоская модель памяти) а не к ПЦ… к стати на сколько знаю linux до сих пор может использовать только два из четырёх.

    Откуда этот «Код (Text):» - какая программа? Есть ли она/аналог в linux?
    Можно приводить ссылки на «литературу» на основе которой делается утверждение, или(и) подтверждать цитатой-ссылкой, что бы можно было самому исследовать то о чем вы говорите – это просьба.
    И в целом то что вы говорите об адресации памяти полностью не соответствует моим данным/знаниям – не упомянуты : параграфы, страницы и ссылка на перевод в физический адрес…
     

    Вложения:

  8. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    509
    Для i86 RIP необычен - он присутствует только в ограниченном подмножестве инструкций относительного перехода. В инструкциях же работающих с данных RIP в x86 начисто отсутствует, что заставляет изобретать изощрённые велосипеды с RCALL +4 ... POP EAX чтобы сымитировать RIP.
    А вот в i86_64 без RIP просто никуда - это по сути дефолтный режим работы. Т.к. нет 64-битных immediate/offset-ов, то ситуация становится похожа на реалии RISC-машин где невозможно в одну инструкцию зашить полный адрес. И типичная схема работы выработанная там годами - решать эти вопросы через RIP. Что в x86_64 и было затащено и инструкция с опкодом mov eax, [addr32] из i86 в i86_64 выполнится как mov eax, [rip+offs32]. Потому что нету mov eax, [addr64] и нужно было это как то нивелировать.
    Таким образом position independent code стал в i86_64 дефолтным режимом работы.
     
  9. kol1978

    kol1978 Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    31
    20250219_104455.jpg плохо получается грузить картинки...сори
    Спасибо за ответ! в данном утверждении вижу противоречие..."В связи с этим один и тот же опкод может сделать mov eax, [ecx+$10] так и mov ax, [ecx+$00000010] так и mov eax, [cx+$0010] смотря какие префиксы перед ним натыкаешь." - то же не понятно что вы хотели объяснить. Можно полный пример кода для компиляции/запуска с указанием компилятора...?
    для примера "перфиксов":
    +------------------------------+------------------------------------+
    | Intel код | AT&T код |
    +------------------------------+------------------------------------+
    | mov eax,1 | movl $1,%eax |
    | mov ebx,0ffh | movl $0xff,%ebx |
    | int 80h | int $0x80 |
    | mov ebx, eax | movl %eax, %ebx |
    | mov eax,[ecx] | movl (%ecx),%eax |
    | mov eax,[ebx+3] | movl 3(%ebx),%eax |
    | mov eax,[ebx+20h] | movl 0x20(%ebx),%eax |
    | add eax,[ebx+ecx*2h] | addl (%ebx,%ecx,0x2),%eax |
    | lea eax,[ebx+ecx] | leal (%ebx,%ecx),%eax |
    | sub eax,[ebx+ecx*4h-20h] | subl -0x20(%ebx,%ecx,0x4),%eax |
    +------------------------------+------------------------------------+
    можете перефразировать?

    --- Сообщение объединено, 19 фев 2025 в 06:32 ---
    пример кода с -O0 флагом :
    Код (Text):
    1. square(int):
    2.         push    rbp
    3.         mov     rbp, rsp
    4.         mov     DWORD PTR [rbp-4], edi
    5.         mov     eax, DWORD PTR [rbp-4]
    6.         imul    eax, eax
    7.         pop     rbp
    8.         ret
    пример кода с -Os флагом:
    Код (Text):
    1. square(int):
    2.         imul    edi, edi
    3.         mov     eax, edi
    4.         ret
    код пустышки https://godbolt.org/
    Код (Text):
    1. // Type your code here, or load an example.
    2. int square(int num) {
    3.     return num * num;
    4. }
    можно сказать что - это уровень оптимизации...так что такого рода рассуждения бессмысленны без указания синтаксиса/компилятора и целевой ОС(хоста)...
    --- Сообщение объединено, 19 фев 2025 в 06:33 ---
    и! директива mov "сама по себе" не бывает:
    movq: для копирования 64-разрядных чисел
    movl: для копирования 32-разрядных чисел
    movw: для копирования 16-разрядных чисел
    movb: для копирования 8-разрядных чисел
    так что нужно уточнять синтаксис...
     
  10. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    509
    Я писал статью где всё это и многое другое последовательно излагается: https://wasm.in/threads/principy-ko...x86-64-ili-exal-prefiks-cherez-prefiks.34390/
    Если совсем вкратце, то в опкодах x86 в большинстве случаев зашито с байтом или со словом они работают, но слово понятие плавающее.
    В режиме i386 по умолчанию принято, что слово - это двойное 32-битное слово DWORD.
    Итак, инструкция mov al, $10 всегда может работать только с байтом и это зашито в её опкоде.
    Но инструкция mov eax, $00000010 может быть переключена в 16-битный режим специальным префиксом и тогда начнёт работать как mov ax, $0010 (ессено размер immediate в машкодах надо будет тоже поправить под стать).
    На всё это еще накладываются сложные режимы адресации с вовлечением байта modR/M (и, потенциально, SIB).
    Когда в байте modR/M описывается ячейка памяти, то возможно указание смещения. И опять в байте modR/M описывается какого размера это смещение - байт или слово.
    И опять таки слово в смещении плавающее понятие и по умолчанию в i386 оно есть 32бита, но может быть переключено на 16 бит специальным префиксом.
    Т.е. можно породить инструкцию вида mov eax, [$0010], где $0010 это именно 16-битное смещение/адрес. При этом и регистры в 16-битном адресе становятся 16-битными, т.е. mov eax, [cx+$0010] - с таким префиксом адресовать можно только первые 64Кб адресного пространства, что чушь и поэтому префикс 16-битного адреса никогда на практике не используется (в отличие от префикса 16-битных данных).

    (префикс адреса был намного интереснее когда еще был 16-битный код и хотелось напротив его временно переключить на 32-битные адреса)

    Еще раз хочу напомнить - что байт-данные и байты-смещения не требуют специальных префиксов - эти режимы выбираются прямо в опкоде или байте modR/M. А вот когда речь заходит про слова - тут выбор 16 или 32 бита по умолчанию настроен на 32 бита, но может быть префиксом переопределен на 16 бит.
    Так понятнее?
     
  11. kol1978

    kol1978 Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    31
    PS
    И!
    и!
    ЭТО грёбаный парадокс!
    --- Сообщение объединено, 19 фев 2025 в 07:01 ---
    если коротко то нет не понятно...или что тоже самое идёт полный разрез с моими данными..."И опять таки слово в смещении плавающее понятие" - это откуда взято? смещение всегда в байтах(см. прил картинку)...
    "mov eax, [cx+$0010] - с таким префиксом" - что вы называете "перфиксом"? знак доллара $ что значит в этом выражении(вопрос о синтаксисе уже был; и мною приведён перечень допустимых косвенных адресаций)?
    "интереснее когда еще был 16-битный код" - не стоит про такую древность...и там далеко не так просто - когда ширина шины данных 8бит а адреса 16бит к примеру...
    "байте modR/M" - можно подробнее и на русском? и речь идёт о коде в пользовательском режиме или вообще отвлечённо?
     
  12. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    143
    А когда это в 16-битных адресах стало возможно использование счетчика? Если он и переключается на 16-битную адресацию, то и использоваться могут только базовые да индексные регистры.

    При использовании префиксного байта 0x67 заменяет сам механизм дешифровки байта modr/m и для 16-бит байт sib становится лишним (не возможным).
     
  13. Marylin

    Marylin Active Member

    Публикаций:
    0
    Регистрация:
    17 фев 2023
    Сообщения:
    251
    Ну тогда вам нужно спорить не со мной, а с инженерами Intel.
    Вот цитата по теме из их доков "SDM - Instruction Set Reference"
    Windows тоже использует только 2 из 4-х колец..
    осталось добавить к ним ещё и кольцо(-1) гипервизора. (только не понятно, причём здесь они)

    Это логи отладчика WinDbg
    для линуха не знаю альтернативы и аналогов.

    это немного из другой оперы, поэтому и не были упомянуты.
     
  14. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    509
    А, вот этого я не знал. Это такая экзотика, что на практике не видел вообще ни разу, а то, что сама расшировка modR/M переключается нигде не видел упоминаний. В принципе если задуматься, то логично - чтобы можно было куски 16-битного кода переключением в 16-битный режим прогонять без каких либо изменений. Поэтому по идее логично, да, но никогда об этом не задумывался.

    Тогда лучше всю статью по ссылке выше почитать - оно всё развивалось методичными шагами от архитектуры к архитектуре и при этом желательно понимать как было до, чтобы осознавать почему в следующей итерации принимались такие то решения.
    Нынешний 64-битный режим i86_64 это довольно таки серия компромиссов. По умолчанию вменены 32-битные данные, но 64-битные адреса. Но при этом нет ни непосредственных (вшитых в инструкцию) 64-битных данных ни 64-битных смещений к адресам (тоже вшитых в инструкции). Поэтому с одной стороны по умолчанию вменён RIP, а с другой стороны всякий раз когда мы задействуем 64-битные регистры данных или хотим использовать (даже 32-битные) дополнительные регистры r8...r15 опкод инструкции предваряется байтом-префиксом REX. Поэтому 64-битность достигается небольшим так сказать пенальти на каждую инструкцию. Это еще один плюс в сторону того, что все операции где приёмник 32-битный регистр обнуляют его верхние 32-бита в 64-битном варианте - можно экономить не переключая где можно инструкции в 64 бита.
     
  15. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    143
    Так у Юрова в книге наглядно показаны две таблицы для 16 и 32 битной адресации. Из этого и становится ясно, что идет замещение адресации при переключении через префикс.
     
  16. Mikl___

    Mikl___ Супермодератор Команда форума

    Публикаций:
    14
    Регистрация:
    25 июн 2008
    Сообщения:
    3.900
    Знак $ означает, что число $100 шестнадцатеричное т.е. равно 256
    С/С++/СPascal/DelphiFreeBasicFASMMASM
    hex0xFF$FF&hFF0xFF, $FF, 0FFh0FFh
    dec255255255255255, 255d, 255t
    oct0377&377&o377377o377o, 377q
    bin0b11111111%11111111&b1111111111111111b11111111b,11111111y
     
  17. kol1978

    kol1978 Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    31
    Посмотрел по ссылке - стало понятно почему не понятно... 1 :
    - так не пойдёт...
    2:
    "Так, например команды условного перемещения CMOV — все падают в опкоды $0F 40 — $0F 4F." - здесь у вас "команда"
    "Т.е. инструкция в опкодовой своей части уже могла выглядеть как три байта, например инструкция MOVSS имеет опкод $F3 0F 10 за которым следует байт modR/M." - здесь у вас "инструкция"
    "Так же в i386 появляется большое число всяких новых вспомогательных регистров и инструкций по работе с ними — все они падают в префикс $0F." - здесь у вас слово "перфикс" используется в контексте с "опкодом", а здесь :"Но инструкция mov eax, $00000010 может быть переключена в 16-битный режим специальным префиксом" - перфикс уже в контексте синтаксиса ассемблера...
    "Когда в байте modR/M описывается ячейка памяти, то возможно указание смещения. И опять в байте modR/M описывается какого размера это смещение - байт или слово." - известные мне ассемблеры gas, nasm изолируют от программиста этот уровень трансляции...насколько мне известно - в контексте какого ассемблера об этом идёт речь?
    --- Сообщение объединено, 19 фев 2025 в 08:54 ---
    речь ведь не шла ни о бейсике не о паскале..FASM - вариант один! можно было обойтись без таблицы...? и! тогда в контексте "опкодов" - это не вяжется(желательно пояснить)...
    --- Сообщение объединено, 19 фев 2025 в 08:57 ---
    ps "инструкция в опкодовой своей части уже..." - согласитесь что это "звиздец"....как звучит. в какой части опкод команды???(риторически)
     
  18. aa_dav

    aa_dav Active Member

    Публикаций:
    0
    Регистрация:
    24 дек 2008
    Сообщения:
    509
    Согласен, тут немного неаккуратно написано, но главное что исходя из предыдущего можно понять о чём речь.
    В системе команд i86 уже хрен поймёшь что есть префикс, а что часть опкода - многочисленные расширения и попытки раздвигать горизонты смешали всё в одну большую кашу. То что раньше было префиксом, становится частью опкода (удаления его радикально меняет смысл опкода), то что раньше было опкодами, становится префиксом (как префикс REX - он модифицирует смысл опкода, сильно, но лишь модифицирует, хотя ранее эти байты были опкодами инкремента).
    Там по теме можно еще увидеть VEX, EVEX, REX2, всё попытки эту кашу как то обуздать, причесать и до сих пор происходят новые попытки. Компромисс на компромиссе лишь бы не переделывать декодер команд с нуля. :lol:
    И всё это не имеет никакого отношения к конкретным ассемблерным синтаксисам - это про то как устроен машинный код.
     
  19. kol1978

    kol1978 Member

    Публикаций:
    0
    Регистрация:
    Воскресенье
    Сообщения:
    31
    movq $nums, %rbx # помещаем в RBX адрес переменной nums - к слову про доллар...
    --- Сообщение объединено, 19 фев 2025 в 09:03 ---
    ну как бы это - "такое..." , тема поста : связка Visual C++ 2017 с MASM... все равно СПС!
    --- Сообщение объединено, 19 фев 2025 в 09:22 ---
    Философское отвлечение:
    отсебятина по памяти:
     
  20. MaKsIm

    MaKsIm Active Member

    Публикаций:
    0
    Регистрация:
    11 фев 2008
    Сообщения:
    143
    https://www.club155.ru/x86cmdformats-modrm