mirror of
				https://gitlab.com/freepascal.org/fpc/source.git
				synced 2025-11-04 05:39:29 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			393 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
			
		
		
	
	
			393 lines
		
	
	
		
			17 KiB
		
	
	
	
		
			ObjectPascal
		
	
	
	
	
	
{
 | 
						|
    $Id$
 | 
						|
    Copyright (c) 1998 by Florian Klaempfl
 | 
						|
 | 
						|
    Reads inline assembler and writes the lines direct to the output
 | 
						|
 | 
						|
    This program is free software; you can redistribute it and/or modify
 | 
						|
    it under the terms of the GNU General Public License as published by
 | 
						|
    the Free Software Foundation; either version 2 of the License, or
 | 
						|
    (at your option) any later version.
 | 
						|
 | 
						|
    This program is distributed in the hope that it will be useful,
 | 
						|
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
						|
    GNU General Public License for more details.
 | 
						|
 | 
						|
    You should have received a copy of the GNU General Public License
 | 
						|
    along with this program; if not, write to the Free Software
 | 
						|
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 | 
						|
 | 
						|
 ****************************************************************************
 | 
						|
}
 | 
						|
unit Ra386dir;
 | 
						|
 | 
						|
  interface
 | 
						|
 | 
						|
    uses
 | 
						|
      tree;
 | 
						|
 | 
						|
     function assemble : ptree;
 | 
						|
 | 
						|
  implementation
 | 
						|
 | 
						|
     uses
 | 
						|
        files,globals,scanner,aasm,cpubase,cpuasm,
 | 
						|
        cobjects,symconst,symtable,types,verbose,
 | 
						|
{$ifdef NEWCG}
 | 
						|
        cgbase,
 | 
						|
{$else}
 | 
						|
        hcodegen,
 | 
						|
{$endif}
 | 
						|
        rautils,ra386;
 | 
						|
 | 
						|
    function assemble : ptree;
 | 
						|
 | 
						|
      var
 | 
						|
         retstr,s,hs : string;
 | 
						|
         c : char;
 | 
						|
         ende : boolean;
 | 
						|
         sym : psym;
 | 
						|
         code : paasmoutput;
 | 
						|
         i,l : longint;
 | 
						|
 | 
						|
       procedure writeasmline;
 | 
						|
         var
 | 
						|
           i : longint;
 | 
						|
         begin
 | 
						|
           i:=length(s);
 | 
						|
           while (i>0) and (s[i] in [' ',#9]) do
 | 
						|
            dec(i);
 | 
						|
           {$ifndef TP}
 | 
						|
             {$ifopt H+}
 | 
						|
               setlength(s,i);
 | 
						|
             {$else}
 | 
						|
               s[0]:=chr(i);
 | 
						|
             {$endif}
 | 
						|
           {$else}
 | 
						|
             s[0]:=chr(i);
 | 
						|
           {$endif}
 | 
						|
           if s<>'' then
 | 
						|
            code^.concat(new(pai_direct,init(strpnew(s))));
 | 
						|
            { consider it set function set if the offset was loaded }
 | 
						|
           if assigned(procinfo^.retdef) and
 | 
						|
              (pos(retstr,upper(s))>0) then
 | 
						|
              procinfo^.funcret_is_valid:=true;
 | 
						|
           s:='';
 | 
						|
         end;
 | 
						|
 | 
						|
     begin
 | 
						|
       ende:=false;
 | 
						|
       s:='';
 | 
						|
       if assigned(procinfo^.retdef) and
 | 
						|
          is_fpu(procinfo^.retdef) then
 | 
						|
         procinfo^.funcret_is_valid:=true;
 | 
						|
       if assigned(procinfo^.retdef) and
 | 
						|
          (procinfo^.retdef<>pdef(voiddef)) then
 | 
						|
         retstr:=upper(tostr(procinfo^.retoffset)+'('+att_reg2str[procinfo^.framepointer]+')')
 | 
						|
       else
 | 
						|
         retstr:='';
 | 
						|
         c:=current_scanner^.asmgetchar;
 | 
						|
         code:=new(paasmoutput,init);
 | 
						|
         while not(ende) do
 | 
						|
           begin
 | 
						|
              { wrong placement
 | 
						|
              current_scanner^.gettokenpos; }
 | 
						|
              case c of
 | 
						|
                 'A'..'Z','a'..'z','_' : begin
 | 
						|
                      current_scanner^.gettokenpos;
 | 
						|
                      i:=0;
 | 
						|
                      hs:='';
 | 
						|
                      while ((ord(c)>=ord('A')) and (ord(c)<=ord('Z')))
 | 
						|
                         or ((ord(c)>=ord('a')) and (ord(c)<=ord('z')))
 | 
						|
                         or ((ord(c)>=ord('0')) and (ord(c)<=ord('9')))
 | 
						|
                         or (c='_') do
 | 
						|
                        begin
 | 
						|
                           inc(i);
 | 
						|
                           hs[i]:=c;
 | 
						|
                           c:=current_scanner^.asmgetchar;
 | 
						|
                        end;
 | 
						|
                      {$ifndef TP}
 | 
						|
                        {$ifopt H+}
 | 
						|
                          setlength(hs,i);
 | 
						|
                        {$else}
 | 
						|
                          hs[0]:=chr(i);
 | 
						|
                        {$endif}
 | 
						|
                      {$else}
 | 
						|
                         hs[0]:=chr(i);
 | 
						|
                      {$endif}
 | 
						|
                      if upper(hs)='END' then
 | 
						|
                         ende:=true
 | 
						|
                      else
 | 
						|
                         begin
 | 
						|
                            if c=':' then
 | 
						|
                              begin
 | 
						|
                                getsym(upper(hs),false);
 | 
						|
                                if srsym<>nil then
 | 
						|
                                  if (srsym^.typ = labelsym) then
 | 
						|
                                    Begin
 | 
						|
                                       hs:=plabelsym(srsym)^.lab^.name;
 | 
						|
                                       plabelsym(srsym)^.lab^.is_set:=true;
 | 
						|
                                    end
 | 
						|
                                  else
 | 
						|
                                    Message(asmr_w_using_defined_as_local);
 | 
						|
                              end
 | 
						|
                            else if upper(hs)='FWAIT' then
 | 
						|
                             FwaitWarning
 | 
						|
                            else
 | 
						|
                            { access to local variables }
 | 
						|
                            if assigned(aktprocsym) then
 | 
						|
                              begin
 | 
						|
                                 { is the last written character an special }
 | 
						|
                                 { char ?                                   }
 | 
						|
                                 if (s[length(s)]='%') and
 | 
						|
                                    ret_in_acc(procinfo^.retdef) and
 | 
						|
                                    ((pos('AX',upper(hs))>0) or
 | 
						|
                                    (pos('AL',upper(hs))>0)) then
 | 
						|
                                   procinfo^.funcret_is_valid:=true;
 | 
						|
                                 if (s[length(s)]<>'%') and
 | 
						|
                                   (s[length(s)]<>'$') and
 | 
						|
                                   ((s[length(s)]<>'0') or (hs[1]<>'x')) then
 | 
						|
                                   begin
 | 
						|
                                      if assigned(aktprocsym^.definition^.localst) and
 | 
						|
                                         (lexlevel >= normal_function_level) then
 | 
						|
                                        sym:=aktprocsym^.definition^.localst^.search(upper(hs))
 | 
						|
                                      else
 | 
						|
                                        sym:=nil;
 | 
						|
                                      if assigned(sym) then
 | 
						|
                                        begin
 | 
						|
                                           if (sym^.typ = labelsym) then
 | 
						|
                                             Begin
 | 
						|
                                                hs:=plabelsym(sym)^.lab^.name;
 | 
						|
                                             end
 | 
						|
                                           else if sym^.typ=varsym then
 | 
						|
                                             begin
 | 
						|
                                             {variables set are after a comma }
 | 
						|
                                             {like in movl %eax,I }
 | 
						|
                                             if pos(',',s) > 0 then
 | 
						|
                                               pvarsym(sym)^.varstate:=vs_used
 | 
						|
                                             else
 | 
						|
                                             if (pos('MOV',upper(s)) > 0) and (pvarsym(sym)^.varstate=vs_declared) then
 | 
						|
                                              Message1(sym_n_uninitialized_local_variable,hs);
 | 
						|
                                             if (vo_is_external in pvarsym(sym)^.varoptions) then
 | 
						|
                                               hs:=pvarsym(sym)^.mangledname
 | 
						|
                                             else
 | 
						|
                                               hs:='-'+tostr(pvarsym(sym)^.address)+'('+att_reg2str[procinfo^.framepointer]+')';
 | 
						|
                                             end
 | 
						|
                                           else
 | 
						|
                                           { call to local function }
 | 
						|
                                           if (sym^.typ=procsym) and ((pos('CALL',upper(s))>0) or
 | 
						|
                                              (pos('LEA',upper(s))>0)) then
 | 
						|
                                             begin
 | 
						|
                                                hs:=pprocsym(sym)^.definition^.mangledname;
 | 
						|
                                             end;
 | 
						|
                                        end
 | 
						|
                                      else
 | 
						|
                                        begin
 | 
						|
                                           if assigned(aktprocsym^.definition^.parast) then
 | 
						|
                                             sym:=aktprocsym^.definition^.parast^.search(upper(hs))
 | 
						|
                                           else
 | 
						|
                                             sym:=nil;
 | 
						|
                                           if assigned(sym) then
 | 
						|
                                             begin
 | 
						|
                                                if sym^.typ=varsym then
 | 
						|
                                                  begin
 | 
						|
                                                     l:=pvarsym(sym)^.address;
 | 
						|
                                                     { set offset }
 | 
						|
                                                     inc(l,aktprocsym^.definition^.parast^.address_fixup);
 | 
						|
                                                     hs:=tostr(l)+'('+att_reg2str[procinfo^.framepointer]+')';
 | 
						|
                                                     if pos(',',s) > 0 then
 | 
						|
                                                       pvarsym(sym)^.varstate:=vs_used;
 | 
						|
                                                  end;
 | 
						|
                                             end
 | 
						|
                                      { I added that but it creates a problem in line.ppi
 | 
						|
                                      because there is a local label wbuffer and
 | 
						|
                                      a static variable WBUFFER ...
 | 
						|
                                      what would you decide, florian ?}
 | 
						|
                                      else
 | 
						|
 | 
						|
                                        begin
 | 
						|
{$ifndef IGNOREGLOBALVAR}
 | 
						|
                                           getsym(upper(hs),false);
 | 
						|
                                           sym:=srsym;
 | 
						|
                                           if assigned(sym) and (sym^.owner^.symtabletype in [unitsymtable,
 | 
						|
                                             globalsymtable,staticsymtable]) then
 | 
						|
                                             begin
 | 
						|
                                                if (sym^.typ = varsym) or (sym^.typ = typedconstsym) then
 | 
						|
                                                  begin
 | 
						|
                                                     Message2(asmr_h_direct_global_to_mangled,hs,sym^.mangledname);
 | 
						|
                                                     hs:=sym^.mangledname;
 | 
						|
                                                     if sym^.typ=varsym then
 | 
						|
                                                       inc(pvarsym(sym)^.refs);
 | 
						|
                                                  end;
 | 
						|
                                                { procs can be called or the address can be loaded }
 | 
						|
                                                if (sym^.typ=procsym) and
 | 
						|
                                                   ((pos('CALL',upper(s))>0) or (pos('LEA',upper(s))>0)) then
 | 
						|
                                                  begin
 | 
						|
                                                     if assigned(pprocsym(sym)^.definition^.nextoverloaded) then
 | 
						|
                                                       Message1(asmr_w_direct_global_is_overloaded_func,hs);
 | 
						|
                                                     Message2(asmr_h_direct_global_to_mangled,hs,sym^.mangledname);
 | 
						|
                                                     hs:=sym^.mangledname;
 | 
						|
                                                  end;
 | 
						|
                                             end
 | 
						|
                                           else
 | 
						|
{$endif TESTGLOBALVAR}
 | 
						|
                                           if upper(hs)='__SELF' then
 | 
						|
                                             begin
 | 
						|
                                                if assigned(procinfo^._class) then
 | 
						|
                                                  hs:=tostr(procinfo^.selfpointer_offset)+'('+att_reg2str[procinfo^.framepointer]+')'
 | 
						|
                                                else
 | 
						|
                                                 Message(asmr_e_cannot_use_SELF_outside_a_method);
 | 
						|
                                             end
 | 
						|
                                           else if upper(hs)='__RESULT' then
 | 
						|
                                             begin
 | 
						|
                                                if assigned(procinfo^.retdef) and
 | 
						|
                                                  (procinfo^.retdef<>pdef(voiddef)) then
 | 
						|
                                                  hs:=retstr
 | 
						|
                                                else
 | 
						|
                                                  Message(asmr_e_void_function);
 | 
						|
                                             end
 | 
						|
                                           else if upper(hs)='__OLDEBP' then
 | 
						|
                                             begin
 | 
						|
                                                { complicate to check there }
 | 
						|
                                                { we do it: }
 | 
						|
                                                if lexlevel>normal_function_level then
 | 
						|
                                                  hs:=tostr(procinfo^.framepointer_offset)+
 | 
						|
                                                    '('+att_reg2str[procinfo^.framepointer]+')'
 | 
						|
                                                else
 | 
						|
                                                  Message(asmr_e_cannot_use_OLDEBP_outside_nested_procedure);
 | 
						|
                                             end;
 | 
						|
                                           end;
 | 
						|
                                        end;
 | 
						|
                                   end;
 | 
						|
                              end;
 | 
						|
                            s:=s+hs;
 | 
						|
                         end;
 | 
						|
                   end;
 | 
						|
 '{',';',#10,#13 : begin
 | 
						|
                      if pos(retstr,s) > 0 then
 | 
						|
                        procinfo^.funcret_is_valid:=true;
 | 
						|
                     writeasmline;
 | 
						|
                     c:=current_scanner^.asmgetchar;
 | 
						|
                   end;
 | 
						|
             #26 : Message(scan_f_end_of_file);
 | 
						|
             else
 | 
						|
               begin
 | 
						|
                 current_scanner^.gettokenpos;
 | 
						|
                 {$ifndef TP}
 | 
						|
                   {$ifopt H+}
 | 
						|
                     setlength(s,length(s)+1);
 | 
						|
                   {$else}
 | 
						|
                     inc(byte(s[0]));
 | 
						|
                   {$endif}
 | 
						|
                 {$else}
 | 
						|
                    inc(byte(s[0]));
 | 
						|
                 {$endif}
 | 
						|
                 s[length(s)]:=c;
 | 
						|
                 c:=current_scanner^.asmgetchar;
 | 
						|
               end;
 | 
						|
           end;
 | 
						|
         end;
 | 
						|
       writeasmline;
 | 
						|
       assemble:=genasmnode(code);
 | 
						|
     end;
 | 
						|
 | 
						|
end.
 | 
						|
{
 | 
						|
  $Log$
 | 
						|
  Revision 1.26  1999-11-09 23:06:46  peter
 | 
						|
    * esi_offset -> selfpointer_offset to be newcg compatible
 | 
						|
    * hcogegen -> cgbase fixes for newcg
 | 
						|
 | 
						|
  Revision 1.25  1999/11/06 14:34:24  peter
 | 
						|
    * truncated log to 20 revs
 | 
						|
 | 
						|
  Revision 1.24  1999/09/27 23:44:58  peter
 | 
						|
    * procinfo is now a pointer
 | 
						|
    * support for result setting in sub procedure
 | 
						|
 | 
						|
  Revision 1.23  1999/08/04 00:23:26  florian
 | 
						|
    * renamed i386asm and i386base to cpuasm and cpubase
 | 
						|
 | 
						|
  Revision 1.22  1999/08/03 22:03:11  peter
 | 
						|
    * moved bitmask constants to sets
 | 
						|
    * some other type/const renamings
 | 
						|
 | 
						|
  Revision 1.21  1999/05/27 19:44:57  peter
 | 
						|
    * removed oldasm
 | 
						|
    * plabel -> pasmlabel
 | 
						|
    * -a switches to source writing automaticly
 | 
						|
    * assembler readers OOPed
 | 
						|
    * asmsymbol automaticly external
 | 
						|
    * jumptables and other label fixes for asm readers
 | 
						|
 | 
						|
  Revision 1.20  1999/05/21 13:55:15  peter
 | 
						|
    * NEWLAB for label as symbol
 | 
						|
 | 
						|
  Revision 1.19  1999/05/05 22:22:02  peter
 | 
						|
    * updated messages
 | 
						|
 | 
						|
  Revision 1.18  1999/05/01 13:24:40  peter
 | 
						|
    * merged nasm compiler
 | 
						|
    * old asm moved to oldasm/
 | 
						|
 | 
						|
  Revision 1.17  1999/03/31 13:55:18  peter
 | 
						|
    * assembler inlining working for ag386bin
 | 
						|
 | 
						|
  Revision 1.16  1999/03/24 23:17:22  peter
 | 
						|
    * fixed bugs 212,222,225,227,229,231,233
 | 
						|
 | 
						|
  Revision 1.15  1999/03/01 13:22:26  pierre
 | 
						|
   * varsym refs incremented
 | 
						|
 | 
						|
  Revision 1.14  1999/02/22 02:15:36  peter
 | 
						|
    * updates for ag386bin
 | 
						|
 | 
						|
  Revision 1.13  1999/01/27 13:04:12  pierre
 | 
						|
   * bug with static vars in assembler readers
 | 
						|
 | 
						|
  Revision 1.12  1999/01/10 15:37:57  peter
 | 
						|
    * moved some tables from ra386*.pas -> i386.pas
 | 
						|
    + start of coff writer
 | 
						|
    * renamed asmutils unit to rautils
 | 
						|
 | 
						|
  Revision 1.11  1998/11/17 00:26:12  peter
 | 
						|
    * fixed for $H+
 | 
						|
 | 
						|
  Revision 1.10  1998/11/13 15:40:28  pierre
 | 
						|
    + added -Se in Makefile cvstest target
 | 
						|
    + lexlevel cleanup
 | 
						|
      normal_function_level main_program_level and unit_init_level defined
 | 
						|
    * tins_cache grown to A_EMMS (gave range check error in asm readers)
 | 
						|
      (test added in code !)
 | 
						|
    * -Un option was wrong
 | 
						|
    * _FAIL and _SELF only keyword inside
 | 
						|
      constructors and methods respectively
 | 
						|
 | 
						|
  Revision 1.9  1998/10/20 08:06:57  pierre
 | 
						|
    * several memory corruptions due to double freemem solved
 | 
						|
      => never use p^.loc.location:=p^.left^.loc.location;
 | 
						|
    + finally I added now by default
 | 
						|
      that ra386dir translates global and unit symbols
 | 
						|
    + added a first field in tsymtable and
 | 
						|
      a nextsym field in tsym
 | 
						|
      (this allows to obtain ordered type info for
 | 
						|
      records and objects in gdb !)
 | 
						|
 | 
						|
  Revision 1.8  1998/09/04 08:42:08  peter
 | 
						|
    * updated some error messages
 | 
						|
 | 
						|
  Revision 1.7  1998/09/03 17:39:05  florian
 | 
						|
    + better code for type conversation longint/dword to real type
 | 
						|
 | 
						|
  Revision 1.6  1998/09/03 17:08:47  pierre
 | 
						|
    * better lines for stabs
 | 
						|
      (no scroll back to if before else part
 | 
						|
      no return to case line at jump outside case)
 | 
						|
    + source lines also if not in order
 | 
						|
 | 
						|
  Revision 1.5  1998/08/21 08:45:51  pierre
 | 
						|
    * better line info for asm statements
 | 
						|
 | 
						|
}
 |