Почему значение первого байта, может не совпадать?
От: nen777w  
Дата: 05.11.18 14:08
Оценка:
  "Код"
#include <stdio.h>
int main()
{
    unsigned int lbl_begin;
    __asm { mov dword ptr lbl_begin, offset l_begin };

    __asm jmp l_end;
l_begin:
    __asm _emit 0x00;
    __asm _emit 0x01;
    __asm _emit 0x02;
    __asm _emit 0x03;
l_end:

    unsigned char c0 = ((unsigned char*)lbl_begin)[0];
    if (c0 == 0x00) printf("Equal\n"); else printf("Not Equal\n");
    unsigned char c1 = ((unsigned char*)lbl_begin)[1];
    if (c1 == 0x01) printf("Equal\n"); else printf("Not Equal\n");
    unsigned char c2 = ((unsigned char*)lbl_begin)[2];
    if (c2 == 0x02) printf("Equal\n"); else printf("Not Equal\n");
    unsigned char c3 = ((unsigned char*)lbl_begin)[3];
    if (c3 == 0x03) printf("Equal\n"); else printf("Not Equal\n");

    return 0;
}


У меня иногда печатает:

Equal, Equal, Equal, Equal

а иногда

Not Equal, Equal, Equal, Equal


Оптимизации отключены. С чем это может быть связяно?
Отредактировано 05.11.2018 14:09 nen777w . Предыдущая версия .
Re: Почему значение первого байта, может не совпадать?
От: kov_serg Россия  
Дата: 05.11.18 20:23
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Оптимизации отключены. С чем это может быть связяно?

С выравниванием и архитектурой процессора
Re: Почему значение первого байта, может не совпадать?
От: Alexander G Украина  
Дата: 05.11.18 20:39
Оценка:
Здравствуйте, nen777w, Вы писали:


N>У меня иногда печатает:

N>

Equal, Equal, Equal, Equal

N>а иногда
N>

Not Equal, Equal, Equal, Equal


N>Оптимизации отключены. С чем это может быть связяно?


Видимо, значение там 0xCC и связано это с работой отладчика.
Явная breakpoint, или неявная из-за пошаговой отладки.
Русский военный корабль идёт ко дну!
Re: Почему значение первого байта, может не совпадать?
От: andrey.desman  
Дата: 05.11.18 20:45
Оценка: +1
Здравствуйте, nen777w, Вы писали:

N>У меня иногда печатает:

N>

Equal, Equal, Equal, Equal

N>а иногда
N>

Not Equal, Equal, Equal, Equal


N>Оптимизации отключены. С чем это может быть связяно?


А ты выведи lbl_begin и lbl_begin[i] вместо Equal/Not equal. Может, наведет на мысли.
Re[2]: Почему значение первого байта, может не совпадать?
От: nen777w  
Дата: 06.11.18 08:50
Оценка:
Здравствуйте, Alexander G, Вы писали:

AG>Здравствуйте, nen777w, Вы писали:



N>>У меня иногда печатает:

N>>

Equal, Equal, Equal, Equal

N>>а иногда
N>>

Not Equal, Equal, Equal, Equal


N>>Оптимизации отключены. С чем это может быть связяно?


AG>Видимо, значение там 0xCC и связано это с работой отладчика.

AG>Явная breakpoint, или неявная из-за пошаговой отладки.

Ясно, спасибо. Именно это значение 0xcc (это что получается int 0x03 ?). А есть способ "попросить" отладчик не делать этого?
Это тестовый пример. В оригинальном коде тоже все работало, причем достаточно долго без проблем, но потом вдруг стало глючить.
Отредактировано 06.11.2018 8:52 nen777w . Предыдущая версия .
Re[3]: Почему значение первого байта, может не совпадать?
От: Alexander G Украина  
Дата: 06.11.18 11:21
Оценка:
Здравствуйте, nen777w, Вы писали:

AG>>Видимо, значение там 0xCC и связано это с работой отладчика.

AG>>Явная breakpoint, или неявная из-за пошаговой отладки.

N>(это что получается int 0x03 ?).


да

N>А есть способ "попросить" отладчик не делать этого?


Боюсь, нет.

Можно добавить лишнюю инструкцию, чтобы автоматическая бряка снималась перед чтением инструкции

    __asm jmp l_end;
l_begin:
    __asm _emit 0x00;
    __asm _emit 0x01;
    __asm _emit 0x02;
    __asm _emit 0x03;
l_end:
    // лишняя инструкция для того, чтобы при шаге в неё восстанавливалась l_begin
    __asm nop; // или  __nop(); 

    unsigned char c0 = ((unsigned char*)lbl_begin)[0];
    if (c0 == 0x00) printf("Equal\n"); else printf("Not Equal\n");
...


Но если там будет стоять пользовательская софтварная бряка, то не поможет.

N>Это тестовый пример. В оригинальном коде тоже все работало, причем достаточно долго без проблем, но потом вдруг стало глючить.


