瀏覽代碼

* correctly handle PE COMDAT sections: like for the Comdat groups in ELF files the unused symbols need to be converted to externals so that relocations are handled correctly

git-svn-id: trunk@43359 -
svenbarth 5 年之前
父節點
當前提交
ccb169b0f1
共有 1 個文件被更改,包括 42 次插入20 次删除
  1. 42 20
      compiler/ogbase.pas

+ 42 - 20
compiler/ogbase.pas

@@ -2548,8 +2548,10 @@ implementation
           j      : longint;
           hs     : string;
           exesym : TExeSymbol;
+          tmpsym,
           objsym : TObjSymbol;
           grp    : TObjSectionGroup;
+          makeexternal : boolean;
         begin
           for j:=0 to ObjData.ObjSymbolList.Count-1 do
             begin
@@ -2607,26 +2609,20 @@ implementation
                 begin
                   exesym:=texesymbol.Create(FExeSymbolList,objsym.name);
                   exesym.ObjSymbol:=objsym;
-                end;
-              objsym.ExeSymbol:=exesym;
-              case objsym.bind of
-                AB_GLOBAL,
-                AB_PRIVATE_EXTERN:
-                  begin
-                    if exesym.State<>symstate_defined then
-                      begin
-                        exesym.ObjSymbol:=objsym;
-                        exesym.State:=symstate_defined;
-                      end
-                    else
+                end
+              else
+                begin
+                  if assigned(objsym.objsection) and assigned(exesym.objsymbol.objsection) then
+                    begin
                       if (oso_comdat in exesym.ObjSymbol.objsection.SecOptions) and
                          (oso_comdat in objsym.objsection.SecOptions) then
                         begin
                           if exesym.ObjSymbol.objsection.ComdatSelection=objsym.objsection.ComdatSelection then
                             begin
+                              makeexternal:=true;
                               case objsym.objsection.ComdatSelection of
                                 oscs_none:
-                                  Message1(link_e_duplicate_symbol,objsym.name);
+                                  makeexternal:=false;
                                 oscs_any:
                                   Message1(link_d_comdat_discard_any,objsym.name);
                                 oscs_same_size:
@@ -2641,22 +2637,48 @@ implementation
                                     Message1(link_d_comdat_discard_content,objsym.name);
                                 oscs_associative:
                                   { this is handled in a different way }
-                                  Message1(link_e_duplicate_symbol,objsym.name);
+                                  makeexternal:=false;
                                 oscs_largest:
                                   if objsym.size>exesym.ObjSymbol.size then
                                     begin
                                       Message1(link_d_comdat_replace_size,objsym.name);
-                                      exesym.ObjSymbol.exesymbol:=nil;
-                                      exesym.ObjSymbol:=objsym;
+                                      { we swap the symbols and turn the smaller one to an external
+                                        symbol }
+                                      tmpsym:=exesym.objsymbol;
+                                      exesym.objsymbol:=objsym;
+                                      objsym.exesymbol:=exesym;
+                                      objsym:=tmpsym;
                                     end;
                               end;
+                              if makeexternal then
+                                begin
+                                  { Undefine the symbol, causing relocations to it from same
+                                    objdata to be redirected to the symbol that is actually
+                                    used }
+                                  if objsym.bind=AB_GLOBAL then
+                                    objsym.bind:=AB_EXTERNAL;
+                                  { AB_WEAK_EXTERNAL remains unchanged }
+                                  objsym.objsection:=nil;
+                                end;
                             end
                           else
                             Message1(link_e_comdat_selection_differs,objsym.name);
-                        end
-                      else
-                        { specific error if ComDat flags are different? }
-                        Message1(link_e_duplicate_symbol,objsym.name);
+                        end;
+                    end;
+                end;
+
+              objsym.ExeSymbol:=exesym;
+              case objsym.bind of
+                AB_GLOBAL,
+                AB_PRIVATE_EXTERN:
+                  begin
+                    if exesym.State<>symstate_defined then
+                      begin
+                        exesym.ObjSymbol:=objsym;
+                        exesym.State:=symstate_defined;
+                      end
+                    else
+                      Message1(link_e_duplicate_symbol,objsym.name);
 
                     { hidden symbols must become local symbols in the executable }
                     if objsym.bind=AB_PRIVATE_EXTERN then