/**
 * Compiler implementation of the
 * $(LINK2 http://www.dlang.org, D programming language).
 *
 * Copyright:   Copyright (C) 1994-1998 by Symantec
 *              Copyright (C) 2000-2018 by The D Language Foundation, All Rights Reserved
 * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
 * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
 * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/obj.d, backend/obj.d)
 */

module dmd.backend.obj;

// Online documentation: https://dlang.org/phobos/dmd_backend_obj.html

/* Interface to object file format
 */

import dmd.backend.cdef;
import dmd.backend.cc;
import dmd.backend.code;
import dmd.backend.el;
import dmd.backend.outbuf;

extern (C++):

version (Windows)
{
    version (SCPP)
    {
        version = OMF;
    }
    version (SPP)
    {
        version = OMF;
    }
    version (HTOD)
    {
        version = STUB;
    }
    version (MARS)
    {
        version = OMFandMSCOFF;
    }
}

version (OMF)
{
    class Obj
    {
      static
      {
        Obj init(Outbuffer *, const(char)* filename, const(char)* csegname);
        void initfile(const(char)* filename, const(char)* csegname, const(char)* modname);
        void termfile();
        void term(const(char)* objfilename);
        size_t mangle(Symbol *s,char *dest);
        void _import(elem *e);
        void linnum(Srcpos srcpos, int seg, targ_size_t offset);
        int codeseg(char *name,int suffix);
        void dosseg();
        void startaddress(Symbol *);
        bool includelib(const(char)* );
        bool allowZeroSize();
        void exestr(const(char)* p);
        void user(const(char)* p);
        void compiler();
        void wkext(Symbol *,Symbol *);
        void lzext(Symbol *,Symbol *);
        void _alias(const(char)* n1,const(char)* n2);
        void theadr(const(char)* modname);
        void segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
        void staticctor(Symbol *s,int dtor,int seg);
        void staticdtor(Symbol *s);
        void setModuleCtorDtor(Symbol *s, bool isCtor);
        void ehtables(Symbol *sfunc,uint size,Symbol *ehsym);
        void ehsections();
        void moduleinfo(Symbol *scc);
      }
        final int comdat(Symbol *);
        final int comdatsize(Symbol *, targ_size_t symsize);
        final int readonly_comdat(Symbol *s);
      static
      {
        void setcodeseg(int seg);
        seg_data *tlsseg();
        seg_data *tlsseg_bss();
        seg_data *tlsseg_data();
        int  fardata(char *name, targ_size_t size, targ_size_t *poffset);
        void export_symbol(Symbol *s, uint argsize);
        void pubdef(int seg, Symbol *s, targ_size_t offset);
        void pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize);
        int external_def(const(char)* );
        int data_start(Symbol *sdata, targ_size_t datasize, int seg);
        int external(Symbol *);
        int common_block(Symbol *s, targ_size_t size, targ_size_t count);
        int common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count);
        void lidata(int seg, targ_size_t offset, targ_size_t count);
        void write_zeros(seg_data *pseg, targ_size_t count);
        void write_byte(seg_data *pseg, uint _byte);
        void write_bytes(seg_data *pseg, uint nbytes, void *p);
        void _byte(int seg, targ_size_t offset, uint _byte);
        uint bytes(int seg, targ_size_t offset, uint nbytes, void *p);
        void ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
        void write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2);
        void reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags);
        void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
        void reftocodeseg(int seg, targ_size_t offset, targ_size_t val);
        int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags);
        void far16thunk(Symbol *s);
        void fltused();
        int data_readonly(char *p, int len, int *pseg);
        int data_readonly(char *p, int len);
        int string_literal_segment(uint sz);
        Symbol *sym_cdata(tym_t, char *, int);
        void func_start(Symbol *sfunc);
        void func_term(Symbol *sfunc);
        void write_pointerRef(Symbol* s, uint off);
        int jmpTableSegment(Symbol* s);
        Symbol *tlv_bootstrap();
        void gotref(Symbol *s);
        int seg_debugT();           // where the symbolic debug type data goes
      }
    }
}
else version (OMFandMSCOFF)
{
    class Obj
    {
      public:
        static Obj init(Outbuffer *, const(char)* filename, const(char)* csegname);
        void initfile(const(char)* filename, const(char)* csegname, const(char)* modname);
        void termfile();
        void term(const(char)* objfilename);
        size_t mangle(Symbol *s,char *dest);
        void _import(elem *e);
        void linnum(Srcpos srcpos, int seg, targ_size_t offset);
        int codeseg(char *name,int suffix);
        void dosseg();
        void startaddress(Symbol *);
        bool includelib(const(char)* );
        bool allowZeroSize();
        void exestr(const(char)* p);
        void user(const(char)* p);
        void compiler();
        void wkext(Symbol *,Symbol *);
        void lzext(Symbol *,Symbol *);
        void _alias(const(char)* n1,const(char)* n2);

        void theadr(const(char)* modname);
        void segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
        void staticctor(Symbol *s,int dtor,int seg);
        void staticdtor(Symbol *s);
        void setModuleCtorDtor(Symbol *s, bool isCtor);
        void ehtables(Symbol *sfunc,uint size,Symbol *ehsym);
        void ehsections();
        void moduleinfo(Symbol *scc);
        int comdat(Symbol *);
        int comdatsize(Symbol *, targ_size_t symsize);
        int readonly_comdat(Symbol *s);
        void setcodeseg(int seg);
        seg_data *tlsseg();
        seg_data *tlsseg_bss();
        seg_data *tlsseg_data();
        static int  fardata(char *name, targ_size_t size, targ_size_t *poffset);
        void export_symbol(Symbol *s, uint argsize);
        void pubdef(int seg, Symbol *s, targ_size_t offset);
        void pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize);
        int external_def(const(char)* );
        int data_start(Symbol *sdata, targ_size_t datasize, int seg);
        int external(Symbol *);
        int common_block(Symbol *s, targ_size_t size, targ_size_t count);
        int common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count);
        void lidata(int seg, targ_size_t offset, targ_size_t count);
        void write_zeros(seg_data *pseg, targ_size_t count);
        void write_byte(seg_data *pseg, uint _byte);
        void write_bytes(seg_data *pseg, uint nbytes, void *p);
        void _byte(int seg, targ_size_t offset, uint _byte);
        uint bytes(int seg, targ_size_t offset, uint nbytes, void *p);
        void ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
        void write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2);
        void reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags);
        void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
        void reftocodeseg(int seg, targ_size_t offset, targ_size_t val);
        int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags);
        void far16thunk(Symbol *s);
        void fltused();
        int data_readonly(char *p, int len, int *pseg);
        int data_readonly(char *p, int len);
        int string_literal_segment(uint sz);
        Symbol *sym_cdata(tym_t, char *, int);
        void func_start(Symbol *sfunc);
        void func_term(Symbol *sfunc);
        void write_pointerRef(Symbol* s, uint off);
        int jmpTableSegment(Symbol* s);

        Symbol *tlv_bootstrap();

        static void gotref(Symbol *s);

        int seg_debugT();           // where the symbolic debug type data goes
    }


    class MsCoffObj : Obj
    {
      public:
        static MsCoffObj init(Outbuffer *, const(char)* filename, const(char)* csegname);
        override void initfile(const(char)* filename, const(char)* csegname, const(char)* modname);
        override void termfile();
        override void term(const(char)* objfilename);
        override void compiler();
        override void exestr(const(char)* p);
        //override void dosseg();
        //override size_t mangle(Symbol *s,char *dest);
        override void startaddress(Symbol *);
        override bool includelib(const(char)* );
        override void _alias(const(char)* n1,const(char)* n2);
        override void user(const(char)* p);
    //    void _import(elem *e);
        override void linnum(Srcpos srcpos, int seg, targ_size_t offset);
        override int codeseg(char *name,int suffix);
        override bool allowZeroSize();
        override void wkext(Symbol *,Symbol *);
    //    void lzext(Symbol *,Symbol *);
    //    void theadr(const(char)* modname);
    //    void segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
        override void staticctor(Symbol *s,int dtor,int seg);
        override void staticdtor(Symbol *s);
        override void setModuleCtorDtor(Symbol *s, bool isCtor);
        override void ehtables(Symbol *sfunc,uint size,Symbol *ehsym);
        override void ehsections();
        override void moduleinfo(Symbol *scc);
        override int comdat(Symbol *);
        override int comdatsize(Symbol *, targ_size_t symsize);
        override int readonly_comdat(Symbol *s);
        override void setcodeseg(int seg);
        override seg_data *tlsseg();
        override seg_data *tlsseg_bss();
        override seg_data *tlsseg_data();
        override void export_symbol(Symbol *s, uint argsize);
        override void pubdef(int seg, Symbol *s, targ_size_t offset);
        override void pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize);
    //    int external(const(char)* );
        override int external_def(const(char)* );
        override int data_start(Symbol *sdata, targ_size_t datasize, int seg);
        override int external(Symbol *);
        override int common_block(Symbol *s, targ_size_t size, targ_size_t count);
        override int common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count);
        override void lidata(int seg, targ_size_t offset, targ_size_t count);
        override void write_zeros(seg_data *pseg, targ_size_t count);
        override void write_byte(seg_data *pseg, uint _byte);
        override void write_bytes(seg_data *pseg, uint nbytes, void *p);
        override void _byte(int seg, targ_size_t offset, uint _byte);
        override uint bytes(int seg, targ_size_t offset, uint nbytes, void *p);
    //    void ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
    //    void write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2);
        override void reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags);
    //    void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
        override void reftocodeseg(int seg, targ_size_t offset, targ_size_t val);
        override int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags);
        override void far16thunk(Symbol *s);
        override void fltused();
        override int data_readonly(char *p, int len, int *pseg);
        override int data_readonly(char *p, int len);
        override int string_literal_segment(uint sz);
        override Symbol *sym_cdata(tym_t, char *, int);
        static  uint addstr(Outbuffer *strtab, const(char)* );
        static void func_start(Symbol *sfunc);
        static void func_term(Symbol *sfunc);
        override void write_pointerRef(Symbol* s, uint off);
        override int jmpTableSegment(Symbol* s);

        static int getsegment(const(char)* sectname, uint flags);
        static int getsegment2( uint shtidx);
        static  uint addScnhdr(const(char)* scnhdr_name, uint flags);

        static void addrel(int seg, targ_size_t offset, Symbol *targsym,
             uint targseg, int rtype, int val);
    //    static void addrel(int seg, targ_size_t offset, uint type,
    //                                         uint symidx, targ_size_t val);

        static int seg_pdata();
        static int seg_xdata();
        static int seg_pdata_comdat(Symbol *sfunc);
        static int seg_xdata_comdat(Symbol *sfunc);

        static int seg_debugS();
        override int seg_debugT();
        static int seg_debugS_comdat(Symbol *sfunc);

        override Symbol *tlv_bootstrap();
    }
}
else version (Posix)
{
    class Obj
    {
      public:
        static Obj init(Outbuffer *, const(char)* filename, const(char)* csegname);
        static void initfile(const(char)* filename, const(char)* csegname, const(char)* modname);
        static void termfile();
        static void term(const(char)* objfilename);
        static void compiler();
        static void exestr(const(char)* p);
        static void dosseg();
        static void startaddress(Symbol *);
        static bool includelib(const(char)* );
        static size_t mangle(Symbol *s,char *dest);
        static void _alias(const(char)* n1,const(char)* n2);
        static void user(const(char)* p);

        static void _import(elem *e);
        static void linnum(Srcpos srcpos, int seg, targ_size_t offset);
        static int codeseg(char *name,int suffix);
        static bool allowZeroSize();
        static void wkext(Symbol *,Symbol *);
        static void lzext(Symbol *,Symbol *);
        static void theadr(const(char)* modname);
        static void segment_group(targ_size_t codesize, targ_size_t datasize, targ_size_t cdatasize, targ_size_t udatasize);
        static void staticctor(Symbol *s,int dtor,int seg);
        static void staticdtor(Symbol *s);
        static void setModuleCtorDtor(Symbol *s, bool isCtor);
        static void ehtables(Symbol *sfunc,uint size,Symbol *ehsym);
        static void ehsections();
        static void moduleinfo(Symbol *scc);
        int comdat(Symbol *);
        static int comdatsize(Symbol *, targ_size_t symsize);
        int readonly_comdat(Symbol *s);
        static void setcodeseg(int seg);
        seg_data *tlsseg();
        seg_data *tlsseg_bss();
        static seg_data *tlsseg_data();
        static int  fardata(char *name, targ_size_t size, targ_size_t *poffset);
        static void export_symbol(Symbol *s, uint argsize);
        static void pubdef(int seg, Symbol *s, targ_size_t offset);
        static void pubdefsize(int seg, Symbol *s, targ_size_t offset, targ_size_t symsize);
        static int external_def(const(char)* );
        static int data_start(Symbol *sdata, targ_size_t datasize, int seg);
        static int external(Symbol *);
        static int common_block(Symbol *s, targ_size_t size, targ_size_t count);
        static int common_block(Symbol *s, int flag, targ_size_t size, targ_size_t count);
        static void lidata(int seg, targ_size_t offset, targ_size_t count);
        static void write_zeros(seg_data *pseg, targ_size_t count);
        static void write_byte(seg_data *pseg, uint _byte);
        static void write_bytes(seg_data *pseg, uint nbytes, void *p);
        static void _byte(int seg, targ_size_t offset, uint _byte);
        static uint bytes(int seg, targ_size_t offset, uint nbytes, void *p);
        static void ledata(int seg, targ_size_t offset, targ_size_t data, uint lcfd, uint idx1, uint idx2);
        static void write_long(int seg, targ_size_t offset, uint data, uint lcfd, uint idx1, uint idx2);
        static void reftodatseg(int seg, targ_size_t offset, targ_size_t val, uint targetdatum, int flags);
        static void reftofarseg(int seg, targ_size_t offset, targ_size_t val, int farseg, int flags);
        static void reftocodeseg(int seg, targ_size_t offset, targ_size_t val);
        static int reftoident(int seg, targ_size_t offset, Symbol *s, targ_size_t val, int flags);
        static void far16thunk(Symbol *s);
        static void fltused();
        static int data_readonly(char *p, int len, int *pseg);
        static int data_readonly(char *p, int len);
        static int string_literal_segment(uint sz);
        static Symbol *sym_cdata(tym_t, char *, int);
        static void func_start(Symbol *sfunc);
        static void func_term(Symbol *sfunc);
        static void write_pointerRef(Symbol* s, uint off);
        static int jmpTableSegment(Symbol* s);

        static Symbol *tlv_bootstrap();

        static void gotref(Symbol *s);

        static  uint addstr(Outbuffer *strtab, const(char)* );
        static Symbol *getGOTsym();
        static void refGOTsym();
    }

    version (OSX)
    {
        class MachObj : Obj
        {
          public:
            static int getsegment(const(char)* sectname, const(char)* segname,
                int  _align, int flags);
            static void addrel(int seg, targ_size_t offset, Symbol *targsym,
                 uint targseg, int rtype, int val = 0);
        }

        class MachObj64 : MachObj
        {
          public:
            override seg_data *tlsseg();
            override seg_data *tlsseg_bss();
        }
    }
    else
    {
        class ElfObj : Obj
        {
          public:
            static int getsegment(const(char)* name, const(char)* suffix,
                int type, int flags, int  _align);
            static void addrel(int seg, targ_size_t offset, uint type,
                                uint symidx, targ_size_t val);
            static size_t writerel(int targseg, size_t offset, uint type,
                                    uint symidx, targ_size_t val);
        }
    }
}
else version (STUB)
{
    public import stubobj;
}
else
    static assert(0, "unsupported version");


extern __gshared Obj objmod;