Может существовать какое-то альтернативное решение, вопрос, зачем это нужно.
Сгенерированный в рантайме код обычно генерируют как массив байт в памяти с PAGE_EXECUTEREAD (даже у HeapCreate есть флаг, чтобы хип для такого кода сделать)
Если просто разместить данные в коде, то не пробовал, но по идее это решается прагмами.
Русский военный корабль идёт ко дну!
Re[4]: Почему значение первого байта, может не совпадать?
От: nen777w  
Дата: 07.11.18 12:12
Оценка:
AG>Можно добавить лишнюю инструкцию, чтобы автоматическая бряка снималась перед чтением инструкции
Спасибо.

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

Да именно данные в коде. Не помню пробовал ли я pragma использовать, видимо нет. Покопаю google на эту тему.
Re[5]: Почему значение первого байта, может не совпадать?
От: Alexander G Украина  
Дата: 07.11.18 15:41
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Да именно данные в коде. Не помню пробовал ли я pragma использовать, видимо нет. Покопаю google на эту тему.


Если это просто блок данных в коде, ещё можно вынести в отдельную функцию с __declspec(naked), вместо метки тогда использовать указатель на функцию.
Русский военный корабль идёт ко дну!
Re[2]: Почему значение первого байта, может не совпадать?
От: lpd Черногория  
Дата: 07.11.18 16:12
Оценка: 1 (1) +1
Здравствуйте, Alexander G, Вы писали:

AG>Видимо, значение там 0xCC и связано это с работой отладчика.

AG>Явная breakpoint, или неявная из-за пошаговой отладки.

Не понял откуда там может взяться breakpoint.
В любом случае, при пошаговой отладке используются TF-флаг и int1, а не 0xCC.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re: Почему значение первого байта, может не совпадать?
От: Mystic Artifact  
Дата: 11.11.18 05:49
Оценка:
Здравствуйте, nen777w, Вы писали:

    unsigned int lbl_begin;
    __asm { mov dword ptr lbl_begin, offset l_begin };


А можно по подробне,е что данная инструкция должна выполнять и каким образом?

На сколько я помню никаких пересылок память в память не было и нет, вместо этого вы пишите в lbl_begin смещение (адрес) l_begin.

Нужно что-то такое:
mov eax, dword ptr l_begin
mov dword ptr lbl_begin, eax


Не?
Re[3]: Почему значение первого байта, может не совпадать?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.11.18 07:07
Оценка:
Здравствуйте, lpd, Вы писали:

AG>>Видимо, значение там 0xCC и связано это с работой отладчика.

AG>>Явная breakpoint, или неявная из-за пошаговой отладки.

lpd>Не понял откуда там может взяться breakpoint.

lpd>В любом случае, при пошаговой отладке используются TF-флаг и int1, а не 0xCC.

Скорее всего, под "пошаговой" имелась в виду не покомандная, а построчная.
На одну строку исходника может приходиться таки много команд.
Тогда отладчик ставит бряк в виде int3 (0xCC) на начало следующей строки с кодом, запускает программу без TF и ждёт срабатывания. Когда сработало, возвращает тот байт, что был там нормально, и отдаёт управление юзеру.
Заметим, что это неадекватно работает в случае рекурсивного вызова (типично, сказал next на уровне вложенности 3, а остановился на уровне вложенности 4). Для таких случаев нужна особая обработка в отладчике.
The God is real, unless declared integer.
Re[4]: Почему значение первого байта, может не совпадать?
От: lpd Черногория  
Дата: 13.11.18 09:18
Оценка:
Здравствуйте, netch80, Вы писали:

N>Скорее всего, под "пошаговой" имелась в виду не покомандная, а построчная.

N>На одну строку исходника может приходиться таки много команд.
N>Тогда отладчик ставит бряк в виде int3 (0xCC) на начало следующей строки с кодом, запускает программу без TF и ждёт срабатывания. Когда сработало, возвращает тот байт, что был там нормально, и отдаёт управление юзеру.

А если в этой строчке if или switch? Как отладчик узнает следующую строчку, чтобы поставить int3? Думаю, проще это реализовать через пошаговую трассировку TF/int1, пока не встретится известная строчка исходного кода.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[5]: Почему значение первого байта, может не совпадать?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.11.18 09:44
Оценка: 5 (1)
Здравствуйте, lpd, Вы писали:

N>>Скорее всего, под "пошаговой" имелась в виду не покомандная, а построчная.

N>>На одну строку исходника может приходиться таки много команд.
N>>Тогда отладчик ставит бряк в виде int3 (0xCC) на начало следующей строки с кодом, запускает программу без TF и ждёт срабатывания. Когда сработало, возвращает тот байт, что был там нормально, и отдаёт управление юзеру.

lpd>А если в этой строчке if или switch? Как отладчик узнает следующую строчку, чтобы поставить int3?


