Sign in Join

Live chat for Free Pascal, Lazarus, Delphi and every Pascal programmer.

Mailing lists / fpc-pascal / 2010-09

Interface with NASM

15 messages · 5 people · –

Reply by email Subscribe to this list Your subscription

Read-only archive. Use j and k to move between messages.

leledumbo

I need to teach assembler, and the easiest way would be to create a driver and simple I/O library in high level language that can be called from assembler so that students can focus in programming with assembler more than dealing with system specific features. It's been quite a while since I go down to this level, so I might miss something.

Here's the IO library (asmio.pas):

unit asmio;
interface
procedure printc(const c: Char); pascal;
procedure printi(const i: LongInt); pascal;
implementation
procedure printc(const c: Char); pascal; [public, alias: 'printc'];
begin
  Write(c);
end;
procedure printi(const i: LongInt); pascal; [public, alias: 'printi'];
begin
  Write(i);
end;
end.

The driver program (driver.pas):

program driver;
{$L asmio.o}
{$L test.o}
procedure tes; pascal; external name 'tes';
begin
  tes;
end.

And example assembler program which suppose to print 'A' (test.asm):

[bits 32]
extern printc,printi

segment .text
global tes
tes:
push ebp
mov ebp,esp
push 65
call printc
leave
ret

build command:
nasm -f coff test.asm
fpc asmio.pas
fpc -o test driver.pas

As you can see, I didn't use any optimizations because AFAIR FPC would change parameter passing mechanism when a certain optimizations are performed. Of course if it works I won't ask here, but it doesn't. I got access violation instead. However changing the driver program to:

procedure printc(const c: Char); pascal; external name 'printc';
begin
  printc('A');
end.

generates the same instruction sequence for calling printc:

push 65
call printc

I've tried omitting the stackframe (with the corresponding modifier in driver program) but no effect. I wonder where my mistake is...

Additional information:
I've made it to work for non IO functions

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Interface-with-NASM-tp2838671p2838671.html Sent from the Free Pascal - General mailing list .

Reply by email

Matthias K.
to leledumbo

Hi,
I've played around with your code and didn't get usefull results either at first glance. Instead of putting the
printc test into driver, I've wrote a pure pascal unit which does the same as your test.asm, compiled it, disassembled it and modfied the nasm program. That worked.

I'm on a different target machine and pascal calling convention doesn't work at all so this may not be usefull for you, but at least there is a chance it may be, so here is the pure pascal test.asm. If this doesn't link correctly it may be another Problem (!so Compiler Version/svn revision and Target would be good to know!)

---
unit testp;
interface
procedure tes; pascal;
implementation
procedure printchar( c: Char ); pascal; external name 'printc';
procedure tes; pascal; [public, alias: 'tes'];
begin
  printchar( 'A' );
end;
end.
---

Btw. It would be very interesting to know the solution for your Problem if its already fixed :)

Reply by email

Felipe Monteiro de Carvalho
to Matthias K.

I changed it to a very similar program, but one which can be built with a single instruction:

program driver;
uses asmio;
{$ASMMODE Intel}

procedure tes; assembler; [alias:'tes'];
asm
push ebp
mov ebp,esp
mov EAX,65
push EAX
call printc
leave
ret
end;

begin
 tes;
end.

It crashes inside printc apparently when getting the parameter.

Felipe Monteiro de Carvalho

Reply by email

Felipe Monteiro de Carvalho
to Felipe Monteiro de Carvalho

Strange, I took a look and no idea why it doesn't work with the linked .o file =) Maybe disassembling what nasm produces could show something, but I don't know which GNU tool could be used for that...

The following program works for me:

program driver;
uses asmio;
{$ASMMODE att}
procedure tes2; pascal;
begin
  printc(Char(65));
end;

procedure tes; assembler; [alias:'tes'];
asm
movl $65,%eax
push %eax
call printc
end;

begin
  tes2;
  tes;
end.

And here is the assembler generated:

fpc -s driver.pas
edit driver.s

.text
.align 4
.globl _P$DRIVER_TES2
_P$DRIVER_TES2:
pushl %ebp
movl %esp,%ebp
subl $24,%esp
movl %ebx,-12(%ebp)
movl %esi,-8(%ebp)
movl %edi,-4(%ebp)
movl $65,%eax
movl %eax,(%esp)
call L_ASMIO_PRINTC$CHAR$stub
movl -12(%ebp),%ebx
movl -8(%ebp),%esi
movl -4(%ebp),%edi
leave
ret

