Assembler процедура, возврат результата.

Вопросы программирования на Free Pascal, использования компилятора и утилит.

Модератор: Модераторы

Assembler процедура, возврат результата.

Сообщение Azazaz » 24.11.2016 19:16:56

Есть вот такой код:
Код: Выделить всё
{$mode objfpc}{$H+}
{$inline on}
{$ASMMODE intel}

procedure DM(W: Word; dwr: byte; var D, M: byte); assembler;
asm
mov ax, W;
div dwr;

mov byte [M], ah;
mov byte [D], al;
end;

var
{div, mod}
D, M: byte;
begin
DM(20, 3, d, m);
Writeln('D = ', D, ' M = ', M);
readln;
end.

где процедура должна вернуть результат(div и mod операций) через 2 переменные, но возвращает только одну переменную.
В чем проблема? Каким образом FPC возвращает результаты assembler процедур?
Azazaz
новенький
 
Сообщения: 41
Зарегистрирован: 21.04.2015 20:00:03

Re: Assembler процедура, возврат результата.

Сообщение Дож » 24.11.2016 19:43:13

Проблема в том, что M (т.е. указатель на переменную) передаётся через стек, а не в регистре:
Код: Выделить всё
.section .text.n_p$program_$$_dm$word$byte$byte$byte,"x"
   .balign 16,0x90
.globl   P$PROGRAM_$$_DM$WORD$BYTE$BYTE$BYTE
P$PROGRAM_$$_DM$WORD$BYTE$BYTE$BYTE:
# [da.pas]
# [6] asm
   pushl   %ebp
   movl   %esp,%ebp
# Var W located in register ax
# Var dwr located in register dl
# Var D located in register ecx
# Var M located at ebp+8, size=OS_32
# [7] mov ax, W;
   movw   %ax,%ax
# [8] div dwr;
   divb   %dl
# [12] mov byte [M], ah;
   movb   %ah,8(%ebp)
# [13] mov byte [D], al;
   movb   %al,(%ecx)
# [14] end;
   leave
   ret   $4

Одним mov'ом не обойтись, нужно два, вот так работает:
Код: Выделить всё
procedure DM(W: Word; dwr: byte; var D, M: byte); assembler;
asm
mov ax, W;
div dwr;

mov ebx, [M]
mov byte [ebx], ah;
mov byte [D], al;
end;

Код: Выделить всё
C:\data\temp>fpc -al da.pas && da
Free Pascal Compiler version 3.0.0rc1 [2015/08/10] for i386
Copyright (c) 1993-2015 by Florian Klaempfl and others
Note: Switching assembler to default source writing assembler
Target OS: Win32 for i386
Compiling da.pas
Assembling program
Linking da.exe
21 lines compiled, 0.1 sec, 25504 bytes code, 1236 bytes data
1 note(s) issued
D = 6 M = 2


Для успешного написания ассемблерных функций следует либо изучить подробно как действует дефолтная конвенция вызова в паскале, либо использовать какую-то более-менее фиксированную (stdcall, например).
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Assembler процедура, возврат результата.

Сообщение Azazaz » 24.11.2016 20:20:16

У меня код с 2 mov работает прежним образом. По умолчанию компилятор использует регистры для передачи аргументов, по видимому M переменная попадает в неизвестный регистр из-за чего не возвращается результат. Вопрос в том в какие регистры распихиваются переменные?
Azazaz
новенький
 
Сообщения: 41
Зарегистрирован: 21.04.2015 20:00:03

Re: Assembler процедура, возврат результата.

Сообщение Дож » 24.11.2016 20:28:51

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

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

по видимому M переменная попадает в неизвестный регистр из-за чего не возвращается результат.

Ещё раз: я привёл выше дамп промежуточного ассемблерного кода, в комментариях которого можно увидеть в какие именно «регистры» попали параметры. В частности, M не попал ни в какой регистр, он был передан через стек.

Добавлено спустя 3 минуты 14 секунд:
У меня код с 2 mov работает прежним образом.

Значит, нужно смотреть дамп ассемблерного кода (ключик -al), где именно были размещены переменные.
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47

Re: Assembler процедура, возврат результата.

Сообщение Azazaz » 24.11.2016 20:33:28

Все, заработало. Интересно что будет если скомпилировать вот так:
Код: Выделить всё
procedure DM(W: Word; dwr: byte; var D, M: byte); assembler; register; nostackframe;
asm
div dwr;
mov ebx, M;
mov byte [ebx], ah;
mov byte [D], al;
end;

M не будет передано?

Добавлено спустя 7 минут 15 секунд:
Скомпилировал, M по прежнему в ebp+8 даже с ключом nostackframe.
Azazaz
новенький
 
Сообщения: 41
Зарегистрирован: 21.04.2015 20:00:03

Re: Assembler процедура, возврат результата.

Сообщение Дож » 24.11.2016 20:54:49

Так а модификатор nostackframe и не отключает стек, он отключает обвязку с сохранением топа в стек
http://www.freepascal.org/docs-html/ref/refsu79.html

Добавлено спустя 1 минуту 45 секунд:
По всей видимости, asm..end блок не учитывает nostackframe и алиас M неправильный, поэтому обращаться к переменной нужно ручками
Код: Выделить всё
procedure DM(W: Word; dwr: byte; var D, M: byte); assembler; register; nostackframe;
asm
div dwr;
mov ebx, [esp+4];
mov byte [ebx], ah;
mov byte [D], al;
end;
Аватара пользователя
Дож
энтузиаст
 
Сообщения: 899
Зарегистрирован: 12.10.2008 16:14:47


Вернуться в Free Pascal Compiler

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 15

Рейтинг@Mail.ru