Хороший вопрос. Качественно сделанный отладчик в этом случае ставит бряки на все ветки, которые получаются из точки развилки.
На самом деле ситуация ещё интереснее: изначально может быть тоже ситуация, когда этих мест несколько. Если вы ставите breakpoint в коде, который стал inline (изначально потому что функция была объявлена inline, или компилятор соптимизировал), то может оказаться, что его надо ставить в нескольких местах.
Поэтому отладчик уже должен быть рассчитан на то, что и явный, и неявный breakpoint (как в обсуждаемом случае, точка заказанного останова) может быть в компилированном коде в нескольких местах.

lpd>Думаю, проще это реализовать через пошаговую трассировку TF/int1, пока не встретится известная строчка исходного кода.


Проще — да. Но не лучше. Потому что до следущей строки может выполниться вся суть программы. через вызываемые функции и на каждую машинную инструкцию переключаться туда-обратно — можно не дождаться.
Но в качестве quick&dirty реализации, да, можно сделать и через TF.

Верно, что в этих вещах начинаются реально тяжёлые проблемы, в которых сидят тысяча голодных дьяволов.
Например, команда step into требует остановки на каждой (или первой из, для отладчика поумнее) функции, вызванной из текущей. Для простоты это действительно делается через TF, предполагая, что инструкций до наступления первого call будет немного. Но если там случилось, например, копирование большого объекта через inline memcpy, то это может стать очень долгим действием.
The God is real, unless declared integer.
Re[6]: Почему значение первого байта, может не совпадать?
От: lpd Черногория  
Дата: 13.11.18 11:14
Оценка:
Здравствуйте, netch80, Вы писали:

N>Проще — да. Но не лучше. Потому что до следущей строки может выполниться вся суть программы. через вызываемые функции и на каждую машинную инструкцию переключаться туда-обратно — можно не дождаться.

N>Но в качестве quick&dirty реализации, да, можно сделать и через TF.

Скорее всего, просто "Step Into"(step) через TF/int1, а "Step Over"(next) через int3 для callов. Не думаю, что отладички заморачиваются на препроцессинг и парсинг синтаксиса вызова функций: у них есть только соответствие номеров строк адресам, да информация о стек-фрейме.
У сложных вещей обычно есть и хорошие, и плохие аспекты.
Берегите Родину, мать вашу. (ДДТ)
Re[7]: Почему значение первого байта, может не совпадать?
От: netch80 Украина http://netch80.dreamwidth.org/
Дата: 13.11.18 14:23
Оценка:
Здравствуйте, lpd, Вы писали:

N>>Проще — да. Но не лучше. Потому что до следущей строки может выполниться вся суть программы. через вызываемые функции и на каждую машинную инструкцию переключаться туда-обратно — можно не дождаться.

N>>Но в качестве quick&dirty реализации, да, можно сделать и через TF.
lpd>Скорее всего, просто "Step Into"(step) через TF/int1, а "Step Over"(next) через int3 для callов.

Step Over через int3, но call тут мало при чём — просто точка, при неуправляемом приходе выполнения на которую он обнаруживает, что что-то случилось (в данном случае — закончилось выполнение строки).
А вот Step Into... тут сложнее. Тут тоже должна быть отладочная информация, но другого типа:
— Если вызов вложенной функции идёт через call — сам этот call помечается, чтобы отладчик мог остановиться на этой call и саму её пройти через TF (но тут он должен уметь понимать, где начинается известный ему код, чтобы адекватно пройти, например, косвенный вызов динамически прилинкованной функции с ленивым резолвингом)
— Если вызов вложенной функции сделан через inline — первая инструкция inline-версии помечается, чтобы отладчик мог на ней остановиться

а будет он это делать через TF или постарается вычислить, куда поставить временные int3, это уже зависит от того, как он написан.
Как минимум, мне кажется, дойдя до call, он должен переключиться на TF и далее после каждой инструкции проверять, не попали ли на известный ему код.

lpd> Не думаю, что отладички заморачиваются на препроцессинг и парсинг синтаксиса вызова функций: у них есть только соответствие номеров строк адресам, да информация о стек-фрейме.


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

Вот я читаю, например, спек по DWARF 4 — там есть типы DW_TAG_subprogram и DW_TAG_inlined_subroutine.
К ним прилагаются данные типа диапазона адресов кода. Попав на какой-то адрес, можно проверить его вхождение в такие диапазоны и понять, в какую функцию мы попали.
Если идёт смена этой функции — значит, мы прошли границу события для Step Into или Step Out...
The God is real, unless declared integer.
Re: Почему значение первого байта, может не совпадать?
От: Vain Россия google.ru
Дата: 01.01.19 20:50
Оценка:
Здравствуйте, nen777w, Вы писали:

N>Оптимизации отключены. С чем это может быть связяно?

А если джамп убрать?
__asm jmp l_end;
[In theory there is no difference between theory and practice. In
practice there is.]
[Даю очевидные ответы на риторические вопросы]
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.