GAECHKA
Твоя помощница в решении задач

Модуль написанный на ассемблере

Добрый день, форумчане! Надо было написать модуль на ассемблере и потом подключить его к паскальевской программе. Написал, вроде компилируется, когда запускаю exe-щник мгновенно закроется. Запустил через cmd, пишет следующий текст runtime error 2 at $0040162F
$0040162F
$00401F14
$0040BAF1
Можете подсказать с чем это может быть связано?
0
вопрос задан

Источник


13 ответов
Решение
Чудес не бывает. Нужно пошаговое выполнение в Lazarus или IDE FP. Тогда будет видно название процедуры с ошибкой.
Кроме того, в начале программы добавить
{$ifdef Debug}        {для отладки}
uses
  HeapTrc, LineInfo;
{$endif}
При пошаговой отладке аварийный останов на строке
single_point(ch1, ch2, random(16));
Просматривая программу на ассемблере вижу
Assembler
        mov esi, [esp+24]; child 1 / a
        mov esi, [esi]
        mov edi, [esp+28]; child 2 / b
        mov edi, [edi]
        mov ecx, [esp+32]; n
        mov ecx, [ecx]
Но
procedure single_point(var a, b:LONGINT; n: LONGINT);
        stdcall; external name '_GENETICA_$$_SINGLE_POINT$LONGINT$LONGINT$LONGINT' ;
параметр n передаётся по значению, а не по указателю.

Добавлено через 7 минут
В других процедурах вижу аналогичную ошибку - параметр-значение внутри asm-процедуры обрабатывается как параметр-переменная.
АВС.net, поскольку в нем написано
Сомневаюсь.

В PABC.Net нету директивы {$L} и ключевого слова stdcall.

stdcall я вроде видел в старинных кодах на PABC.Net, но его уже много лет компилятор не принимает.

А {$L} вообще первый раз вижу. Наверное, это что то типа $reference для неуправляемого кода.

Подключить этот модуль всё равно должно быть возможно, ибо код на C подключается без проблем (но, разумеется, пока битность у неуправляемого кода правильная).

Но для начала, всё же, zero_one, выясните какой компилятор паскаля у вас стоит, ибо их огромное кол-во. И его версия это тоже важно. Лучше всего будет, наверное, если вы скините 2 скрина, как выглядит IDE, и как выглядит страница "о программе" (та на которой версия, имена разработчиков и т.п.).
Учитесь пользоваться отладчиком - встроенным в IDE или внешним (x64dbg, OllyDbg).

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

На первый взгляд, значение маски (ebx) вычисляется иначе, чем в Pascal.

Со строки 21 какая-то муть - в строке 20 результат сохранён в esi, а в строке 21 что-то заносится в esi и результат затирается.
var
  n: integer;
  mass: mas;
begin
  SetLength(mass,n);
  ...................
end.
Я так понимаю это вывод за границы массива?
Да. Динамический массив индексируется от 0 до n-1, а у тебя в коде раньше была индексация от 0 до n...
Может приведете модуль и программу, а так же неплохо бы ознакомиться с заданием.
Puporev, буду благодарен за любую подсказку
Я то это не знаю, но есть у нас люди которые знают, будем надеяться что заглянут.

Добавлено через 5 минут
Тему перенес в раздел АВС.net, поскольку в нем написано. Что-то кода на ассемблере я там не увидел.
Sun Serega, у меня free pascal 3.0.4. Я запускаю asm-файл, полученный obj-файл - это модуль, {$L <имя объекта>.obj} так подключаю модуль. У меня вроде нет деления на ноль, не знаю из-за чего runtime error.
А почему сразу деление на ноль? Может же быть AccessViolation (чтение или запись в память, которая приложению не принадлежит) или неправильная программа (как вызов деления когда на стеке только 1 параметр) и много чего ещё.

Но, разве нет никаких инструментов для дебага .asm? А то что вы гадаете то...
параметр n передаётся по значению
спасибо большое за замечание! Исправил Теперь вроде правильно работает! Но другая проблема нашлась: Код написанный на паскале
procedure single_point(var a, b: longint; n: longint);
  var
    m, t: Word;
  begin
    m := 1 shl n - 1;
    t := a;
    a := a and not m or b and m;
    b := b and not m or t and m;
  end;
и код написанный на ассемблере
Assembler
GENETICA_$$_SINGLE_POINT$LONGINT$LONGINT$LONGINT:
        push esi ; a 
        push edi ; b
        push eax
        push ebx ; m
        push ecx ; t
        
        mov esi, [esp+24]; child 1 / a
        mov esi, [esi]
        mov edi, [esp+28]; child 2 / b
        mov edi, [edi]
        mov ecx, [esp+32]; n
        mov eax, esi 
        mov ebx, 65535 
        shr ebx, cl
        not ebx 
        and esi, ebx; a not m 
        not ebx  
        and edi, ebx; b and m 
        or  esi, edi; a := a and not m or b and m;  
        mov esi, [esp+24]; child 1 / a
        mov esi, [esi]
        mov edi, [esp+28]; child 2 / b
        mov edi, [edi]
        not ebx
        and edi, ebx 
        not ebx 
        and eax, ebx; t and m 
        or edi, eax ; b := b and not m or t and m;
        mov edx, [esp+24] 
        mov [edx], esi 
        mov edx, [esp+28] 
        mov [edx], edi 
        
        pop ecx 
        pop ebx
        pop eax 
        pop edi 
        pop esi 
        ret 12
Делают ли одно и тоже? Написал, скорее всего неправильно Где ошибка не могу найти.
На первый взгляд, значение маски (ebx) вычисляется иначе, чем в Pascal.
Со строки 21 какая-то муть - в строке 20 результат сохранён в esi, а в строке 21 что-то заносится в esi и результат затирается.
Исправил, работает правильно, как надо! Я бы хотел сделать массив динамическим, погуглил и нашел, что делается это через команду SetLength. У меня получается использовать.
type
  m = record
    x: word;
    y: real
  end;
 mas = array of m;
var
  n: integer;
  mass: mas;
  SetLength(mass,n);
Не подскажите как исправить?
Выдает такую ошибку
Genetica1.pas(27) : Встречено '(', а ожидалось ':'
Добавлено через 12 минут
27ая строчка это 10ая строка на коде сообщения выше, не успел отредактировать.
Сделал, но выдает ошибку runtime error 216 и какие адреса памяти, насколько я понял. Я так понимаю это вывод за границы массива?