From 95bea696ca37a3fa550eef97135d86b1826d1b09 Mon Sep 17 00:00:00 2001 From: svenbarth <pascaldragon@googlemail.com> Date: Fri, 3 Feb 2017 22:36:58 +0000 Subject: [PATCH] + add ability to read Big Obj COFF files as generated by MSVC with /bigobj and GNU AS with -mbig-obj (starting from version 2.25); this format allows 2^31 sections per COFF file instead of 2^16, thus solving the problem of compiling packages\odata\src\sharepoint.pp Note: the field names of tcoffbigobjheader and coffbigobjsymbol are inspired from the field names of the structs declared in LLVM git-svn-id: trunk@35379 - --- compiler/ogcoff.pas | 186 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 153 insertions(+), 33 deletions(-) diff --git a/compiler/ogcoff.pas b/compiler/ogcoff.pas index b4e6a02055..629b461c57 100644 --- a/compiler/ogcoff.pas +++ b/compiler/ogcoff.pas @@ -53,6 +53,18 @@ interface opthdr : word; flag : word; end; + tcoffbigobjheader = packed record + Sig1 : word; + Sig2 : word; + Version : word; + Machine : word; + TimeDateStame : longword; + UUID : array[0..15] of byte; + unused : array[0..3] of longword; + NumberOfSections : longword; + PointerToSymbolTable : longword; + NumberOfSymbols : longword; + end; tcoffpeoptheader = packed record Magic : word; MajorLinkerVersion : byte; @@ -171,6 +183,7 @@ interface FSecCount : Longint; FSecTbl : ^TObjSectionArray; win32 : boolean; + bigobj : boolean; function GetSection(secidx:longint):TObjSection; function Read_str(strpos:longword):string; procedure read_relocs(s:TCoffObjSection); @@ -270,6 +283,8 @@ interface COFF_OPT_MAGIC = $20b; TLSDIR_SIZE = $28; {$endif x86_64} + COFF_BIG_OBJ_MAGIC: array[0..15] of byte = ($C7, $A1, $BA, $D1, $EE, $BA, $A9, $4B, $AF, $20, $FA, $F6, $6A, $A4, $DC, $B8); + COFF_BIG_OBJ_VERSION = 2; function ReadDLLImports(const dllname:string;readdllproc:Treaddllproc):boolean; implementation @@ -474,6 +489,10 @@ implementation sym : longword; reloctype : word; end; + strtableoffset=packed record + Zeroes : longword; + Offset : longword; + end; coffsymbol=packed record name : array[0..3] of char; { real is [0..7], which overlaps the strpos ! } strpos : longword; @@ -483,6 +502,18 @@ implementation typ : byte; aux : byte; end; + coffbigobjsymbol=packed record + Name : record + case boolean of + True: (ShortName : array[0..7] of char); + False: (Offset : strtableoffset) + end; + Value : longword; + SectionNumber : longword; + _Type : word; + StorageClass : byte; + NumberOfAuxSymbols : byte; + end; { This is defined in rtl/win/sysos.inc source } tlsdirectory=packed record @@ -1561,6 +1592,7 @@ const pemagic : array[0..3] of byte = ( begin inherited create; win32:=awin32; + bigobj:=false; FSymTbl:=nil; end; @@ -1696,22 +1728,31 @@ const pemagic : array[0..3] of byte = ( symidx : aint; i : longint; sym : coffsymbol; + bosym : coffbigobjsymbol; objsym : TObjSymbol; bind : Tasmsymbind; strname : string; - auxrec : array[0..17] of byte; + auxrec : array[0..sizeof(coffsymbol)-1] of byte; + boauxrec : array[0..sizeof(coffbigobjsymbol)-1] of byte; objsec : TObjSection; + secidx : longint; + symvalue : longword; + auxcount : byte; + symcls : byte; { keeps string manipulations out of main routine } procedure UnsupportedSymbolType; begin - Comment(V_Fatal,'Unsupported COFF symbol type '+tostr(sym.typ)+' at index '+tostr(symidx)+' while reading '+InputFileName); + Comment(V_Fatal,'Unsupported COFF symbol type '+tostr(symcls)+' at index '+tostr(symidx)+' while reading '+InputFileName); end; begin with TCoffObjData(objdata) do begin - nsyms:=FCoffSyms.Size div sizeof(CoffSymbol); + if bigobj then + nsyms:=FCoffSyms.Size div sizeof(coffbigobjsymbol) + else + nsyms:=FCoffSyms.Size div sizeof(CoffSymbol); { Allocate memory for symidx -> TObjSymbol table } FSymTbl:=AllocMem(nsyms*sizeof(TObjSymbol)); { Load the Symbols } @@ -1719,28 +1760,53 @@ const pemagic : array[0..3] of byte = ( symidx:=0; while (symidx<nsyms) do begin - FCoffSyms.Read(sym,sizeof(sym)); - if plongint(@sym.name)^<>0 then + if bigobj then begin - move(sym.name,strname[1],8); - strname[9]:=#0; - strname[0]:=chr(strlen(@strname[1])); - if strname='' then - Internalerror(200205171); + FCoffSyms.Read(bosym,sizeof(bosym)); + if bosym.Name.Offset.Zeroes<>0 then + begin + move(bosym.Name.ShortName,strname[1],8); + strname[9]:=#0; + strname[0]:=chr(strlen(@strname[1])); + if strname='' then + internalerror(2017020301); + end + else + strname:=Read_str(bosym.Name.Offset.Offset); + secidx:=longint(bosym.SectionNumber); + symvalue:=bosym.Value; + auxcount:=bosym.NumberOfAuxSymbols; + symcls:=bosym.StorageClass; end else - strname:=Read_str(sym.strpos); + begin + FCoffSyms.Read(sym,sizeof(sym)); + if plongint(@sym.name)^<>0 then + begin + move(sym.name,strname[1],8); + strname[9]:=#0; + strname[0]:=chr(strlen(@strname[1])); + if strname='' then + Internalerror(200205171); + end + else + strname:=Read_str(sym.strpos); + secidx:=sym.section; + symvalue:=sym.value; + auxcount:=sym.aux; + symcls:=sym.typ; + end; bind:=AB_EXTERNAL; size:=0; address:=0; objsym:=nil; objsec:=nil; - case sym.typ of + case symcls of COFF_SYM_GLOBAL : begin - if sym.section=0 then + if secidx=0 then begin - if sym.value=0 then + if symvalue=0 then bind:=AB_EXTERNAL else begin @@ -1751,9 +1817,9 @@ const pemagic : array[0..3] of byte = ( else begin bind:=AB_GLOBAL; - objsec:=GetSection(word(sym.section)); - if sym.value>=objsec.mempos then - address:=sym.value-objsec.mempos; + objsec:=GetSection(secidx); + if symvalue>=objsec.mempos then + address:=symvalue-objsec.mempos; end; objsym:=CreateSymbol(strname); objsym.bind:=bind; @@ -1766,11 +1832,11 @@ const pemagic : array[0..3] of byte = ( COFF_SYM_LOCAL : begin { do not add constants (section=-1) } - if sym.section<>-1 then + if secidx<>-1 then begin - objsec:=GetSection(word(sym.section)); - if sym.value>=objsec.mempos then - address:=sym.value-objsec.mempos; + objsec:=GetSection(secidx); + if symvalue>=objsec.mempos then + address:=symvalue-objsec.mempos; objsym:=CreateSymbol(strname); objsym.bind:=AB_LOCAL; objsym.typ:=AT_FUNCTION; @@ -1782,11 +1848,11 @@ const pemagic : array[0..3] of byte = ( COFF_SYM_SECTION : begin { GetSection checks that index is in range } - objsec:=GetSection(word(sym.section)); + objsec:=GetSection(secidx); if assigned(objsec) then begin - if sym.value>=objsec.mempos then - address:=sym.value-objsec.mempos; + if symvalue>=objsec.mempos then + address:=symvalue-objsec.mempos; objsym:=CreateSymbol(strname); objsym.bind:=AB_LOCAL; objsym.typ:=AT_FUNCTION; @@ -1803,9 +1869,12 @@ const pemagic : array[0..3] of byte = ( end; FSymTbl^[symidx]:=objsym; { read aux records } - for i:=1 to sym.aux do + for i:=1 to auxcount do begin - FCoffSyms.Read(auxrec,sizeof(auxrec)); + if bigobj then + FCoffSyms.Read(boauxrec,sizeof(boauxrec)) + else + FCoffSyms.Read(auxrec,sizeof(auxrec)); inc(symidx); end; inc(symidx); @@ -1836,12 +1905,17 @@ const pemagic : array[0..3] of byte = ( function TCoffObjInput.ReadObjData(AReader:TObjectreader;out objdata:TObjData):boolean; var secalign : shortint; + secofs, strpos, i : longint; + sympos, + symcount, + symsize, code : longint; objsec : TCoffObjSection; secoptions : TObjSectionOptions; header : tcoffheader; + boheader : tcoffbigobjheader; sechdr : tcoffsechdr; secname : string; secnamebuf : array[0..15] of char; @@ -1859,7 +1933,34 @@ const pemagic : array[0..3] of byte = ( InputError('Can''t read COFF Header'); exit; end; - if header.mach<>COFF_MAGIC then + if (header.mach=0) and (header.nsects=$ffff) then + begin + { either a library or big obj COFF } + AReader.seek(0); + if not AReader.read(boheader,sizeof(boheader)) then + begin + InputError('Can''t read Big Obj COFF Header'); + exit; + end; + if CompareByte(boheader.UUID,COFF_BIG_OBJ_MAGIC,length(boheader.uuid))<>0 then + begin + { ToDo: this should be treated as a library } + InputError('Illegal Big Obj COFF Magic'); + exit; + end; + if boheader.Version<>COFF_BIG_OBJ_VERSION then + begin + InputError('Illegal Big Obj COFF Version'); + exit; + end; + if boheader.Machine<>COFF_MAGIC then + begin + InputError('Illegal COFF Machine type'); + exit; + end; + bigobj:=true; + end + else if header.mach<>COFF_MAGIC then begin InputError('Illegal COFF Magic'); exit; @@ -1868,8 +1969,20 @@ const pemagic : array[0..3] of byte = ( eVCobj:=header.flag=$100; {$endif arm} { ObjSymbols } - AReader.Seek(header.sympos); - if not AReader.ReadArray(FCoffSyms,header.syms*sizeof(CoffSymbol)) then + if bigobj then + begin + sympos:=longint(boheader.PointerToSymbolTable); + symcount:=longint(boheader.NumberOfSymbols); + symsize:=sizeof(CoffBigObjSymbol); + end + else + begin + sympos:=longint(header.sympos); + symcount:=longint(header.syms); + symsize:=sizeof(CoffSymbol); + end; + AReader.Seek(sympos); + if not AReader.ReadArray(FCoffSyms,symcount*symsize) then begin InputError('Error reading coff symbol table'); exit; @@ -1895,10 +2008,17 @@ const pemagic : array[0..3] of byte = ( end; { Section headers } { Allocate SecIdx -> TObjSection table, secidx is 1-based } - FSecCount:=header.nsects; - FSecTbl:=AllocMem((header.nsects+1)*sizeof(TObjSection)); - AReader.Seek(sizeof(tcoffheader)+header.opthdr); - for i:=1 to header.nsects do + if bigobj then + FSecCount:=longint(boheader.NumberOfSections) + else + FSecCount:=header.nsects; + FSecTbl:=AllocMem((FSecCount+1)*sizeof(TObjSection)); + if bigobj then + secofs:=sizeof(tcoffbigobjheader) + else + secofs:=sizeof(tcoffheader)+header.opthdr; + AReader.Seek(secofs); + for i:=1 to FSecCount do begin if not AReader.read(sechdr,sizeof(sechdr)) then begin