; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: Macros for importing functions in Linux
;
;  Target OS: Linux
;
;  Dependencies:
;
;  Notes:
;_________________________________________________________________________________________


options.AlignStackExt = 1       ;  SYSTEM V ABI requires stack aligned on 16 bytes on calls.

include '_elf.inc'


macro interpreter [library]
{
 db library,0
}


macro __define_import_arguments [arg] {
common
  local ..start

  if arg eq VOID
    .__info.argtype=1
  else
    if arg eq NONE
      .__info.argtype = 0
    else
      virtual at ebp+8
        ..start:
forward
        if ~arg eq ...
          arg dd ?
        else
          label .more_arguments dword
        end if
common
        .__info.argsize = $ - ..start
      end virtual
      .__info.argtype = 2
    end if
  end if
}



macro __InitImportMacros {
common
  local libs, func

  libs equ 0
  func equ 0

  ; creates symbols list with needed libraries.
  macro import_proto library, [iname, arg, ename] \{
    \common
      \local str, cnt, use
      rept 1 i:libs+1 \\{
        libs equ i
        libs\\#i equ str:cnt:use:library
      \\}

    \forward
      \local fstr
      rept 1 i:func+1 \\{
        func equ i
        func\\#i equ fstr:cnt:iname:ename:arg
        iname\\#.@here = 1
      \\}
  \}

  macro export [lbl] \{
    \forward
      \local fstr
      rept 1 i:func+1 \\{
        func equ i
        func\\#i equ fstr:cnt:lbl:\\`lbl:EXPORT
      \\}
  \}

  macro __ImportAll \{
  \common
    \local strtab,strsz,symtab,rel,relsz,hash,tcnt, tcnt2, size1, size2

    tcnt = 0
    tcnt2 = 0

    if defined options.ShowImported & options.ShowImported & __imported_count>0
      disp 3, 'Imported functions: ', <__imported_count, 10>, $09
    end if

    if defined options.ShowImported & options.ShowImported & __exported_count>0
      disp 3, 'Exported functions: ', <__exported_count, 10>, $09
    end if

    rept func i:1 \\{
      match fstr:cnt:iname:ename:arg, func\\#i \\\{
        if used iname | arg eq EXPORT
          if arg eq EXPORT
            tcnt2 = tcnt2 + 1
          else
            tcnt = tcnt + 1
          end if
          if defined options.ShowImported & options.ShowImported
            if arg eq EXPORT
              display 3, 'Exported "', \\\`iname, '" function.'
            else
              display 3, 'Imported "', \\\`iname, '" function.'
            end if
            if i = func
              display $0d
            else
              display $0a
            end if
          end if
        end if
      \\\}
    \\}

    __imported_count = tcnt;
    __exported_count = tcnt2;

    size1 = 0

    if __imported_count > 0 | __exported_count > 0
      zalign 4, ?
      segment dynamic readable

      rept libs i:1 \\{
        match str:cnt:use:library, libs\\#i \\\{
          cnt = 0
          if use > 0
            dd DT_NEEDED, str-strtab
          end if
        \\\}
      \\}

      dd DT_STRTAB, rva strtab
      dd DT_STRSZ, strsz
      dd DT_SYMTAB, rva symtab
      dd DT_SYMENT, sizeof.Elf32_Sym
      dd DT_REL, rva rel
      dd DT_RELSZ, relsz
      dd DT_RELENT, sizeof.Elf32_Rel
      dd DT_HASH, rva hash
      dd DT_NULL, 0

      size1 = $ - $$

      zalign 4, ?
      segment readable writeable
      symtab: Elf32_Sym

      rept func i:1 \\{
        match fstr:cnt:iname:ename:arg, func\\#i \\\{
          if arg eq EXPORT
              Elf32_Sym fstr-strtab,rva iname,0,STB_GLOBAL,STT_FUNC,0,1
          else
            if used iname
              Elf32_Sym fstr-strtab,0,0,STB_GLOBAL,STT_FUNC,0,0
              cnt = cnt + 1
            end if
          end if
        \\\}
      \\}

      rel:
      \local counter
      counter = 1

      rept func i:1 \\{
        match fstr:cnt:iname:ename:arg, func\\#i \\\{
          if used iname & ~(arg eq EXPORT)
            Elf32_Rel iname, counter, R_386_32
            counter = counter + 1
          end if
        \\\}
      \\}

      relsz = $-rel
      hash:
      dd 1, counter
      dd 0

      repeat counter
       if % = counter
        dd 0
       else
        dd %
       end if
      end repeat

      strtab db 0

      rept func i:1 \\{
        match fstr:cnt:iname:ename:arg, func\\#i \\\{
          if arg eq EXPORT | used iname
            fstr db ename, 0
          end if
        \\\}
      \\}

      rept libs i:1 \\{
        match str:cnt:use:library, libs\\#i \\\{
          use = cnt
          if use > 0
            str db library, 0
          end if
        \\\}
      \\}

      strsz = $-strtab

      rept func i:1 \\{
        match fstr:cnt:iname:ename:arg, func\\#i \\\{
          if ~(arg eq EXPORT)
            if used iname
              iname dd 0
            else
              iname = 0
            end if
            __define_import_arguments arg
          end if
        \\\}
      \\}
    else
      size1 = $ - $$
    end if

    size2 = $ - $$

    DispSize 'ELF Import data1:', size1
    DispSize 'ELF Import data2:', size2
  \}
}


__InitImportMacros