* Rework of Android startup code. It is needed to always link to libc on android to implement finalization and environment variables in shared libraries.

* Cleanup of Android linker.
* Use only INSERT command in the linker script to inject custom .fpc sections. Whole linker script duplication is nor needed anymore.
* Use BFD linker, since GOLD linker does not support INSERT command. Other incompatibilities may also exist.
* Enable tf_smartlink_sections for i386-android.
* i386-android is broken after this commit. Will be fixed later.

git-svn-id: branches/targetandroid@23284 -
This commit is contained in:
yury 2013-01-01 23:49:12 +00:00
parent f37a18f600
commit 6ccb152647
4 changed files with 227 additions and 606 deletions

View File

@ -97,7 +97,7 @@ unit i_android;
system : system_i386_ANDROID;
name : 'Android for i386';
shortname : 'Android';
flags : [tf_needs_symbol_size,tf_pic_uses_got{,tf_smartlink_sections}{,tf_winlikewidestring},
flags : [tf_needs_symbol_size,tf_pic_uses_got,tf_smartlink_sections,
tf_needs_symbol_type,tf_files_case_sensitive,
tf_smartlink_library,tf_needs_dwarf_cfi,tf_has_winlike_resources,
tf_safecall_exceptions, tf_safecall_clearstack];

View File

@ -40,15 +40,16 @@ interface
procedure setfininame(list: TAsmList; const s: string); override;
end;
{ tlinkerandroid }
tlinkerandroid=class(texternallinker)
private
libctype:(bionic);
cprtobj,
gprtobj,
prtobj : string[80];
reorder : boolean;
linklibc: boolean;
Function WriteResponseFile(isdll:boolean) : Boolean;
function GetLdOptions: string;
function DoLink(IsSharedLib: boolean): boolean;
public
constructor Create;override;
procedure SetDefaultInfo;override;
@ -124,36 +125,24 @@ const
{$ifdef i386} platform_select='';{$endif} {unknown :( }
var
defdynlinker: string;
s: string;
begin
with Info do
begin
ExeCmd[1]:='ld '+platform_select+' $OPT $DYNLINK $STATIC $GCSECTIONS $STRIP -L. -o $EXE';
{ when we want to cross-link we need to override default library paths }
if length(sysrootpath) > 0 then
ExeCmd[1]:=ExeCmd[1]+' -T';
ExeCmd[1]:=ExeCmd[1]+' $RES';
DllCmd[1]:='ld '+platform_select+' $OPT $INIT $FINI $SONAME -shared -L. -o $EXE $RES';
{ Specify correct max-page-size and common-page-size to prevent big gaps between sections in resulting executable }
s:='ld '+platform_select+'-z max-page-size=0x1000 -z common-page-size=0x1000 $OPT -L. -T $RES -o $EXE';
ExeCmd[1]:=s + ' --entry=_fpc_start';
DllCmd[1]:=s + ' -shared -soname $SONAME';
DllCmd[2]:='strip --strip-unneeded $EXE';
ExtDbgCmd[1]:='objcopy --only-keep-debug $EXE $DBG';
ExtDbgCmd[2]:='objcopy --add-gnu-debuglink=$DBG $EXE';
ExtDbgCmd[3]:='strip --strip-unneeded $EXE';
defdynlinker:='/system/bin/linker';
{
There is only one C library on android, the bionic libc
}
libctype:=bionic;
if fileexists(sysrootpath+defdynlinker,false) then
begin
DynamicLinker:=defdynlinker;
end
else
begin
{ when no dyn. linker is found, we are probably
cross compiling, so use the default dyn. linker }
DynamicLinker:=defdynlinker;
end;
DynamicLinker:='/system/bin/linker';
end;
end;
@ -173,59 +162,12 @@ Begin
End;
Procedure TLinkerAndroid.InitSysInitUnitName;
var
csysinitunit,
gsysinitunit : string[20];
hp : tmodule;
begin
hp:=tmodule(loaded_units.first);
while assigned(hp) do
begin
linklibc := hp.linkothersharedlibs.find('c');
if linklibc then break;
hp:=tmodule(hp.next);
end;
reorder := linklibc and ReOrderEntries;
reorder := ReOrderEntries;
if current_module.islibrary then
begin
sysinitunit:='dll';
csysinitunit:='dll';
gsysinitunit:='dll';
prtobj:='dllprt0';
cprtobj:='dllprt0';
gprtobj:='dllprt0';
end
prtobj:='dllprt0'
else
begin
prtobj:='prt0';
sysinitunit:='prc';
case libctype of
bionic:
begin
cprtobj:='cprt0';
gprtobj:='gprt0';
csysinitunit:='c';
gsysinitunit:='g';
end
else
runerror(2012080901);
end;
end;
if cs_profile in current_settings.moduleswitches then
begin
prtobj:=gprtobj;
sysinitunit:=gsysinitunit;
linklibc:=true;
end
else
begin
if linklibc then
begin
prtobj:=cprtobj;
sysinitunit:=csysinitunit;
end;
end;
sysinitunit:='si_'+sysinitunit;
prtobj:='prt0';
end;
Function TLinkerAndroid.WriteResponseFile(isdll:boolean) : Boolean;
@ -233,17 +175,11 @@ Var
linkres : TLinkRes;
i : longint;
HPath : TCmdStrListItem;
s,s1,s2 : TCmdStr;
found1,
found2 : boolean;
linksToSharedLibFiles : boolean;
s,s1 : TCmdStr;
begin
result:=False;
{ set special options for some targets }
if cs_profile in current_settings.moduleswitches then
begin
AddSharedLibrary('c');
end;
{ Always link to libc }
AddSharedLibrary('c');
{ Open link.res file }
LinkRes:=TLinkRes.Create(outputexedir+Info.ResName,true);
@ -289,26 +225,17 @@ begin
StartSection('INPUT(');
{ add objectfiles, start with prt0 always }
if not (target_info.system in systems_internal_sysinit) and (prtobj<>'') then
AddFileName(maybequoted(FindObjectFile(prtobj,'',false)));
{ try to add crti and crtbegin if linking to C }
if linklibc then
begin
{ crti.o must come first }
if librarysearchpath.FindFile('crti.o',false,s) then
AddFileName(s);
{ then the crtbegin* }
if cs_create_pic in current_settings.moduleswitches then
begin
if librarysearchpath.FindFile('crtbeginS.o',false,s) then
AddFileName(s);
end
else
if (cs_link_staticflag in current_settings.globalswitches) and
librarysearchpath.FindFile('crtbeginT.o',false,s) then
AddFileName(s)
else if librarysearchpath.FindFile('crtbegin.o',false,s) then
AddFileName(s);
end;
AddFileName(maybequoted(FindObjectFile(prtobj,'',false)));
{ Add libc startup object file }
if isdll then
s:='crtbegin_so.o'
else
if cs_link_staticflag in current_settings.globalswitches then
s:='crtbegin_static.o'
else
s:='crtbegin_dynamic.o';
librarysearchpath.FindFile(s,false,s1);
AddFileName(s1);
{ main objectfiles }
while not ObjectFiles.Empty do
begin
@ -335,45 +262,24 @@ begin
ExpandAndApplyOrder(SharedLibFiles);
// after this point addition of shared libs not allowed.
{ Write sharedlibraries like -l<lib>, also add the needed dynamic linker
here to be sure that it gets linked this is needed for glibc2 systems (PFV) }
if (isdll) then
begin
Add('INPUT(');
Add(info.DynamicLinker);
Add(')');
end;
linksToSharedLibFiles := not SharedLibFiles.Empty;
if not SharedLibFiles.Empty then
begin
if (SharedLibFiles.Count<>1) or
(TCmdStrListItem(SharedLibFiles.First).Str<>'c') or
reorder then
if (SharedLibFiles.Count<>1) or reorder then
begin
Add('INPUT(');
While not SharedLibFiles.Empty do
begin
S:=SharedLibFiles.GetFirst;
if (s<>'c') or reorder then
begin
i:=Pos(target_info.sharedlibext,S);
if i>0 then
Delete(S,i,255);
Add('-l'+s);
end
else
begin
linklibc:=true;
end;
i:=Pos(target_info.sharedlibext,S);
if i>0 then
Delete(S,i,255);
Add('-l'+s);
end;
Add(')');
end
else
linklibc:=true;
end;
if (cs_link_staticflag in current_settings.globalswitches) or
(linklibc and not reorder) then
(not reorder) then
begin
Add('GROUP(');
{ when we have -static for the linker the we also need libgcc }
@ -384,262 +290,34 @@ begin
Add('-lgcc_eh');
end;
{ be sure that libc is the last lib }
if linklibc and not reorder then
if not reorder then
Add('-lc');
Add(')');
end;
end;
{ objects which must be at the end }
if linklibc then
begin
if cs_create_pic in current_settings.moduleswitches then
found1:=librarysearchpath.FindFile('crtendS.o',false,s1)
else
found1:=librarysearchpath.FindFile('crtend.o',false,s1);
found2:=librarysearchpath.FindFile('crtn.o',false,s2);
if found1 or found2 then
begin
Add('INPUT(');
if found1 then
AddFileName(s1);
if found2 then
AddFileName(s2);
Add(')');
end;
end;
{ Add libc finalization object file }
Add('INPUT(');
if isdll then
s:='crtend_so.o'
else
s:='crtend_android.o';
librarysearchpath.FindFile(s,false,s1);
AddFileName(s1);
Add(')');
{Entry point. Only needed for executables, set on the linker command line for
shared libraries. }
if (not isdll) then
if (linksToSharedLibFiles and not linklibc) then
add('ENTRY(_dynamic_start)')
else
add('ENTRY(_start)');
{ Additions to the linker script }
{$ifdef ARM}
if target_info.abi=abi_eabi then
begin
{ from GNU ld (CodeSourcery Sourcery G++ Lite 2007q3-53) 2.18.50.20070820 }
add('/* Script for -z combreloc: combine and sort reloc sections */');
add('OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm",');
add(' "elf32-littlearm")');
add('OUTPUT_ARCH(arm)');
add('SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");');
add('SECTIONS');
add('{');
add(' /* Read-only sections, merged into text segment: */');
add(' PROVIDE (__executable_start = 0x8000); . = 0x8000 + SIZEOF_HEADERS;');
add(' .interp : { *(.interp) }');
add(' .note.gnu.build-id : { *(.note.gnu.build-id) }');
add(' .hash : { *(.hash) }');
add(' .gnu.hash : { *(.gnu.hash) }');
add(' .dynsym : { *(.dynsym) }');
add(' .dynstr : { *(.dynstr) }');
add(' .gnu.version : { *(.gnu.version) }');
add(' .gnu.version_d : { *(.gnu.version_d) }');
add(' .gnu.version_r : { *(.gnu.version_r) }');
add(' .rel.dyn :');
add(' {');
add(' *(.rel.init)');
add(' *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*)');
add(' *(.rel.fini)');
add(' *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*)');
add(' *(.rel.data.rel.ro* .rel.gnu.linkonce.d.rel.ro.*)');
add(' *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*)');
add(' *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*)');
add(' *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*)');
add(' *(.rel.ctors)');
add(' *(.rel.dtors)');
add(' *(.rel.got)');
add(' *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*)');
add(' }');
add(' .rela.dyn :');
add(' {');
add(' *(.rela.init)');
add(' *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)');
add(' *(.rela.fini)');
add(' *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)');
add(' *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)');
add(' *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)');
add(' *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)');
add(' *(.rela.ctors)');
add(' *(.rela.dtors)');
add(' *(.rela.got)');
add(' *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)');
add(' }');
add(' .rel.plt : { *(.rel.plt) }');
add(' .rela.plt : { *(.rela.plt) }');
add(' .init :');
add(' {');
add(' KEEP (*(.init))');
add(' } =0');
add(' .plt : { *(.plt) }');
add(' .text :');
add(' {');
add(' *(.text .stub .text.* .gnu.linkonce.t.*)');
add(' KEEP (*(.text.*personality*))');
add(' /* .gnu.warning sections are handled specially by elf32.em. */');
add(' *(.gnu.warning)');
add(' *(.glue_7t) *(.glue_7) *(.vfp11_veneer)');
add(' } =0');
add(' .fini :');
add(' {');
add(' KEEP (*(.fini))');
add(' } =0');
add(' PROVIDE (__etext = .);');
add(' PROVIDE (_etext = .);');
add(' PROVIDE (etext = .);');
add(' .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }');
add(' .rodata1 : { *(.rodata1) }');
add(' .ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) }');
add(' __exidx_start = .;');
add(' .ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) }');
add(' __exidx_end = .;');
add(' .eh_frame_hdr : { *(.eh_frame_hdr) }');
add(' .eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }');
add(' .gcc_except_table : ONLY_IF_RO { *(.gcc_except_table .gcc_except_table.*) }');
add(' /* Adjust the address for the data segment. We want to adjust up to');
add(' the same address within the page on the next page up. */');
add(' . = ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1));');
add(' /* Exception handling */');
add(' .eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }');
add(' .gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }');
add(' /* Thread Local Storage sections */');
add(' .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }');
add(' .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }');
add(' .preinit_array :');
add(' {');
add(' PROVIDE_HIDDEN (__preinit_array_start = .);');
add(' KEEP (*(.preinit_array))');
add(' PROVIDE_HIDDEN (__preinit_array_end = .);');
add(' }');
add(' .init_array :');
add(' {');
add(' PROVIDE_HIDDEN (__init_array_start = .);');
add(' KEEP (*(SORT(.init_array.*)))');
add(' KEEP (*(.init_array))');
add(' PROVIDE_HIDDEN (__init_array_end = .);');
add(' }');
add(' .fini_array :');
add(' {');
add(' PROVIDE_HIDDEN (__fini_array_start = .);');
add(' KEEP (*(.fini_array))');
add(' KEEP (*(SORT(.fini_array.*)))');
add(' PROVIDE_HIDDEN (__fini_array_end = .);');
add(' }');
add(' .ctors :');
add(' {');
add(' /* gcc uses crtbegin.o to find the start of');
add(' the constructors, so we make sure it is');
add(' first. Because this is a wildcard, it');
add(' doesn''t matter if the user does not');
add(' actually link against crtbegin.o; the');
add(' linker won''t look for a file to match a');
add(' wildcard. The wildcard also means that it');
add(' doesn''t matter which directory crtbegin.o');
add(' is in. */');
add(' KEEP (*crtbegin.o(.ctors))');
add(' KEEP (*crtbegin?.o(.ctors))');
add(' /* We don''t want to include the .ctor section from');
add(' the crtend.o file until after the sorted ctors.');
add(' The .ctor section from the crtend file contains the');
add(' end of ctors marker and it must be last */');
add(' KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))');
add(' KEEP (*(SORT(.ctors.*)))');
add(' KEEP (*(.ctors))');
add(' }');
add(' .dtors :');
add(' {');
add(' KEEP (*crtbegin.o(.dtors))');
add(' KEEP (*crtbegin?.o(.dtors))');
add(' KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))');
add(' KEEP (*(SORT(.dtors.*)))');
add(' KEEP (*(.dtors))');
add(' }');
add(' .jcr : { KEEP (*(.jcr)) }');
add(' .data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro* .gnu.linkonce.d.rel.ro.*) }');
add(' .dynamic : { *(.dynamic) }');
add(' .got : { *(.got.plt) *(.got) }');
add(' .data :');
add(' {');
add(' __data_start = . ;');
add(' *(.data .data.* .gnu.linkonce.d.*)');
{ extra by FPC }
add(' KEEP (*(.fpc .fpc.n_version .fpc.n_links))');
add(' KEEP (*(.gnu.linkonce.d.*personality*))');
add(' SORT(CONSTRUCTORS)');
add(' }');
add(' .data1 : { *(.data1) }');
add(' _edata = .; PROVIDE (edata = .);');
add(' __bss_start = .;');
add(' __bss_start__ = .;');
add(' .bss :');
add(' {');
add(' *(.dynbss)');
add(' *(.bss .bss.* .gnu.linkonce.b.*)');
add(' *(COMMON)');
add(' /* Align here to ensure that the .bss section occupies space up to');
add(' _end. Align after .bss to ensure correct alignment even if the');
add(' .bss section disappears because there are no input sections.');
add(' FIXME: Why do we need it? When there is no .bss section, we don''t');
add(' pad the .data section. */');
add(' . = ALIGN(. != 0 ? 32 / 8 : 1);');
add(' }');
add(' _bss_end__ = . ; __bss_end__ = . ;');
add(' . = ALIGN(32 / 8);');
add(' . = ALIGN(32 / 8);');
add(' __end__ = . ;');
add(' _end = .; PROVIDE (end = .);');
add(' /* Stabs debugging sections. */');
add(' .stab 0 : { *(.stab) }');
add(' .stabstr 0 : { *(.stabstr) }');
add(' .stab.excl 0 : { *(.stab.excl) }');
add(' .stab.exclstr 0 : { *(.stab.exclstr) }');
add(' .stab.index 0 : { *(.stab.index) }');
add(' .stab.indexstr 0 : { *(.stab.indexstr) }');
add(' .comment 0 : { *(.comment) }');
add(' /* DWARF debug sections.');
add(' Symbols in the DWARF debugging sections are relative to the beginning');
add(' of the section so we begin them at 0. */');
add(' /* DWARF 1 */');
add(' .debug 0 : { *(.debug) }');
add(' .line 0 : { *(.line) }');
add(' /* GNU DWARF 1 extensions */');
add(' .debug_srcinfo 0 : { *(.debug_srcinfo) }');
add(' .debug_sfnames 0 : { *(.debug_sfnames) }');
add(' /* DWARF 1.1 and DWARF 2 */');
add(' .debug_aranges 0 : { *(.debug_aranges) }');
add(' .debug_pubnames 0 : { *(.debug_pubnames) }');
add(' /* DWARF 2 */');
add(' .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }');
add(' .debug_abbrev 0 : { *(.debug_abbrev) }');
add(' .debug_line 0 : { *(.debug_line) }');
add(' .debug_frame 0 : { *(.debug_frame) }');
add(' .debug_str 0 : { *(.debug_str) }');
add(' .debug_loc 0 : { *(.debug_loc) }');
add(' .debug_macinfo 0 : { *(.debug_macinfo) }');
add(' /* SGI/MIPS DWARF 2 extensions */');
add(' .debug_weaknames 0 : { *(.debug_weaknames) }');
add(' .debug_funcnames 0 : { *(.debug_funcnames) }');
add(' .debug_typenames 0 : { *(.debug_typenames) }');
add(' .debug_varnames 0 : { *(.debug_varnames) }');
add(' /* DWARF 3 */');
add(' .debug_pubtypes 0 : { *(.debug_pubtypes) }');
add(' .debug_ranges 0 : { *(.debug_ranges) }');
add(' .stack 0x80000 :');
add(' {');
add(' _stack = .;');
add(' *(.stack)');
add(' }');
add(' .ARM.attributes 0 : { KEEP (*(.ARM.attributes)) KEEP (*(.gnu.attributes)) }');
add(' .note.gnu.arm.ident 0 : { KEEP (*(.note.gnu.arm.ident)) }');
add(' /DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) }');
add('}');
end;
{$endif ARM}
add('SECTIONS');
add('{');
add(' .data :');
add(' {');
{ extra by FPC }
add(' KEEP (*(.fpc .fpc.n_version .fpc.n_links))');
add(' }');
add('}');
add('INSERT BEFORE .data1');
{ Write and Close response }
writetodisk;
@ -649,63 +327,87 @@ begin
WriteResponseFile:=True;
end;
function TLinkerAndroid.MakeExecutable:boolean;
var
i : longint;
binstr,
cmdstr : TCmdStr;
success : boolean;
DynLinkStr : string;
GCSectionsStr,
StaticStr,
StripStr : string[40];
function tlinkerandroid.GetLdOptions: string;
begin
if not(cs_link_nolink in current_settings.globalswitches) then
Message1(exec_i_linking,current_module.exefilename);
{ Create some replacements }
StaticStr:='';
StripStr:='';
GCSectionsStr:='';
DynLinkStr:='';
if (cs_link_staticflag in current_settings.globalswitches) then
StaticStr:='-static';
Result:='';
if (cs_link_strip in current_settings.globalswitches) and
not(cs_link_separate_dbg_file in current_settings.globalswitches) then
StripStr:='-s';
Result:=Result + ' -s';
if (cs_link_map in current_settings.globalswitches) then
StripStr:='-Map '+maybequoted(ChangeFileExt(current_module.exefilename,'.map'));
Result:=Result + ' -Map '+maybequoted(ChangeFileExt(current_module.exefilename,'.map'));
if create_smartlink_sections then
GCSectionsStr:='--gc-sections';
If (cs_profile in current_settings.moduleswitches) or
((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty)) then
begin
DynLinkStr:='--dynamic-linker='+Info.DynamicLinker;
if cshared then
DynLinkStr:=DynLinkStr+' --shared ';
if rlinkpath<>'' then
DynLinkStr:=DynLinkStr+' --rpath-link '+rlinkpath;
End;
Result:=Result + ' --gc-sections';
end;
function tlinkerandroid.DoLink(IsSharedLib: boolean): boolean;
var
i: longint;
binstr, cmdstr: TCmdStr;
s, opts, outname: string;
success: boolean;
begin
Result:=False;
if IsSharedLib then
outname:=current_module.sharedlibfilename
else
outname:=current_module.exefilename;
if not(cs_link_nolink in current_settings.globalswitches) then
Message1(exec_i_linking, outname);
opts:='';
if (cs_link_strip in current_settings.globalswitches) and
not (cs_link_separate_dbg_file in current_settings.globalswitches) then
opts:=opts + ' -s';
if (cs_link_map in current_settings.globalswitches) then
opts:=opts + ' -Map '+maybequoted(ChangeFileExt(outname,'.map'));
if create_smartlink_sections then
opts:=opts + ' --gc-sections';
if (cs_link_staticflag in current_settings.globalswitches) then
opts:=opts + ' -static'
else
if cshared then
opts:=opts + ' -call_shared';
if rlinkpath<>'' then
opts:=opts+' --rpath-link '+rlinkpath;
if not IsSharedLib then
begin
if (cs_profile in current_settings.moduleswitches) or
((Info.DynamicLinker<>'') and (not SharedLibFiles.Empty))
then
opts:=opts + ' --dynamic-linker=' + Info.DynamicLinker;
{ create dynamic symbol table? }
if HasExports then
opts:=opts+' -E';
end;
opts:=Trim(opts + ' ' + Info.ExtraOptions);
{ Write used files and libraries }
WriteResponseFile(false);
WriteResponseFile(IsSharedLib);
{ Call linker }
SplitBinCmd(Info.ExeCmd[1],binstr,cmdstr);
Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
Replace(cmdstr,'$OPT',Info.ExtraOptions);
if IsSharedLib then
s:=Info.DllCmd[1]
else
s:=Info.ExeCmd[1];
SplitBinCmd(s, binstr, cmdstr);
Replace(cmdstr,'$EXE',maybequoted(outname));
Replace(cmdstr,'$OPT',opts);
Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
Replace(cmdstr,'$STATIC',StaticStr);
Replace(cmdstr,'$STRIP',StripStr);
Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
Replace(cmdstr,'$DYNLINK',DynLinkStr);
if IsSharedLib then
Replace(cmdstr,'$SONAME',ExtractFileName(outname));
{ create dynamic symbol table? }
if HasExports then
cmdstr:=cmdstr+' -E';
binstr:=FindUtil(utilsprefix+BinStr);
{ We should use BFD version of LD, since GOLD version does not support INSERT command in linker scripts }
if binstr <> '' then begin
{ Checking if ld.bfd exists }
s:=ChangeFileExt(binstr, '.bfd' + source_info.exeext);
if FileExists(s, True) then
binstr:=s;
end;
success:=DoExec(FindUtil(utilsprefix+BinStr),CmdStr,true,false);
success:=DoExec(binstr,CmdStr,true,false);
{ Create external .dbg file with debuginfo }
if success and (cs_link_separate_dbg_file in current_settings.globalswitches) then
@ -713,7 +415,7 @@ begin
for i:=1 to 3 do
begin
SplitBinCmd(Info.ExtDbgCmd[i],binstr,cmdstr);
Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
Replace(cmdstr,'$EXE',maybequoted(outname));
Replace(cmdstr,'$DBGFN',maybequoted(extractfilename(current_module.dbgfilename)));
Replace(cmdstr,'$DBG',maybequoted(current_module.dbgfilename));
success:=DoExec(FindUtil(utilsprefix+BinStr),CmdStr,true,false);
@ -724,59 +426,19 @@ begin
{ Remove ReponseFile }
if (success) and not(cs_link_nolink in current_settings.globalswitches) then
DeleteFile(outputexedir+Info.ResName);
DeleteFile(outputexedir+Info.ResName);
MakeExecutable:=success; { otherwise a recursive call to link method }
Result:=success; { otherwise a recursive call to link method }
end;
function TLinkerAndroid.MakeExecutable:boolean;
begin
Result:=DoLink(False);
end;
Function TLinkerAndroid.MakeSharedLibrary:boolean;
var
InitStr,
FiniStr,
SoNameStr : string[80];
binstr,
cmdstr : TCmdStr;
success : boolean;
begin
MakeSharedLibrary:=false;
if not(cs_link_nolink in current_settings.globalswitches) then
Message1(exec_i_linking,current_module.sharedlibfilename);
{ Write used files and libraries }
WriteResponseFile(true);
{ Create some replacements }
{ note: linux does not use exportlib.initname/fininame due to the custom startup code }
InitStr:='-init FPC_SHARED_LIB_START';
FiniStr:='-fini FPC_LIB_EXIT';
SoNameStr:='-soname '+ExtractFileName(current_module.sharedlibfilename);
{ Call linker }
SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename));
Replace(cmdstr,'$OPT',Info.ExtraOptions);
Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
Replace(cmdstr,'$INIT',InitStr);
Replace(cmdstr,'$FINI',FiniStr);
Replace(cmdstr,'$SONAME',SoNameStr);
success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
{ Strip the library ? }
if success and (cs_link_strip in current_settings.globalswitches) then
begin
{ only remove non global symbols and debugging info for a library }
Info.DllCmd[2]:='strip --discard-all --strip-debug $EXE';
SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
Replace(cmdstr,'$EXE',maybequoted(current_module.sharedlibfilename));
success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
end;
{ Remove ReponseFile }
if (success) and not(cs_link_nolink in current_settings.globalswitches) then
DeleteFile(outputexedir+Info.ResName);
MakeSharedLibrary:=success; { otherwise a recursive call to link method }
Result:=DoLink(True);
end;
{*****************************************************************************

View File

@ -15,9 +15,6 @@
.file "dllprt0.as"
.text
.globl _startlib
.type _startlib,#function
_startlib:
.globl FPC_SHARED_LIB_START
.type FPC_SHARED_LIB_START,#function
FPC_SHARED_LIB_START:
@ -25,51 +22,51 @@ FPC_SHARED_LIB_START:
stmfd sp!,{fp, ip, lr, pc}
sub fp, ip, #4
/* registers do not contain any of the argc/argv/envp
information. They are zero by default anyway, so no
need to do anything else */
/* Save initial stackpointer */
ldr ip,=__stkptr
str sp,[ip]
/* save initial stackpointer */
ldr ip, =__stklen
str sp, [ip]
/* Get environment info from libc */
ldr ip,=environ
ldr r5,[ip]
ldr ip,=operatingsystem_parameter_envp
str r5,[ip]
/* Register exit handler. It is called only when the main process terminates */
ldr r0,=FPC_LIB_EXIT
bl atexit
/* call main and exit normally */
bl PASCALMAIN
ldmdb fp, {fp, sp, pc}
/* --------------------------------------------------------- */
.globl _haltproc
.type _haltproc,#function
_haltproc:
/* reload exitcode */
ldr r0,=operatingsystem_result
ldr r0,[r0]
swi 0x900001
b _haltproc
.globl _haltproc_eabi
.type _haltproc_eabi,#function
_haltproc_eabi:
/* reload exitcode */
ldr r0,=operatingsystem_result
ldr r0,[r0]
mov r7,#248
swi 0x0
b _haltproc_eabi
/* Go to libc exit() */
b exit
/* --------------------------------------------------------- */
.data
.type operatingsystem_parameters,#object
.size operatingsystem_parameters,12
operatingsystem_parameters:
.skip 3*4
.global operatingsystem_parameter_envp
.global operatingsystem_parameter_argc
.global operatingsystem_parameter_argv
.set operatingsystem_parameter_envp,operatingsystem_parameters+0
.set operatingsystem_parameter_argc,operatingsystem_parameters+4
.set operatingsystem_parameter_argv,operatingsystem_parameters+8
.bss
.comm __stkptr,4
.comm operatingsystem_parameter_envp,4
operatingsystem_parameter_argc:
.global operatingsystem_parameter_argc
.long 1
operatingsystem_parameter_argv:
.global operatingsystem_parameter_argv
.long EmptyCmdLine
EmptyCmdLine:
.long EmptyCmdStr
EmptyCmdStr:
.ascii "\0"
/* --------------------------------------------------------- */
.section .init_array, "aw"
.long FPC_SHARED_LIB_START

View File

@ -17,125 +17,87 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/* This is the canonical entry point, usually the first thing in the text
segment.
/* At this entry point, most registers' values are unspecified, except:
Note that the code in the .init section has already been run.
This includes _init and _libc_init
At this entry point, most registers' values are unspecified, except:
a1 Contains a function pointer to be registered with `atexit'.
This is how the dynamic linker arranges to have DT_FINI
functions called for shared libraries that have been loaded
before this code runs.
sp The stack contains the arguments and environment:
0(sp) argc
4(sp) argv[0]
...
(4*argc)(sp) NULL
(4*(argc+1))(sp) envp[0]
...
NULL
sp The stack contains the arguments and environment:
0(sp) argc
4(sp) argv[0]
...
(4*argc)(sp) NULL
(4*(argc+1))(sp) envp[0]
...
NULL
*/
.text
.globl _dynamic_start
.type _dynamic_start,#function
_dynamic_start:
ldr ip,=__dl_fini
str a1,[ip]
b _start
.text
.globl _start
.type _start,#function
_start:
/* Clear the frame pointer since this is the outermost frame. */
mov fp, #0
ldmia sp!, {a2}
/* Pop argc off the stack and save a pointer to argv */
ldr ip,=operatingsystem_parameter_argc
ldr a3,=operatingsystem_parameter_argv
str a2,[ip]
/* calc envp */
add a2,a2,#1
add a2,sp,a2,LSL #2
ldr ip,=operatingsystem_parameter_envp
str sp,[a3]
str a2,[ip]
/* In our entry point we should save pointers to cmd line arguments
and environment vars, then pass control to libc entry point.
After needed libc init, it will call FPC main code.
*/
.text
.globl _fpc_start
.type _fpc_start,#function
_fpc_start:
/* Clear the frame pointer since this is the outermost frame. */
mov fp, #0
/* Save initial stackpointer */
ldr ip,=__stkptr
str sp,[ip]
/* align sp again to 8 byte boundary, needed by eabi */
sub sp,sp,#4
ldr ip,=__stkptr
str sp,[ip]
mov r4,sp
/* Pop argc off the stack and save a pointer to argv */
ldmia r4!, {r5}
ldr ip,=operatingsystem_parameter_argc
str r5,[ip]
ldr ip,=operatingsystem_parameter_argv
str r4,[ip]
/* Let the libc call main and exit with its return code. */
bl PASCALMAIN
/* calc envp */
add r5,r5,#1
add r5,r4,r5,LSL #2
ldr ip,=operatingsystem_parameter_envp
str r5,[ip]
b PASCALMAIN
/* Call __libc_init */
/* ELF data block */
mov r0, sp
/* "onexit" function, not used on any platform supported by Bionic */
mov r1, #0
/* the "main" function of the program */
ldr r2, =PASCALMAIN
/* constructors and destructors list */
adr r3, 1f
b __libc_init
.globl _haltproc
.type _haltproc,#function
1: .long __PREINIT_ARRAY__
.long __INIT_ARRAY__
.long __FINI_ARRAY__
/* --------------------------------------------------------- */
.globl _haltproc
.type _haltproc,#function
_haltproc:
/* r0 contains exitcode */
swi 0x900001
b _haltproc
.globl _haltproc_eabi
.globl _haltproc_eabi
.type _haltproc_eabi,#function
_haltproc_eabi:
ldr r0,=__dl_fini
ldr r0,[r0]
cmp r0,#0
/* only branch if not equal zero */
movne lr,pc
bxne r0 /* we require armv5 anyway, so use bx here */
.Lloop:
ldr r0,=operatingsystem_result
ldr r0,[r0]
mov r7,#248 /* exit group call */
swi 0x0
b .Lloop
/* Go to libc exit() */
b exit
/* Define a symbol for the first piece of initialized data. */
.data
.globl __data_start
/* --------------------------------------------------------- */
.data
/* Define a symbol for the first piece of initialized data. */
.globl __data_start
__data_start:
.long 0
.weak data_start
data_start = __data_start
.long 0
.weak data_start
data_start = __data_start
/* --------------------------------------------------------- */
.bss
.comm __dl_fini,4
.comm __stkptr,4
.comm operatingsystem_parameter_envp,4
.comm operatingsystem_parameter_argc,4
.comm operatingsystem_parameter_argv,4
.section ".comment"
.byte 0
.ascii "generated by FPC http://www.freepascal.org\0"
/* We need this stuff to make gdb behave itself, otherwise
gdb will chokes with SIGILL when trying to debug apps.
*/
.section ".note.ABI-tag", "a"
.align 4
.long 1f - 0f
.long 3f - 2f
.long 1
0: .asciz "GNU"
1: .align 4
2: .long 0
.long 2,0,0
3: .align 4
.section .note.GNU-stack,"",%progbits