.text
.align 4
.globl _P$DRIVER_TES
_P$DRIVER_TES:
.reference tes
.globl tes
tes:
.reference _P$DRIVER_TES
subl $12,%esp
movl $65,%eax
pushl %eax
call _ASMIO_PRINTC$CHAR
addl $12,%esp
ret

Felipe Monteiro de Carvalho

Reply by email

leledumbo
to Felipe Monteiro de Carvalho: I changed it to a very similar program, but one which can be built with a single…
It crashes inside printc apparently when getting the parameter

That's it! That's exactly what happened.

Maybe disassembling what nasm produces could show something, but I don't know which GNU tool could be used for that...

ndisasm from nasm package, or objdump can also do that.

The following program works for me

Just by changing to ATT syntax? Weird...

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Interface-with-NASM-tp2838671p2841994.html Sent from the Free Pascal - General mailing list .

Reply by email

Felipe Monteiro de Carvalho
to leledumbo
leledumbo wrote
Just by changing to ATT syntax? Weird...

No, I removed the function header:

push ebp
mov ebp,esp

And function footer:

leave
ret

Because FPC automatically adds them, putting another header was the cause of the crash in my code. But this doesn't seam to be the case with the nasm object file.

Felipe Monteiro de Carvalho

Reply by email

Felipe Monteiro de Carvalho
to Jonas Maebe
Jonas Maebe wrote
Check that this puts a 32 bit value on the stack rather than an 8 bit or 16 bit one. You may need "push dword 65" or something like that.

I can add that my gdb said that the stack was missaligned, so this has a high probability of being the case.

Felipe Monteiro de Carvalho

Reply by email

leledumbo
to Felipe Monteiro de Carvalho
Check that this puts a 32 bit value on the stack rather than an 8 bit or 16 bit one. You may need "push dword 65" or something like that.

I've tried that. Even a (stupid) trick like this:

section .data
charA db 'A'

section .text
global tes
tes:
push ebp
mov ebp,esp
mov eax,charA
mov dword eax,[eax]
push eax
call printc
leave
ret

View this message in context: http://free-pascal-general.1045716.n5.nabble.com/Interface-with-NASM-tp2838671p2842117.html Sent from the Free Pascal - General mailing list .

Reply by email

Jeppe Johansen
to Jonas Maebe: Check that this puts a 32 bit value on the stack rather than an 8 bit or 16 bit one. You…

Pushes/pops on x86/x86_64 are always word sized

Jonas Maebe wrote 18 lines
On 14 Sep 2010, at 08:35, leledumbo wrote: > segment .text > global tes > tes: > push ebp > mov ebp,esp > push 65 Check that this puts a 32 bit value on the stack rather than an 8 bit or 16 bit one. You may need "push dword 65" or something like that. Jonas _______________________________________________ fpc-pascal maillist - http://lists.freepascal.org/mailman/listinfo/fpc-pascal

Reply by email

Jonas Maebe
to leledumbo: I need to teach assembler, and the easiest way would be to create a driver and simple I/O…
leledumbo wrote 8 lines
build command: nasm -f coff test.asm fpc asmio.pas fpc -o test driver.pas As you can see, I didn't use any optimizations because AFAIR FPC would change parameter passing mechanism when a certain optimizations are performed.

That's not the case. The only situation in which the compiler would be allowed to do that is for routines defined in the main program or in the implementation section of a unit that are not manually declared as public/export either (in your case they're both in the interface of a unit and manually declared as public), and for safety that maybe also are not called from inline assembler blocks (but it doesn't do that at this time).

Of course if it works I won't ask here, but it doesn't. I got access violation instead.

It works fine under linux (if you replace the "-f coff" with "-f elf").

Jonas

Reply by email

Jonas Maebe
to Felipe Monteiro de Carvalho
Felipe Monteiro de Carvalho wrote 6 lines
On Thu, Sep 16, 2010 at 3:19 PM, Jonas Maebe < > wrote: > It works fine under linux (if you replace the "-f coff" with "-f > elf"). For me it doesn't work in Mac OS X using -f macho

That is normal, Mac OS X/i386 requires a different function calling model than other i386 platforms. Windows does not.

Jonas

Reply by email