|
@@ -185,6 +185,32 @@ type
|
|
|
{ array of caggregateinformation instances }
|
|
|
faggregateinformation: tfpobjectlist;
|
|
|
|
|
|
+ { Support for generating data that is only referenced from the typed
|
|
|
+ constant data that we are currently generated. Such data can all be put
|
|
|
+ in the same dead-strippable unit, as it's either all included or none of
|
|
|
+ it is included. This data can be spread over multiple kinds of sections
|
|
|
+ though (e.g. rodata and rodata_no_rel), so per section keep track whether
|
|
|
+ we already started a dead-strippable unit and if so, what the section
|
|
|
+ name was (so that on platforms that perform the dead stripping based on
|
|
|
+ sections, we put all data for one typed constant into a single section
|
|
|
+ with the same name) }
|
|
|
+ protected type
|
|
|
+ tinternal_data_section_info = record
|
|
|
+ secname: TSymStr;
|
|
|
+ sectype: TAsmSectiontype;
|
|
|
+ end;
|
|
|
+ protected var
|
|
|
+ { all internally generated data must be stored in the same list, as it must
|
|
|
+ be consecutive (if it's spread over multiple lists, we don't know in
|
|
|
+ which order they'll be concatenated) -> keep track of this list }
|
|
|
+ finternal_data_asmlist: tasmlist;
|
|
|
+ { kind of the last section we started in the finternal_data_asmlist, to
|
|
|
+ avoid creating unnecessary section statements }
|
|
|
+ finternal_data_current_section: TAsmSectiontype;
|
|
|
+ { info about in which kinds of sections we have already emitted internal
|
|
|
+ data, and what their names were }
|
|
|
+ finternal_data_section_info: array of tinternal_data_section_info;
|
|
|
+
|
|
|
{ ensure that finalize_asmlist is called only once }
|
|
|
fasmlist_finalized: boolean;
|
|
|
|
|
@@ -203,12 +229,27 @@ type
|
|
|
location }
|
|
|
procedure pad_next_field(nextfielddef: tdef);
|
|
|
|
|
|
+ { returns the index in finternal_data_section_info of the info for the
|
|
|
+ section of type typ. Returns -1 if there is no such info yet }
|
|
|
+ function get_internal_data_section_index(typ: TAsmSectiontype): longint;
|
|
|
+
|
|
|
{ easy access to the top level aggregate information instance }
|
|
|
property curagginfo: taggregateinformation read getcurragginfo;
|
|
|
public
|
|
|
constructor create(const options: ttcasmlistoptions); virtual;
|
|
|
destructor destroy; override;
|
|
|
|
|
|
+ public
|
|
|
+ { returns a builder for generating data that is only referrenced by the
|
|
|
+ typed constant date we are currently generating (e.g. string data for a
|
|
|
+ pchar constant). Also returns the label that will be placed at the start
|
|
|
+ of that data. list is the tasmlist to which the data will be }
|
|
|
+ procedure start_internal_data_builder(list: tasmlist; sectype: TAsmSectiontype; out tcb: ttai_typedconstbuilder; out l: tasmlabel);
|
|
|
+ { finish a previously started internal data builder, including
|
|
|
+ concatenating all generated data to the provided list and freeing the
|
|
|
+ builder }
|
|
|
+ procedure finish_internal_data_builder(var tcb: ttai_typedconstbuilder; l: tasmlabel; def: tdef; alignment: longint);
|
|
|
+
|
|
|
{ add a simple constant data element (p) to the typed constant.
|
|
|
def is the type of the added value }
|
|
|
procedure emit_tai(p: tai; def: tdef); virtual;
|
|
@@ -649,6 +690,15 @@ implementation
|
|
|
end;
|
|
|
|
|
|
|
|
|
+ function ttai_typedconstbuilder.get_internal_data_section_index(typ: TAsmSectiontype): longint;
|
|
|
+ begin
|
|
|
+ for result:=low(finternal_data_section_info) to high(finternal_data_section_info) do
|
|
|
+ if finternal_data_section_info[result].sectype=typ then
|
|
|
+ exit;
|
|
|
+ result:=-1;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
function ttai_typedconstbuilder.aggregate_kind(def: tdef): ttypedconstkind;
|
|
|
begin
|
|
|
if (def.typ in [recorddef,filedef,variantdef]) or
|
|
@@ -771,6 +821,7 @@ implementation
|
|
|
foptions:=options;
|
|
|
{ queue is empty }
|
|
|
fqueue_offset:=low(fqueue_offset);
|
|
|
+ finternal_data_current_section:=sec_none;
|
|
|
end;
|
|
|
|
|
|
|
|
@@ -785,6 +836,99 @@ implementation
|
|
|
end;
|
|
|
|
|
|
|
|
|
+ procedure ttai_typedconstbuilder.start_internal_data_builder(list: tasmlist; sectype: TAsmSectiontype; out tcb: ttai_typedconstbuilder; out l: tasmlabel);
|
|
|
+ var
|
|
|
+ options: ttcasmlistoptions;
|
|
|
+ foundsec: longint;
|
|
|
+ begin
|
|
|
+ options:=[tcalo_is_lab];
|
|
|
+ { Add a section header if the previous one was different. We'll use the
|
|
|
+ same section name in case multiple items are added to the same kind of
|
|
|
+ section (rodata, rodata_no_rel, ...), so that everything will still
|
|
|
+ end up in the same section even if there are multiple section headers }
|
|
|
+ if finternal_data_current_section<>sectype then
|
|
|
+ include(options,tcalo_new_section);
|
|
|
+ finternal_data_current_section:=sectype;
|
|
|
+ l:=nil;
|
|
|
+ { did we already create a section of this type for the internal data of
|
|
|
+ this builder? }
|
|
|
+ foundsec:=get_internal_data_section_index(sectype);
|
|
|
+ if foundsec=-1 then
|
|
|
+ begin
|
|
|
+ { we only need to start a dead-strippable section of data at the
|
|
|
+ start of the first subsection of this kind for this block.
|
|
|
+
|
|
|
+ exception: if dead stripping happens based on objects/libraries,
|
|
|
+ then we only have to create a new object file for the first
|
|
|
+ internal data section of any kind (all the rest will simply be put
|
|
|
+ in the same object file) }
|
|
|
+ if create_smartlink then
|
|
|
+ begin
|
|
|
+ if not create_smartlink_library or
|
|
|
+ (length(finternal_data_section_info)=0) then
|
|
|
+ include(options,tcalo_make_dead_strippable);
|
|
|
+ { on Darwin, dead code/data stripping happens based on non-
|
|
|
+ temporary labels (any label that doesn't start with "L" -- it
|
|
|
+ doesn't have to be global) -> add a non-temporary lobel at the
|
|
|
+ start of every kind of subsection created in this builder }
|
|
|
+ if target_info.system in systems_darwin then
|
|
|
+ current_asmdata.getstaticdatalabel(l)
|
|
|
+ end;
|
|
|
+ foundsec:=length(finternal_data_section_info);
|
|
|
+ setlength(finternal_data_section_info,foundsec+1);
|
|
|
+ finternal_data_section_info[foundsec].sectype:=sectype;
|
|
|
+ end;
|
|
|
+ if not assigned(finternal_data_asmlist) and
|
|
|
+ (cs_create_smart in current_settings.moduleswitches) then
|
|
|
+ begin
|
|
|
+ { on Darwin, dead code/data stripping happens based on non-temporary
|
|
|
+ labels (any label that doesn't start with "L" -- it doesn't have
|
|
|
+ to be global) }
|
|
|
+ if target_info.system in systems_darwin then
|
|
|
+ current_asmdata.getstaticdatalabel(l)
|
|
|
+ else if create_smartlink_library then
|
|
|
+ current_asmdata.getglobaldatalabel(l);
|
|
|
+ { the internal data list should only be assigned by this routine,
|
|
|
+ the first time that an internal data block is started }
|
|
|
+ if not assigned(list) or
|
|
|
+ assigned(finternal_data_asmlist) then
|
|
|
+ internalerror(2015032101);
|
|
|
+ finternal_data_asmlist:=list;
|
|
|
+ end
|
|
|
+ { all internal data for this tcb must go to the same list (otherwise all
|
|
|
+ data we want to add to the dead-strippable block is not guaranteed to
|
|
|
+ be sequential and e.g. in the same object file in case of library-based
|
|
|
+ dead stripping) }
|
|
|
+ else if (assigned(finternal_data_asmlist) and
|
|
|
+ (list<>finternal_data_asmlist)) or
|
|
|
+ not assigned(list) then
|
|
|
+ internalerror(2015032101);
|
|
|
+ finternal_data_asmlist:=list;
|
|
|
+ if not assigned(l) then
|
|
|
+ if create_smartlink_library then
|
|
|
+ { all labels need to be global in case they're in another object }
|
|
|
+ current_asmdata.getglobaldatalabel(l)
|
|
|
+ else
|
|
|
+ { no special requirement for the label -> just get a local one }
|
|
|
+ current_asmdata.getlocaldatalabel(l);
|
|
|
+ { first section of this kind -> set name }
|
|
|
+ if finternal_data_section_info[foundsec].secname='' then
|
|
|
+ finternal_data_section_info[foundsec].secname:=l.Name;
|
|
|
+ tcb:=ttai_typedconstbuilderclass(classtype).create(options);
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
+ procedure ttai_typedconstbuilder.finish_internal_data_builder(var tcb: ttai_typedconstbuilder; l: tasmlabel; def: tdef; alignment: longint);
|
|
|
+ begin
|
|
|
+ finternal_data_asmlist.concatList(tcb.get_final_asmlist(l,def,
|
|
|
+ finternal_data_current_section,
|
|
|
+ finternal_data_section_info[get_internal_data_section_index(finternal_data_current_section)].secname,
|
|
|
+ alignment));
|
|
|
+ tcb.free;
|
|
|
+ tcb:=nil;
|
|
|
+ end;
|
|
|
+
|
|
|
+
|
|
|
procedure ttai_typedconstbuilder.emit_tai(p: tai; def: tdef);
|
|
|
var
|
|
|
kind: ttypedconstkind;
|