Конференция "Прочее" » Передача параметров функции
 
  • SergP © (30.05.16 14:38) [0]
    Допустим у меня есть такая функция с тремя параметрами:
    function Search(count:integer; keyword:int64; var source):integer;

    первый параметр, как я понимаю передается через EAX
    Результат тоже вроде через EAX передается.
    Третий похоже через EDX
    А что со вторым?
    Я не силен в ассемблере, но судя по коду он передается через стек. Если да, то где именно в стеке он находится?
    насколько я понял, то на вершине стека находится адрес возврата (4 байта), а следом за ним параметр, ближе к вершине более младшие его байты. Правильно?

    Т.е. такая функция будет работать?
    (поиск в массиве по полю field. Если надено - возвращается номер элемента массива, если не найдено, то возвращается -1)

    ...
    type TWork=packed record
      field:int64;
      MSet:TMset;
      Probe:Extended;
      end;
    ...
    workarr:packed array of TWork;
    ...
    function Search(count:integer; keyword:int64; var source):integer;
    label
     lbloop, lbcont,lbbreak;
    const
     step=sizeof(TWork);
    asm
           push edx;
           push ecx;
           push ebx;
           mov  ecx,[esp+$10];
           mov  ebx,[esp+$14];
           dec  eax;
    lbloop: cmp  ebx,[edx+$04];
           jnz  lbcont;
           cmp  ecx,[edx];
           jz   lbbreak;
    lbcont: add  edx,step;
           dec  eax;
           jns  lbloop;
    lbbreak:pop  ebx;
           pop  ecx;
           pop  edx;
    end;

  • SergP © (30.05.16 14:50) [1]
    Глянул скомпилированный код.
    Оно там вначале добавило:
    push ebp;    // Зачем делать то, что я не просил?
    mov ebp,esp;
    push ebx;

    и в конце:

    mov eax,ebx; //Зачем оно мне result портит?
    pop ebx;
    pop ebp;
    ret $0008; //что за параметр?
    lea eax,[eax+$00]; //а это вообще что за чудо? или это просто мусор связанный с выравниванием?
  • SergP © (30.05.16 14:53) [2]

    > ret $0008; //что за параметр?


    хотя что это такое вроде понял, если я правильно понял, то это число на которое дополнительно увеличивается ESP после возврата, из-за того что в стеке передавался параметр...
    А вот как насчет всего остального?
  • Rouse_ © (30.05.16 15:14) [3]
    Вот так напиши:

    function Search2(count:integer; keyword:int64; var source):integer;
    const
    step = sizeof(TWork);
    asm
     push eax
     mov  ecx, eax
     mov  edx, [edx]
    @compare:
     mov eax, [esp + 12]
     cmp [edx], eax
     jne @next
     mov eax, [esp + 16]
     cmp [edx + 4], eax
     je @done
    @next:
     add edx, step
     dec ecx
     jnz @compare
     mov ecx, [esp]
     inc ecx
    @done:
     pop eax
     sub eax, ecx
    end;
  • SergP © (30.05.16 15:23) [4]

    >   mov eax, [esp + 12]
    >   cmp [edx], eax
    >   jne @next
    >   mov eax, [esp + 16]
    >   cmp [edx + 4], eax
    >   je @done


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

    lbloop: cmp  eax,[edx+$04];
           jnz  lbcont;
           cmp  ecx,[edx];
           jz   lbbreak;



    Вроде так заработало...:

    function Search(count:integer; keyword:int64; var source):integer;
    label
     lbloop, lbcont,lbbreak;
    const
     step=sizeof(TWork);
    asm
           push edx;
           push ecx;
           mov  ebx,eax;
           mov  ecx,[ebp+$08];
           mov  eax,[ebp+$0C];
           dec  ebx;
    lbloop: cmp  eax,[edx+$04];
           jnz  lbcont;
           cmp  ecx,[edx];
           jz   lbbreak;
    lbcont: add  edx,step;
           dec  ebx;
           jns  lbloop;
    lbbreak:pop  ecx;
           pop  edx;
    end;



    Хотя какие-то странности пока имеются... Но возможно они связаны с другими участками кода.
  • SergP © (30.05.16 15:25) [5]

    > Хотя какие-то странности пока имеются... Но возможно они
    > связаны с другими участками кода.


    А. ну да. понял. я же по массиву вверх иду, а счетчик вниз считает... :)))
  • Rouse_ © (30.05.16 15:28) [6]
    в регистрах? ну тогда вот так:

    function Search2(count:integer; keyword:int64; var source):integer;
    const
    step = sizeof(TWork);
    asm
     push eax
     push esi
     mov  esi, [esp + 16]
     push edi
     mov  edi, [esp + 24]
     mov  ecx, eax
     mov  edx, [edx]
    @compare:
     cmp  [edx], esi
     jne  @next
     cmp  [edx + 4], edi
     je   @done
    @next:
     add  edx, step
     dec  ecx
     jnz  @compare
     mov  ecx, [esp + 8]
     inc  ecx
    @done:
     pop  edi
     pop  esi
     pop  eax
     sub  eax, ecx
    end;
  • Rouse_ © (30.05.16 15:30) [7]
    ну и пример вызова:

    var
     workarr: packed array of TWork;
    begin
     try
       SetLength(workarr, 10);
       workarr[0].field := 456;
       workarr[7].field := $CDB81F21CDB81F20;
       Writeln(Search2(10, $CDB81F21CDB81F20, workarr)); // result must be 7
  • SergP © (30.05.16 16:13) [8]

    >   dec  ecx
    >   jnz  @compare


    и еще вопрос: Вроде для таких вещей можно использовать команду loop, если бы она работала с 32-разрядным регистром.

    Но вот по информации в инете не могу понять: какой все-таки регистр использует команда loop :  CX или ECX?

    например как понять вот это:

    > Команда LOOP уменьшает регистр-счетчик без изменения какого-
    > либо из флагов. Затем проверяются условия характерные для
    > конкретной формы используемой команды LOOP. Если условия
    > удовлетворяются, то происходит короткий переход на метку,
    >  заданную операндом команды LOOP.
    >
    > Если атрибут размера адреса равен 16 бит, то в качестве
    > счетчика используется регистр CX, иначе — ECX.


    Что подразумевается под атрибутом размера адреса?
  • Rouse_ © (30.05.16 16:21) [9]

    > и еще вопрос: Вроде для таких вещей можно использовать команду
    > loop, если бы она работала с 32-разрядным регистром.

    как правило не используют, она по тактам немного проигрывает.


    > Что подразумевается под атрибутом размера адреса?

    Префикс, указывающий с каким размером адресного регистра мы работаем.

    Вот так цикл будет идти 65538 раз
     mov ecx, 65538
    @loop:
     loop @loop


    А вот так только два раза (т.к. в регистр CX будет равен двойке):

     mov ecx, 65538
    @loop:
     db $67 // Address-size override prefix
     loop @loop
  • SergP © (30.05.16 17:08) [10]
    Чем отличаются команды JE от JZ и JNE от JNZ?
  • SergP © (30.05.16 17:19) [11]

    > add  edx, step


    и еще: будет ли LEA edx,[edx+step] в данном случае быстрее?
  • Rouse_ © (30.05.16 17:21) [12]
    Ничем, ну только разве что читабельностью.
    Для булевых операций обычно примеряют E (после test/cmp), для математических (add/sub/inc/dec) Z. В данном случае вычитается единица, и ожидаем результатом ноль, поэтому JNZ (опкоды у этих инструкций идентичные)
  • Rouse_ © (30.05.16 17:22) [13]

    > и еще: будет ли LEA edx,[edx+step] в данном случае быстрее?

    нет, идентичны по тактам будут.
  • SergP © (31.05.16 14:59) [14]
    Почему в случае сабжевого кода (пусть он даже и не совсем верный), компилятор добавлял:

    В начале:
    push ebp;    
    mov ebp,esp;
    push ebx;


    и в конце:
    mov eax,ebx;
    pop ebx;
    pop ebp;
    ret $0008;



    А в случае [6], только

    В начале
    push ebp;    
    mov ebp,esp;



    и в конце:


    pop ebp;
    ret $0008;



    т.е. чем вызвана эта самодеятельность компилятора:
    ...
    push ebx;
    ...
    mov eax,ebx;
    pop ebx;
    ...


    ?
    и как в будущем предугадать такие козни компилятора?
  • dmk © (31.05.16 15:39) [15]
    >т.е. чем вызвана эта самодеятельность компилятора:
    Отладкой. Для Debug Kernel нужно. Точки останова и т.п.
  • dmk © (31.05.16 15:40) [16]
    Можно внешний obj подтянуть без использования ebp, но там точки останова не будут работать.
  • SergP © (31.05.16 16:00) [17]

    > dmk ©   (31.05.16 15:40) [16]
    >
    > Можно внешний obj подтянуть без использования ebp, но там
    > точки останова не будут работать.


    я не про ebp (то что компилятор всегда вставляет - то не страшно), а про то, что он вставляет непонятно когда... Иногда вставляет, а иногда нет.
    Вот это:

    ...
    push ebx;
    ...
    mov eax,ebx;
    pop ebx;
    ...

  • dmk © (31.05.16 16:31) [18]
    Сложно сказать. У меня Delphi XE6 и такого нет. Только BP, EBP, RBP.
    Не нравится — вставляй по старинке obj'екты. Компилируй masm или еще чем.
    Тогда точно будет так как написано.
    Во времена Trubo Pascal и Delphi 3 я так и делал. Вставлял OBJ.

    Кстати проверить еще можно отключив debug.
    Run without Debugging Shitf+ Ctrl + F9.
  • Rouse_ © (31.05.16 16:57) [19]

    > Почему в случае сабжевого кода (пусть он даже и не совсем
    > верный), компилятор добавлял:
    >

    Потому что, по пунктам:

    1.
    В начале
    push ebp;    
    mov ebp,esp;

    и в конце:

    pop ebp;
    ret $0008;


    Это стековый фрейм, он добавляется автоматом при использовании процедурой самого стека (под локальные переменные, под входные параметры).

    2.
    ret $0008
    чистится стек из-за соглашения FASTCALL (в частности нивелируется передача второго параметра через стек)

    3.
    push ebx;
    и в конце:
    mov eax,ebx;
    pop ebx;

    EBX обьектный регистр, который нужно сохранять, видя что ты его используешь, компилер тебя подстраховывает
  • dmk © (31.05.16 17:01) [20]
    >видя что ты его используешь, компилер тебя подстраховывает

    хмм ... у меня нет такого. Не сохранил, получи AV или висяк.
    Где-то в настройках?
  • SergP © (31.05.16 17:03) [21]

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


    Да, я его использовал, но я сам его сохранял при этом.  
    Ну даже пусть он таким образом меня подстраховывает,
    но зачем в конце функции мне портить результат, который был в eax, командой mov eax,ebx ?
  • Rouse_ © (31.05.16 17:05) [22]

    > dmk ©   (31.05.16 17:01) [20]
    > >видя что ты его используешь, компилер тебя подстраховывает
    >
    > хмм ... у меня нет такого. Не сохранил, получи AV или висяк.
    >
    > Где-то в настройках?

    Хм, на ХЕ10 тоже не сгенерировалось, а вчера на домашней (ХЕ4) был такой код
  • Rouse_ © (31.05.16 17:07) [23]

    > SergP ©   (31.05.16 17:03) [21]

    Вариантов много, от ошибки генерации кода (судя по всему) до преднамеренно вставляемой инструкции (доки нужно смотреть)
  • SergP © (31.05.16 17:23) [24]

    > Rouse_ ©   (31.05.16 17:07) [23]
    >
    >
    > > SergP ©   (31.05.16 17:03) [21]
    >
    > Вариантов много, от ошибки генерации кода (судя по всему)
    > до преднамеренно вставляемой инструкции (доки нужно смотреть)


    Но вот в твоем коде [6] оно такого не вставило...

    Получается, что после того как написал что-то на асме, нужно ставить бряк, и в окне CPU-View всегда проверять что там компилятор намутил, и если он сделал мне такой подарок, переписывать код по-другому и снова проверять, и так далее, пока его добавления не перестанут противоречить логике работы моего кода?
  • Rouse_ © (31.05.16 17:24) [25]
    Вполне вероятно что действительно ошибка, сейчас пересмотрел свои исходные коды, там есть у меня всяческие подстраховки плана:

     function GetSPAddrFromPEB(var Len: Integer): Pointer;
     asm
     {$IFDEF WIN32}
       mov edx, FS:[$30]
       movzx ecx, word ptr [edx + $1F0]
       mov [eax], ecx
       mov eax, [edx + $1F4]
     {$ELSE}
       //  mov rdx, GS:[$60]
       // в старых версиях плывет кодогенерация при работе с сегментами
       // поэтому пропишем опкоды напрямую
       DB $65, $48, $8B, $14, $25, $60, $00, $00, 00
       movzx rax, word ptr [rdx + $2E8]
       mov word ptr [rcx], ax
       mov rax, [rdx + $2F0]
     {$ENDIF}
     end;
  • Rouse_ © (31.05.16 17:24) [26]

    > SergP ©   (31.05.16 17:23) [24]
    > Получается, что после того как написал что-то на асме, нужно
    > ставить бряк, и в окне CPU-View всегда проверять что там
    > компилятор намутил, и если он сделал мне такой подарок,
    > переписывать код по-другому и снова проверять, и так далее,
    >  пока его добавления не перестанут противоречить логике
    > работы моего кода?

    Конечно, проверять всегда надо - а как по другому-то?
  • Rouse_ © (31.05.16 17:27) [27]
    Есть другой вариант.
    Оформляй все свои асм блоки как процедуры - тогда получишь чистый код - без пролога и эпилога - тно вызов таких функций нудно контролировать самому
  • Rouse_ © (31.05.16 18:44) [28]

    > dmk ©   (31.05.16 17:01) [20]
    > >видя что ты его используешь, компилер тебя подстраховывает
    >
    > хмм ... у меня нет такого. Не сохранил, получи AV или висяк.
    >


    Да, еще раз перепроверил под ХЕ4

    // пролог
    005B1FD4: 55                                         PUSH EBP
    005B1FD5: 8B EC                                      MOV EBP, ESP
    005B1FD7: 53                                         PUSH EBX

    // тело функции
    005B1FD8: 52                                         PUSH EDX
    005B1FD9: 51                                         PUSH ECX
    005B1FDA: 53                                         PUSH EBX
    005B1FDB: 8B 4C 24 10                                MOV ECX, [ESP+0x10]
    005B1FDF: 8B 5C 24 14                                MOV EBX, [ESP+0x14]
    005B1FE3: 48                                         DEC EAX
    005B1FE4: 3B 5A 04                                   CMP EBX, [EDX+0x4]
    005B1FE7: 75 04                                      JNZ 0x5B1FED
    005B1FE9: 3B 0A                                      CMP ECX, [EDX]
    005B1FEB: 74 06                                      JZ 0x5B1FF3
    005B1FED: 83 C2 16                                   ADD EDX, 0x16
    005B1FF0: 48                                         DEC EAX
    005B1FF1: 79 F1                                      JNS 0x5B1FE4
    005B1FF3: 5B                                         POP EBX
    005B1FF4: 59                                         POP ECX
    005B1FF5: 5A                                         POP EDX

    // эпилог
    005B1FF6: 8B C3                                      MOV EAX, EBX << оть это весьма странно, видимо инициализация результата
    005B1FF8: 5B                                         POP EBX
    005B1FF9: 5D                                         POP EBP
    005B1FFA: C2 08 00                                   RET 0x8



    Здесь явно кривая кодогенерация
  • Rouse_ © (31.05.16 18:46) [29]
    Судя по тому что в ХЕ10 такого не наблюдается - значит был на CodeCentral багрепорт и это было исправлено.
  • Pavia © (31.05.16 23:20) [30]
    1) Читай справку Parameter passing.
    Первые 3 параметра передаются через EAX, EDX, и ECX,  остальные через стек.

    2)

    > push ebp;    // Зачем делать то, что я не просил?

    Это нужно, для отладчика. Принудительно отключается так
    procedure Foo(); registers;
    assemble
    asm
    end;
    Передача параметров через регистры и убираем begin.


    > mov eax,ebx; //Зачем оно мне result портит?

    Он вам портит не resul, а eax.
    result это локальная переменная в стеке.
    При разработке компилятора так проще сделать.


    > и еще вопрос: Вроде для таких вещей можно использовать команду
    > loop, если бы она работала с 32-разрядным регистром.
    >
    > Но вот по информации в инете не могу понять: какой все-таки
    > регистр использует команда loop :  CX или ECX?


    У инструкции, ака мнемоники 'loop' есть несколько кодов. По умолчанию в Delphi идет 32 битный или 64 битный в зависимости от настрое компилятора.
    В старом паскале был 16 битный.

    Для 16 - CX, для 32 , ECX

    Код можно принудительно переключить приставкой.
    Обычно db 66h, но для Loop db 67h

    > Что подразумевается под атрибутом размера адреса?

    Есть несколько приставок основных две приставка изменить_размер_данных и приставка изменить_размер_адреса
    db 66h и db 67h


    > Чем отличаются команды JE от JZ и JNE от JNZ?

    Ничем. Помните про луп, тут обратный случай мнемоники разные, а код один.


    > и еще: будет ли LEA edx,[edx+step] в данном случае быстрее?

    В данном одинаково.


    > ?
    > и как в будущем предугадать такие козни компилятора?

    Алгоритм генерации стековых рамок довольно сложный.

    Вот из RTL паскаля 7, что лежало на 13 дискете.


    *******************************************************
    ; *       *
    ; * MACROS      *
    ; *       *
    ; *******************************************************

    LOCALS @@

    ; Public variable definition macro

    VAR MACRO Symbol,SType,Count
     PUBLIC Symbol
     Symbol LABEL SType
     IF Count
       DB SType * Count DUP(?)
     ENDIF
    ENDM

    ; Parameter definition macro

    ARG MACRO Symbol,SType,Count
     LOCAL Offset
     @AP = @AP + SType * Count
     Offset = @AP
     Symbol EQU (SType PTR [BP+@AF-Offset])
    ENDM

    @AP = 0
    @AF = 0

    ; Local variables definition macro

    LOC MACRO Symbol,SType,Count
     LOCAL Offset
     @LP = @LP + SType * Count
     Offset = @LP
     Symbol EQU (SType PTR [BP+@LF-Offset])
    ENDM

    @LP = 0
    @LF = 0

    ; Stack frame modifiers

    sfFar  EQU 01H  ;FAR frame
    sfMarkBP EQU 02H  ;Make saved BP odd
    sfSaveDS EQU 04H  ;Save DS at [BP-2]
    sfInitDS EQU 08H  ;Init DS using SS

    ; Default stack frame type

    sfDefault = 0

    ; Stack frame types

       IF WindowsVersion
    WINFAR  EQU sfFar+sfMarkBP+sfSaveDS
       ELSE
    WINFAR  EQU sfFar
       ENDIF

    ; Entry code generation macro

    ENTRY MACRO FrameType
     IFB <FrameType>
       @SF = sfDefault
     ELSE
       IFIDNI <FrameType>,<NEAR>
         @SF = 0
       ELSE
         IFIDNI <FrameType>,<FAR>
           @SF = sfFar
         ELSE
           @SF = FrameType
         ENDIF
       ENDIF
     ENDIF
     IF @SF AND sfMarkBP
       INC BP
     ENDIF
     PUSH BP
     MOV BP,SP
     IF @SF AND sfFar
       @AF = @AP + 6
     ELSE
       @AF = @AP + 4
     ENDIF
     IF @SF AND sfSaveDS
       PUSH DS
       @LF = -2
     ELSE
       @LF = 0
     ENDIF
     IF @LP
       SUB SP,@LP
     ENDIF
     IF @SF AND sfInitDS
       PUSH DS
       PUSH SS
       POP DS
     ENDIF
    ENDM

    ; Exit code generation macro

    EXIT MACRO ArgSize
     IF @SF AND sfInitDS
       POP DS
     ENDIF
     IF @LF - @LP
       MOV SP,BP
     ENDIF
     POP BP
     IF @SF AND sfMarkBP
       DEC BP
     ENDIF
     IFNB <ArgSize>
       @AP = ArgSize
     ENDIF
     IF @SF AND sfFar
       RETF @AP
     ELSE
       RETN @AP
     ENDIF
     @AP = 0
     @LP = 0
    ENDM

  • Rouse_ © (31.05.16 23:46) [31]
    Эммм...
    Pavia, знаешь чем теория отличается от практики? :)

    Зы: а так в принципе... Ну ты старался :)
  • Pavia © (01.06.16 08:53) [32]

    > Pavia, знаешь чем теория отличается от практики? :)

    Знаю.

    Просто вчера не смог вспомнить где лежит нужная теория. Сегодня вспомнил.
    Полная теория лежит в бумажном руководстве пользователя, а не в хелпе.


    > Да, я его использовал, но я сам его сохранял при этом.  
    >
    > Ну даже пусть он таким образом меня подстраховывает,
    > но зачем в конце функции мне портить результат, который
    > был в eax, командой mov eax,ebx ?

    Да это косяк компилятора. Но программист виноват не меньше.

    Assembly procedures and functions


    > Unless a function returns a string, variant, or interface
    > reference, the compiler doesn't allocate a function result
    > variable; a reference to the @Result symbol is an error.
    >  For strings, variants, and interfaces, the caller always
    > allocates an @Result pointer.
    >


    Пока вы в тексте  не напишете @Result компилятор думает, что его нет.
    По идее он должен был выкинуть mov eax, ebx. Но не выкинул.

    Так что пишите         mov @Result,eax и будет всё тип топ.
  • Pavia © (01.06.16 09:03) [33]
    Сейчас свой кодогенератор делаю. Так вот теории нету! Не понятно как гарантировать его безошибочность.
    Пока что остановился на следующим пишу частные случае потом буду обобщать на общие. А после тестировать. Но как известно тестирование не гарантирует, что не будет ошибок. Особенно тут с неизвестной выходной функцией.
  • Rouse_ © (01.06.16 10:36) [34]
    Ну тогда у тебя не правильные выводы, практически все.
    Я не знаю где ты такую документацию читал


    > Первые 3 параметра передаются через EAX, EDX, и ECX,  остальные
    > через стек.

    не верно, если параметр не влазит в регистр он идет принудительно через стек


    > Это нужно, для отладчика.

    не верно. Отладчику на это сугубо фиолетово, да и программа как правильно работает без отладчика. Это нужно для локальных переменных и параметров.


    > Принудительно отключается так
    > procedure Foo(); registers;
    > assemble
    > asm
    > end;


    не верно.

    procedure Foo(); register; assembler;
    var
     Tst: DWORD;
    asm
     mov eax, 10
     mov Tst, eax
    end;


    выдаст вот такой код:

    004184AC: 55                                         PUSH EBP
    004184AD: 8B EC                                      MOV EBP, ESP
    004184AF: 51                                         PUSH ECX
    004184B0: B8 0A 00 00 00                             MOV EAX, 0xA
    004184B5: 89 45 FC                                   MOV [EBP-0x4], EAX
    004184B8: 59                                         POP ECX
    004184B9: 5D                                         POP EBP
    004184BA: C3                                         RET




    > Он вам портит не resul, а eax.
    > result это локальная переменная в стеке.

    не верно, в данном случае Result это именно EAX, а не какая-то переменная на стеке (при чем тут вообще стек)


    > Код можно принудительно переключить приставкой.
    > Обычно db 66h, но для Loop db 67h


    не верно, префикс 0х66 т.н. OperandSizeOverride используется для модификации инструкции (insw->insd/iret->iretd и т.п.) а для модификации регистров используется префикс AddressSizeOverride = $67

    вот полный список префиксов:

    // служебные префиксы
    // см. "2.2. SUMMARY OF INSTRUCTION PREFIXES"
    // =============================================================================
    type
     TPrefixData = record
       Value: Integer;
       Description: string;
     end;

    const
     // Lock and repeat prefixes:
     pfxLock = $F0;
     // The LOCK prefix can be prepended only to the following instructions and only to those forms
     // of the instructions where the destination operand is a memory operand: ADD, ADC, AND,
     // BTC, BTR, BTS, CMPXCHG, CMPXCH8B, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR,
     // XADD, and XCHG

     pfxRepn = $F2;
     pfxRep = $F3;

     // Segment override prefixes:
     pfxCSSegmentOverride = $2E;
     pfxSSSegmentOverride = $36;
     pfxDSSegmentOverride = $3E;
     pfxESSegmentOverride = $26;
     pfxFSSegmentOverride = $64;
     pfxGSSegmentOverride = $65;

     // Operand-size override prefix
     // (when used with the escape opcode 0FH, this
     // is treated as a mandatory prefix for some SIMD instructions)
     pfxOperandSizeOverride = $66;
     pfxEscapeOpcode = $0F;

     // Address-size override prefix
     pfxAddressSizeOverride = $67;

     pfxFPU_BFHTRange = $BF;
     pfxFPUOpcodeRange = [$D8..$DF];

     Prefixes: array [0..8] of TPrefixData = (
      (Value: pfxLock; Description: 'lock'),
      (Value: pfxRepn; Description: 'repn'),
      (Value: pfxRep; Description: 'rep'),
      (Value: pfxCSSegmentOverride; Description: 'cs:'),
      (Value: pfxSSSegmentOverride; Description: 'ss:'),
      (Value: pfxDSSegmentOverride; Description: 'ds:'),
      (Value: pfxESSegmentOverride; Description: 'es:'),
      (Value: pfxFSSegmentOverride; Description: 'fs:'),
      (Value: pfxGSSegmentOverride; Description: 'gs:')
     );




    > Алгоритм генерации стековых рамок довольно сложный.

    не верно - размер стекового фрейма равен общему размеру используемых локальных переменных и передаваемых через стек параметров. ничего секретного и сложного в этом нет.


    > Так что пишите         mov @Result,eax и будет всё тип топ.

    и получишь на выходе замечательную но бессмысленную инструкцию
    MOV EAX, EAX

    Вот как-то так вкратце.
  • Игорь Шевченко © (01.06.16 12:05) [35]
  • SergP © (01.06.16 15:01) [36]

    > У инструкции, ака мнемоники 'loop' есть несколько кодов.
    >  По умолчанию в Delphi идет 32 битный или 64 битный в зависимости
    > от настрое компилятора.
    > В старом паскале был 16 битный.
    >
    > Для 16 - CX, для 32 , ECX
    >
    > Код можно принудительно переключить приставкой.
    > Обычно db 66h, но для Loop db 67h


    Так это приставка действует только на следующую за ней команду loop или переключает глобально?
    И почему через db? Ей, что, забыли придумать отдельную мнемонику?
  • Rouse_ © (01.06.16 15:27) [37]

    >
    > Так это приставка действует только на следующую за ней команду
    > loop или переключает глобально?

    да, это префикс для идущей за ней инструкции, модифицирующий ее поведение по умолчанию


    > И почему через db? Ей, что, забыли придумать отдельную мнемонику?

    может и есть, но я не в курсе. (может какой нить "short loop" или еще как нибудь)
  • Pavia © (01.06.16 16:18) [38]

    > Так это приставка действует только на следующую за ней команду
    > loop или переключает глобально?
    > И почему через db? Ей, что, забыли придумать отдельную мнемонику?
    >

    Да, только на следующую. Для приставки отдельную мнемонику не стали делать. Обычно используется PTR или суффикс d, но вот loop это исключение. Интел толком не описывал. Сейчас вроде придерживатся борладского стиля. Но для каждого компилятора надо выяснять отдельно.


    > The loop instructions for the 80386 processor can either
    > use CX or ECX as the counting
    > register. The standard LOOP, LOOPE, LOOPZ, LOOPNE, and LOOPNZ
    > mnemonics
    > from Intel select the counting register based on whether
    > the current code segment is a 32-bit segment (when using
    > ECX) or a 16-bit segment (when using CX).
    > Turbo Assembler has special instructions that increase the
    > flexibility of the LOOP
    > feature. The LOOPW, LOOPWE, LOOPWZ, LOOPWNE, and LOOPWNZ
    > instructions
    > use CX as the counting register, regardless of the size
    > of the current segment. Similarly, the LOOPD, LOOPDE, LOOPDZ,
    >  LOOPDNE, and LOOPDNZ instructions use ECX as the counting
    > register
  • Pavia © (01.06.16 16:41) [39]

    > > Это нужно, для отладчика.
    >
    > не верно. Отладчику на это сугубо фиолетово, да и программа
    > как правильно работает без отладчика. Это нужно для локальных
    > переменных и параметров.

    Отладчику не всё равно! Смотри скриншот. XE5 Настройки стандартные.
    http://s33.postimg.org/p7tfcr7jj/image.png
  • Rouse_ © (01.06.16 16:59) [40]

    > Pavia ©   (01.06.16 16:41) [39]

    Ну так это же настройки компилятора, а не отладчика :)
  • Pavia © (01.06.16 16:59) [41]

    > > Код можно принудительно переключить приставкой.
    > > Обычно db 66h, но для Loop db 67h
    >
    >
    > не верно, префикс 0х66 т.н. OperandSizeOverride используется
    > для модификации инструкции (insw->insd/iret->iretd и т.п.
    > ) а для модификации регистров используется префикс AddressSizeOverride
    > = $67

    Тут ты ошибаешься. Смотри маны. Loop относится к группе строковых инструкций. Поэтому для него, не как у других инструкций.
    Смотри маны:
    https://docviewer.yandex.ru/?url=ya-disk-public%3A%2F%2Fks8F6OS9JWdJWsURii23TBL%2F3QETut6hh5lPpMKMQfE%3D&name=253666.pdf&page=644&c=574ee91d863a


    IF (AddressSize = 32)
       THEN Count is ECX;
    ELSE IF (AddressSize = 64)
       Count is RCX;
    ELSE Count is CX;
    FI;

  • Rouse_ © (01.06.16 17:08) [42]

    > Поэтому для него, не как у других инструкций.

    ничего не понял, ты хочешь сказать что для других инструкций префикс 0x67 не используется, только для LOOP? :)
  • Pavia © (01.06.16 17:15) [43]

    > ничего не понял, ты хочешь сказать что для других инструкций
    > префикс 0x67 не используется, только для LOOP? :)

    Я хочу сказать, что у Loop'а ECX это не регистр, а адрес!
    Поэтому вместо db 66h надо использовать db 67h.

    Обычные инструкции:
    "pop cx"
    "popd ecx" = "db 66h pop cx"

    У лупа
    "loop cx"
    "loopd ecx" = "db 67h loop cx"
  • Rouse_ © (01.06.16 17:30) [44]

    >
    > Я хочу сказать, что у Loop'а ECX это не регистр, а адрес!
    >

    Не, там работает все немного по другому, 67 указывает что нужно сверятся с регистром CX, а 66 указывает что переход будет идти на младшую часть рассчитываемого адреса, к примеру:

    66E2E5         loop $005b1fe4

    здесь прыжок произойдет не на адрес 005b1fe4 а на адрес 00001fe4
  • SergP © (02.06.16 13:07) [45]

    > Потому что, по пунктам:
    >
    > 1.
    >  
    > В начале
    > push ebp;    
    > mov ebp,esp;
    >  
    > и в конце:
    >  
    > pop ebp;
    > ret $0008;
    >
    >
    > Это стековый фрейм, он добавляется автоматом при использовании
    > процедурой самого стека (под локальные переменные, под входные
    > параметры).
    >
    > 2.
    >  
    > ret $0008
    >
    > чистится стек из-за соглашения FASTCALL (в частности нивелируется
    > передача второго параметра через стек)
    >
    > 3.
    >  
    > push ebx;
    > и в конце:
    > mov eax,ebx;
    > pop ebx;
    >
    > EBX обьектный регистр, который нужно сохранять, видя что
    > ты его используешь, компилер тебя подстраховывает
    >


    Чего же тогда тут компилятор не хочет меня подстраховывать, и вообще не проявляет никакой самодеятельности?

    procedure rave;
    asm
     mov ebp,ecx
     mov ebx,edx
    end;



    Этот бред так и компилируется:
     mov ebp,ecx
     mov ebx,edx
     ret


    и больше ничего.
  • Rouse_ © (02.06.16 13:19) [46]
    ну вот такой компилятор :)
  • DayGaykin © (02.06.16 13:26) [47]
    А можно вкратце, раз уж тема зашла, какие еще регистры нужно сохранять? И в 64 битах.
  • Rouse_ © (02.06.16 15:44) [48]

    > DayGaykin ©   (02.06.16 13:26) [47]
    > А можно вкратце, раз уж тема зашла, какие еще регистры нужно
    > сохранять? И в 64 битах.

    32: EBX, EPB, ESP, EDI, ESI
    64: RBX, RBP, RSP, RDI, RSI, R12-R15
  • SergP © (02.06.16 16:15) [49]
    Вот ради прикола попробовал написать такую функцию:

    function btc(var num:int64):byte;
    asm
     push eax
     mov ecx,[eax]
     mov al,-2
     call @continue
     pop ecx
     mov ecx,[ecx+4]
    @continue:
     lea edx,[ecx-1]
     inc al
     or ecx,edx
     jnz @continue
    end;



    Компилятор на этот раз ничего от себя не добавил.
    В стеке ничего не передается. Поэтому в конце компилятор ставит просто ret

    Но эта штука почему-то виснет. И под отладчиком тоже виснет на call @continue
    Почему?
  • SergP © (02.06.16 16:28) [50]
    Мда. уже нашел где я протупил
  • dmk © (02.06.16 20:10) [51]
    jmp @@continue

    @@continue:
  • SergP © (02.06.16 21:08) [52]

    > dmk ©   (02.06.16 20:10) [51]
    >
    > jmp @@continue
    >
    > @@continue:


    Не. Call @continue - это было так задумано.
    Просто дальше получился бесконечный цикл, а отладчик видимо пошагово показывает результаты выполнения команд только то что до Call. А при Call похоже что шагом считает всю подпрограмму пока из нее не выйдет по ret

    Вот переписал так:
    // Вычисление кол-ва единичных бит в 64-разрядном числе, для случаев
    // когда среднестатистическое их количество невелико.
    function btc(var num:int64):byte;
    asm
         push eax
         mov ecx,[eax]
         xor eax,eax
         call @cnt32
         pop ecx
         mov ecx,[ecx+4]
    @cnt32:
         or ecx,ecx
         jz  @exit
    @continue:
         inc eax
         lea edx,[ecx-1]
         and ecx,edx
         jnz @continue
    @exit:
    end;



    Теперь работает.
  • dmk © (02.06.16 23:12) [53]
    Хмм, а не проще считать так?
    Зачем Вам цикл такой?

    function NumBits(v: int64): int64;
    asm
     popcnt rax, v
    end;

    procedure TForm3.ButtonClick(Sender: TObject);
    var
     v: int64;
     bc: int64;

    begin
     v := 48756000; //Кол-во бит
     bc := NumBits(v);
     ShowMessage('Кол-во бит в числе ' + IntToStr(v) + ' = ' + IntToStr(bc));
    end;
  • SergP © (03.06.16 03:52) [54]

    > dmk ©   (02.06.16 23:12) [53]
    >
    > Зачем Вам цикл такой?
    >


    1. В [52] просто интересно было как отнесется компилятор к дерганию процедурой\функцией своего же хвоста. Хотя можно обойтись (и даже быстрее было бы)  без этого.
    2.  метод [52] далеко не самый лучший, но он не так уж и плох в случаях, когда приходится обрабатывать большое кол-во данных, где заранее известно, что среднее количество единичных бит в числе не большое. Например 5-8.
    3.

    >  Хмм, а не проще считать так?
    >  function NumBits(v: int64): int64;
    >  asm
    >   popcnt rax, v
    >  end;


    И как будет работать такая функция, если вдруг процессор не поддерживает SSE4?
  • dmk © (03.06.16 12:47) [55]
    Пишите функции-переменные с пометкой overload. При инициализации проверяете на поддержку и грузите нужную переменную. Вашу старую или SSE4.2

    type TNumBits = function(v: uint64): byte;

    var
     NumBits: TNumBits;

    //Bit20 A value of 1 indicates that the processor supports SSE4.2
    function CPU_SupportSSE42: boolean;
    asm
     mov rax, $01
     cpuid
     xor rax, rax //result := false
     test ecx, 00100000h //тестируем 20-й бит
     jz @NOSSE42
     inc rax //result := true
     @NOSSE42:
    end;

    SSE42 Давно уже существует. Большинство современных процессоров этот набор поддерживает. У Intel начиная с Core2DUO, Core2QUAD; У AMD только начиная с Buldozer FX.
  • Rouse_ © (03.06.16 13:06) [56]

    > dmk ©   (03.06.16 12:47) [55]

    тогда уж:
    function CPU_SupportSSE42: Boolean;
    asm
     mov eax, 1
     cpuid
     test ecx, 00100000h
     setne al
    end;
  • dmk © (03.06.16 13:44) [57]
    У меня получилось так:


    function NumBitsX86(v: uint64): byte;
    asm
     mov rdx, v
     bswap rdx
     mov rcx, 64
     xor rax, rax

    @@NB:
     xor r8b, r8b
     shld r8, rdx, 1
     shl rdx, 1
     add al, r8b
     dec rcx
     jnz @@NB
    end;

    function NumBitsSSE42(v: uint64): byte;
    asm
     popcnt rax, v
    end;

    Initialization

     if CPU_SupportSSE42 then
       NumBits := NumBitsSSE42 else
       NumBits := NumBitsX86;


  • dmk © (03.06.16 13:44) [58]
    Rouse_ ©   (03.06.16 13:06) [56]

    Спасибо! Будем знать ;)
  • SergP © (03.06.16 13:49) [59]
    Кстати, в какой версии Delphi встроенный ассемблер поддерживает мнемоники SSE4.2?
  • dmk © (03.06.16 13:53) [60]
    >SergP ©   (03.06.16 13:49) [59]
    Delphi 2010 and XE support up to the SSE4.2 instruction sets
  • dmk © (03.06.16 13:59) [61]
    Rouse_ ©   (03.06.16 13:06) [56]
    А как пользоваться SintaxHighlighter ? Не пойму никак )
  • NoUser © (03.06.16 15:08) [62]
    > dmk ©   (03.06.16 13:59) [61]
    кнопочка "D" ))

    Rouse_ , коль пошла такая пьянка, расскажи о выравнивании стека перед CALL -
    как правильно, нужно/не нужно, насколько критично, сколько резервировать для регистровых параметров, сразу 20h или ?
    Спасибо.
  • Rouse_ © (03.06.16 15:23) [63]

    > NoUser ©   (03.06.16 15:08) [62]

    в 64 битах стек должен быть выравнен по 16 байтной границе, требуется резервирование стека под дополнительные 4 64-битных параметра (даже если в этом нет необходимости - так написано в документации)


    > Вызывающая функция отвечает за выделение пространства для
    > параметров вызываемой функции и должна всегда выделять достаточное
    > пространство для 4 параметров, даже если вызываемая функция
    > не содержит такого количества параметров. Это помогает упростить
    > поддержку функций без прототипов и функций с переменным
    > количеством аргументов (vararg) C/C++. Для функций с переменным
    > количеством аргументов или для функций без прототипов любое
    > значение типа float должно быть продублировано в соответствующем
    > регистре общего назначения. Любые параметры, следующие после
    > первых 4, до вызова должны сохраняться в стеке над резервным
    > хранилищем для первых четырех. Сведения о функции с переменным
    > количеством аргументов представлены в разделе Функции с
    > переменным количеством аргументов (Varargs). Сведения о
    > функции без прототипов представлены в разделе Функции без
    > прототипа.
    > Выравнивание
    >
    > Большинство структур выровнены естественным выравниванием.
    >  Главными исключениями являются указатели стека и функции
    > распределения памяти malloc или alloca, которые выровнены
    > на 16 байт для сохранения производительности. Выравнивание
    > свыше 16 байт должно выполняться вручную, но начиная с 16
    > байт выполняется общее выравнивание размера для операций
    > XMM, которого должно хватать для большей части кода. Дополнительные
    > сведения о структуре и выравнивании см. в разделе Типы и
    > хранилище. Дополнительные сведения о стеке см. в разделе
    > Использование стека.
  • SergP © (03.06.16 16:08) [64]
    Ну и тогда еще несколько вопросов:
    Если допустим я захочу полностью переписать процедуру/функцию на ассемблере:
    1. Как работать с глобальными переменными?
    2. Как функция должна возвращать результат, если например это запись?
    3. Если мне понадобится память для локальных переменных: как лучше делать:
    не описывать переменные в секуии var, а просто уменьшать указатель стека на нужную величину, использовать этот кусок памяти, а перед выходом возвращать указатель стека в исходное состояние? или как-то по другому?
    4. Если у меня WinXP, то использовать 64-битные РОН (rax, rbx....) я не могу?
  • dmk © (03.06.16 16:36) [65]
    1. mov rax, GlobalVar
    2.

    TSomeType = record
     private
     public
       function InRangeX(x: integer): boolean;
     end;



    3. Как нравится.
    4. Можешь, только передачу параметров свою делать надо. Например, через указатель.
  • Rouse_ © (03.06.16 16:40) [66]

    > Как работать с глобальными переменными?

    как обычно. вместо:
    MyGlobalVar := 123
    пиши

    lea eax, MyGlobalVar
    mov [eax], 123



    > Как функция должна возвращать результат, если например это
    > запись?

    структуры возвращаются по ссылке


    > 3. Если мне понадобится память для локальных переменных:

    лучше объяви их в секции var, компилятор сам добавит код под выделение памяти


    > 4. Если у меня WinXP, то использовать 64-битные РОН (rax,
    >  rbx....) я не могу?

    регистры RAX и т.п. ты можешь использовать только в 64 битном коде, соответственно только под 64 битной ОС
  • dmk © (03.06.16 18:26) [67]
    >регистры RAX и т.п. ты можешь использовать только в 64 битном коде, соответственно
    >только под 64 битной ОС

    Странно, mmx разве не относится к 64 битам? В D7 раньше байт коды были. Использовал в 32 битном коде.
  • Rouse_ © (03.06.16 19:41) [68]
    Это разные вещи
  • SergP © (04.06.16 09:56) [69]

    > > Как функция должна возвращать результат, если например
    > это
    > > запись?
    >
    > структуры возвращаются по ссылке


    А где выделяется память под это дело? И кто ее выделяет?
    Вызываемая функция или вызывающая процедура/функция?
    Т.е. Кто кому передает эту ссылку?
  • Игорь Шевченко © (04.06.16 10:35) [70]
    SergP ©   (03.06.16 16:08) [64]


    > Ну и тогда еще несколько вопросов:


    Рано тебе их задавать. Матчасть надо учить и не по форумам.
  • Inovet © (04.06.16 12:10) [71]
    > [64] SergP ©   (03.06.16 16:08)

    Сделай для эксперимента на ASM и приликуй к основному модулю - это поубавит вопросов.
  • Inovet © (04.06.16 12:12) [72]
    Правильно. Самостоятельно это сделай.
  • SergP © (04.06.16 13:25) [73]

    > Inovet ©   (04.06.16 12:12) [72]
    >
    > Правильно. Самостоятельно это сделай.


    С тем, что меня интересовало уже разобрался.

    Но вот просто разбираться приходится по коду в окне CPU-View, а там читабельность низкая, навигация неудобная, да и самая большая проблема в том, что это все нельзя сбросить в текстовый файл.

    Ну и кроме того там полно откровенного бреда. Конечно, когда пытаешься мыслить с точки зрения компилятора, то вроде понятно почему он сделал так. Но с точки зрения человека это бред...

    Вот, например, один из перлов компилятора:
     ...if (num and 1) <>0 then
     mov eax,[ebp+$08]
     mov edx,[ebp+$0c]
     and eax,$00000001
     xor edx,edx
     cmp edx,$00
     jnz +$03
     cmp eax,$00
     jz +$06

  • Inovet © (04.06.16 18:59) [74]
    > [73] SergP ©   (04.06.16 13:25)
    > да и самая большая проблема в том, что это все нельзя сбросить
    > в текстовый файл.

    Для этого есть реверсинженеринговые штуки, наподобие дизассемблеров.
  • Inovet © (04.06.16 19:15) [75]
    > [73] SergP ©   (04.06.16 13:25)
    > Вот, например, один из перлов компилятора:

    Ну это может быть в дебаг сборке такое?
  • Inovet © (04.06.16 19:18) [76]
    > [74] Inovet ©   (04.06.16 18:59)
    > реверсинженеринговые

    Да, на всякий случай, в Си есть опция компилятора, при включении которой, компилятор сначала в текстовый АСМ генерит, потм уже Амсом компилит.
  • Inovet © (05.06.16 00:28) [77]
    Розыч, неужели и ты заразился словом "прыжок"? Ну плохо оно звучит для русского слуха. Есть же нормальное слово "переход". Прыжок, млин. Я, может быть, на соответствующих тематческих форумах не бываю, но осуждаю. Какой нафиг прыжок.

    Подпишусь - Ваш Граммар Наци. Давайте не будем использовать настолько тупые кальки.
  • Германн © (05.06.16 01:37) [78]

    > Игорь Шевченко ©   (04.06.16 10:35) [70]
    >
    > SergP ©   (03.06.16 16:08) [64]
    >
    >
    > > Ну и тогда еще несколько вопросов:
    >
    >
    > Рано тебе их задавать. Матчасть надо учить и не по форумам.
    >

    Вот какой смысл у этого поста?
  • Crysis © (05.06.16 08:21) [79]
    > первый параметр, как я понимаю передается через EAX
    > Результат тоже вроде через EAX передается.
    > Третий похоже через EDX
    > А что со вторым?


    Int64 передаётся через стек

    > push ebp;    // Зачем делать то, что я не просил?
    > mov ebp,esp;
    > push ebx;
    > pop ebp;
    > ret $0008; //что за параметр?


    Это особенность компилятора Delphi. Если есть стековые переменные в функции или секции var - Delphi делает префикс/постфикс и обращается к переменным через ebp. Если объявишь keyword через var - то указатель на него передастся через EDX, а третий параметр будет ECX.
  • Игорь Шевченко © (05.06.16 10:28) [80]

    > Ну и кроме того там полно откровенного бреда. Конечно, когда
    > пытаешься мыслить с точки зрения компилятора, то вроде понятно
    > почему он сделал так. Но с точки зрения человека это бред.
    > ..


    С точки зрения необразованного человека.
  • Pavia © (05.06.16 11:56) [81]

    > Розыч, неужели и ты заразился словом "прыжок"? Ну плохо
    > оно звучит для русского слуха. Есть же нормальное слово
    > "переход". Прыжок, млин. Я, может быть, на соответствующих
    > тематческих форумах не бываю, но осуждаю. Какой ... прыжок.
    >
    >
    > Подпишусь - Ваш Граммар Наци. Давайте не будем использовать
    > настолько тупые кальки.

    Прыжок, скачок звучат плохо, только по тому, что их редко используют. Чаще используют идти, сходить. Сходить в магазин.

    Но по смыслу вернее скачок. А не переход. Переход это процесс растянутой во времени. А прыжок он моментальный. И в данном случае я склоняюсь к прыжкам.

    Что касается выбора слов. То при написание текста надо понимать на кого он рассчитан: на серую массу али на профессионалов. Для популярности стоит спускаться до уровня серой массы. А вот для профессионалов лучше использовать более правильные термины.

    PS. Pavia, ушел за хлебом.
  • Rouse_ © (05.06.16 13:24) [82]

    > А где выделяется память под это дело? И кто ее выделяет?

    кто хранит, от и выделяет.

    к примеру:

    var
     P: TPoint;
    begin
     P := Point(10, 10);


    память под локальную P выделяется вызываемой функцией на стеке.


    > Inovet ©   (05.06.16 00:28) [77]
    > Розыч, неужели и ты заразился словом "прыжок"? Ну плохо
    > оно звучит для русского слуха.

    Нормально звучит, переход он рядом с светофором на зебре :)
  • Inovet © (05.06.16 13:40) [83]
    > [81] Pavia ©   (05.06.16 11:56)
    > Но по смыслу вернее скачок. А не переход. Переход это процесс
    > растянутой во времени. А прыжок он моментальный. И в данном
    > случае я склоняюсь к прыжкам.


    > [82] Rouse_ ©   (05.06.16 13:24)
    > Нормально звучит, переход он рядом с светофором на зебре
    > :)

    Я не буду здесь разводить дисскуссию насчёт серой массы и лингвистики, поскольку я в этом деле не понимаю ничего. Своё мнение высказал.

    Ещё в догонку насчёт серой массы. Когда корейская компания производитьль лапши Доширак выходила на российский рынок, ей рекомендовали сменить имя с оригинального Досирак на Доширак, иначе с таким именем будет тяжело продвигаться в русскоговорящей среде. Вот и "прыжок" оттуда же, только в контексте программирования. В другом контексте в естественном окружениии слов он нормально звучит.
  • Inovet © (05.06.16 13:45) [84]
    Или ещё один пример из физики, тут уж точно прыжок, природа так устроена - quantum jump. Но я ни разу не видел в русском тексте другого термина, кроме квантовый переход. Я, конечно, мало читал физической литератры, но тем не менее физики при всё сложности этой науки, обладают чувством стиля.
  • Inovet © (05.06.16 14:00) [85]
    Лучше уж сказать "джамп на лейбл" - оно по программистски и снелгово, и понятно, и вкусно.
  • Inovet © (05.06.16 14:00) [86]
    > [85] Inovet ©   (05.06.16 14:00)
    > снелгово

    сленгово
  • Rouse_ © (05.06.16 15:25) [87]
    Да какая разница? JUMP им и останется (зы: сериал смотрел - квантовый прыжок? :)
  • Inovet © (05.06.16 15:30) [88]
    > [87] Rouse_ ©   (05.06.16 15:25)
    > зы: сериал смотрел - квантовый прыжок?

    Нет.:) Это для серой массы?:)
  • Inovet © (05.06.16 15:35) [89]
    Нашёл в Вики
    доктор Сэмуэль Беккет на базе в пустынях Нью-Мексико (США) возглавил сверхсекретный проект, названный «Квантовый скачок».

    Нью-Мексико - кто бы сомневался. И "Скачёк", однако - что тоже не лучше.:)
  • Inovet © (05.06.16 15:44) [90]
    > [89] Inovet ©   (05.06.16 15:35)
    > "Скачёк",

    Эээ, да, ти русский язык знаешь, да.
    Скачок.
  • Юрий Зотов © (05.06.16 17:23) [91]
    >  "джамп на лейбл" - оно по программистски

    Если по-программистски, то не "лейбл", а "лейбак".
  • Inovet © (05.06.16 20:08) [92]
    > [91] Юрий Зотов ©   (05.06.16 17:23)
    > "лейбак"

    Думал, осмысливал, но не очень вкурил смысл. "Лебка" типа?
  • SergP © (05.06.16 22:07) [93]

    >
    > кто хранит, от и выделяет.
    >
    > к примеру:
    >  
    > var
    >   P: TPoint;
    > begin
    >   P := Point(10, 10);
    >
    >
    > память под локальную P выделяется вызываемой функцией на
    > стеке.


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

    > begin
    >   Point(10, 10);

    это после [72] только решил сам глянуть и увидел, что хоть результат нам не нужен и переменная не описана, все равно под это вызывающая процедура\функция выделяет место в стеке.


    > Есть же нормальное слово "переход". Прыжок, млин. Я, может
    > быть, на соответствующих тематческих форумах не бываю, но
    > осуждаю. Какой нафиг прыжок.


    Почему? Вроде оба термина, когда сами по себе: и переход и прыжок - нормально воспринимаются.
    Хотя в словосочетаниях, например "условный переход" и "условный прыжок" я бы отдал предпочтение первому.
  • SergP © (05.06.16 23:18) [94]

    >  Inovet ©   (04.06.16 19:15) [75]
    >
    > > [73] SergP ©   (04.06.16 13:25)
    > > Вот, например, один из перлов компилятора:
    >
    > Ну это может быть в дебаг сборке такое?


    Не. Это не связано с дебагом. просто num типа int64
    ...if (num and 1) <>0 then
    mov eax,[ebp+$08]
    mov edx,[ebp+$0c]
    and eax,$00000001
    xor edx,edx
    cmp edx,$00
    jnz +$03
    cmp eax,$00
    jz +$06



    Но стоит вместо if (num and 1) <>0 написать if odd(num), как весь бред исчезает и код становится приличным:
    ... if odd(num) then
    mov eax,[ebp+$08]
    test al, $01
    jz +$06

  • Германн © (06.06.16 01:38) [95]

    > просто num типа int64

    Что-то мне это напоминает. :)
    Но Розыч опять скажет что это всё правильно.
  • dmk © (06.06.16 08:24) [96]
    SergP ©   (05.06.16 23:18) [94]
    Разработчики компилятора тебе бы сказали: напиши свой - правильный :)

    А вообще если 32 битный режим, то все логично. Переходи на 64 бита. Там в коде все намного лаконичней и проще (даже в ассемблере), а в 32-битном приходится извращаться и разбивать 64 бита на 2 регистра.
 
Конференция "Прочее" » Передача параметров функции
Есть новые Нет новых   [134432   +19][b:0.001][p:0.01]