Merged revision(s) 31682, 31703-31704, 31719, 31761-31762, 32008, 32021-32024, 32033, 32035 from trunk (Android PIC support):

* arm-android: PIC compatible library startup code.
........
* ARM assembler routines are PIC compatible now.
........
* arm-android: Enable PIC by default.
........
* arm-android: Do not use register r4, since it must be preserved. Use r3 instead.
........
* i386-android: Library startup code is PIC compatible.
........
* Added a comment.
........
* android: Simply jump to the libc exit().
........
* Enable PIC by default for i386-android.
........
* arm-android: Simplified _haltproc for dll.
........
* android: Generate PIC executables. It is required for Android 5.0+.
........
* arm-android: Use PIC in the program start-up code.
........
* android: Fixed crash when using writeln during shared library finalization on Android 4.4+.
........
* i386-android: Use PIC in the program start-up code.
........

git-svn-id: branches/fixes_3_0@33440 -
This commit is contained in:
yury 2016-04-07 14:03:44 +00:00
parent 4d62e12dfe
commit fccd5e534d
13 changed files with 321 additions and 106 deletions

1
.gitattributes vendored
View File

@ -7972,6 +7972,7 @@ rtl/android/jvm/java_sysh_android.inc svneol=native#text/plain
rtl/android/jvm/rtl.cfg svneol=native#text/plain
rtl/android/mipsel/dllprt0.as svneol=native#text/plain
rtl/android/mipsel/prt0.as svneol=native#text/plain
rtl/android/sysandroid.inc svneol=native#text/plain
rtl/arm/arm.inc svneol=native#text/plain
rtl/arm/armdefines.inc svneol=native#text/plain
rtl/arm/divide.inc svneol=native#text/plain

View File

@ -36,7 +36,8 @@ unit i_android;
shortname : 'Android';
flags : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,
tf_requires_proper_alignment, tf_safecall_exceptions,
tf_smartlink_sections,tf_smartlink_library,tf_has_winlike_resources];
tf_pic_uses_got, tf_pic_default,
tf_smartlink_sections,tf_has_winlike_resources];
cpu : cpu_arm;
unit_env : 'ANDROIDUNITS';
extradefines : 'UNIX;HASUNIX;CPUARMEL';
@ -98,10 +99,10 @@ 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_needs_symbol_type,tf_files_case_sensitive,
tf_smartlink_library,tf_needs_dwarf_cfi,tf_has_winlike_resources,
tf_safecall_exceptions, tf_safecall_clearstack];
flags : [tf_needs_symbol_size,tf_needs_symbol_type,tf_files_case_sensitive,
tf_needs_dwarf_cfi,tf_has_winlike_resources,
tf_pic_uses_got, tf_pic_default, tf_smartlink_sections,
tf_safecall_exceptions];
cpu : cpu_i386;
unit_env : 'ANDROIDUNITS';
extradefines : 'UNIX;HASUNIX';

View File

@ -328,6 +328,8 @@ begin
Message1(exec_i_linking, outname);
opts:='';
if not IsSharedLib and (cs_create_pic in current_settings.moduleswitches) then
opts:=opts + ' --pic-executable';
if (cs_link_strip in current_settings.globalswitches) and
not (cs_link_separate_dbg_file in current_settings.globalswitches) then
opts:=opts + ' -s';

View File

@ -3398,6 +3398,7 @@ endif
.NOTPARALLEL:
include $(INC)/makefile.inc
SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
SYSINCDEPS:=$(SYSINCDEPS) sysandroid.inc
include $(PROCINC)/makefile.cpu
SYSCPUDEPS=$(addprefix $(PROCINC)/,$(CPUINCNAMES))
SYSDEPS=$(SYSINCDEPS) $(SYSCPUDEPS)

View File

@ -83,6 +83,7 @@ OBJPASDIR=$(RTL)/objpas
# SYSINCNAMES
include $(INC)/makefile.inc
SYSINCDEPS=$(addprefix $(INC)/,$(SYSINCNAMES))
SYSINCDEPS:=$(SYSINCDEPS) sysandroid.inc
# Get the processor dependent include file names.
# This will set the following variables :

View File

@ -24,27 +24,46 @@ FPC_SHARED_LIB_START:
stmfd sp!,{fp, ip, lr, pc}
sub fp, ip, #4
/* Get GOT */
ldr r3,.L_GOT1
.LPIC1:
add r3,pc,r3
/* Save initial stackpointer */
ldr ip,=__stkptr
ldr ip,.L__stkptr
ldr ip,[r3, ip]
str sp,[ip]
/* Get environment info from libc */
ldr ip,=environ
ldr ip,.Lenviron
ldr ip,[r3, ip]
ldr r0,[ip]
/* Check if environment is NULL */
cmp r0,#0
ldreq r0,=EmptyEnv
ldr ip,=operatingsystem_parameter_envp
ldreq r0,.LEmptyEnv
ldreq r0,[r3, r0]
ldr ip,.Loperatingsystem_parameter_envp
ldr ip,[r3, ip]
str r0,[ip]
/* Register exit handler. It is called only when the main process terminates */
ldr r0,=FPC_LIB_EXIT
blx atexit
/* call main and exit normally */
/* Call main */
blx PASCALMAIN
/* Call library init */
blx FPC_LIB_INIT_ANDROID
ldmea fp, {fp, sp, pc}
.L_GOT1:
.long _GLOBAL_OFFSET_TABLE_-.LPIC1-8
.L__stkptr:
.word __stkptr(GOT)
.Lenviron:
.word environ(GOT)
.LEmptyEnv:
.word EmptyEnv(GOT)
.Loperatingsystem_parameter_envp:
.word operatingsystem_parameter_envp(GOT)
/* --------------------------------------------------------- */
.globl _haltproc
.type _haltproc,#function
@ -52,11 +71,8 @@ _haltproc:
.globl _haltproc_eabi
.type _haltproc_eabi,#function
_haltproc_eabi:
ldr r0,=operatingsystem_result
ldr r0,[r0]
/* Go to libc exit() */
ldr ip,=exit
bx ip
/* Simply call libc exit(). _haltproc has the same declaration as exit. */
blx exit
/* --------------------------------------------------------- */
.data

View File

@ -37,29 +37,52 @@
.globl _fpc_start
.type _fpc_start,#function
_fpc_start:
/* Get GOT */
ldr r3,.L_GOT1
.LPIC1:
add r3,pc,r3
/* Clear the frame pointer since this is the outermost frame. */
mov fp, #0
/* Save initial stackpointer */
ldr ip,=__stkptr
ldr ip,.L__stkptr
ldr ip,[r3, ip]
str sp,[ip]
mov r4,sp
mov r0,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]
ldmia r0!, {r1}
ldr ip,.Loperatingsystem_parameter_argc
ldr ip,[r3, ip]
str r1,[ip]
ldr ip,.Loperatingsystem_parameter_argv
ldr ip,[r3, ip]
str r0,[ip]
/* calc envp */
add r5,r5,#1
add r5,r4,r5,LSL #2
ldr ip,=operatingsystem_parameter_envp
str r5,[ip]
add r1,r1,#1
add r1,r0,r1,LSL #2
ldr ip,.Loperatingsystem_parameter_envp
ldr ip,[r3, ip]
str r1,[ip]
/* Finally go to libc startup code. It will call "PASCALMAIN" via alias "main" */
ldr ip,=_start
ldr ip,.L_start
ldr ip,[r3, ip]
bx ip
.L_GOT1:
.long _GLOBAL_OFFSET_TABLE_-.LPIC1-8
.L__stkptr:
.word __stkptr(GOT)
.L_start:
.word _start(GOT)
.Loperatingsystem_parameter_argc:
.word operatingsystem_parameter_argc(GOT)
.Loperatingsystem_parameter_argv:
.word operatingsystem_parameter_argv(GOT)
.Loperatingsystem_parameter_envp:
.word operatingsystem_parameter_envp(GOT)
/* --------------------------------------------------------- */
.globl _haltproc
.type _haltproc,#function
@ -67,11 +90,8 @@ _haltproc:
.globl _haltproc_eabi
.type _haltproc_eabi,#function
_haltproc_eabi:
ldr r0,=operatingsystem_result
ldr r0,[r0]
/* Go to libc exit() */
ldr ip,=exit
bx ip
/* Simply call libc exit(). _haltproc has the same declaration as exit. */
blx exit
/* --------------------------------------------------------- */
.data

View File

@ -25,26 +25,36 @@ FPC_SHARED_LIB_START:
/* Align the stack to a 16 byte boundary */
andl $~15, %esp
/* Save ebx */
pushl %ebx
/* GOT init */
call fpc_geteipasebx
addl $_GLOBAL_OFFSET_TABLE_,%ebx
/* Save initial stackpointer */
movl %esp,__stkptr
movl __stkptr@GOT(%ebx),%eax
movl %esp,(%eax)
/* Get environment info from libc */
movl environ,%eax
movl environ@GOT(%ebx),%eax
movl (%eax),%eax
/* Check if environment is NULL */
test %eax,%eax
jne env_ok
leal EmptyEnv,%eax
movl EmptyEnv@GOT(%ebx),%eax
env_ok:
movl %eax,operatingsystem_parameter_envp
movl operatingsystem_parameter_envp@GOT(%ebx),%edx
movl %eax,(%edx)
/* Register exit handler. It is called only when the main process terminates */
leal FPC_LIB_EXIT,%eax
pushl %eax
call atexit
addl $4,%esp
/* Restore ebx */
popl %ebx
/* Call main */
call PASCALMAIN@PLT
/* Call library init */
call FPC_LIB_INIT_ANDROID@PLT
/* call main and exit normally */
call PASCALMAIN
leave
ret
@ -52,10 +62,11 @@ env_ok:
.globl _haltproc
.type _haltproc,@function
_haltproc:
movzwl operatingsystem_result,%ebx
pushl %ebx
/* Call libc exit() */
call exit
/* GOT init */
call fpc_geteipasebx
addl $_GLOBAL_OFFSET_TABLE_,%ebx
/* Jump to libc exit(). _haltproc has the same declaration as exit. */
jmp exit@PLT
/* --------------------------------------------------------- */
.data

View File

@ -42,36 +42,45 @@
.globl _fpc_start
.type _fpc_start,@function
_fpc_start:
/* GOT init */
call fpc_geteipasebx
addl $_GLOBAL_OFFSET_TABLE_,%ebx
/* Clear the frame pointer since this is the outermost frame. */
xorl %ebp,%ebp
/* Save initial stackpointer */
movl %esp,__stkptr
movl __stkptr@GOT(%ebx),%eax
movl %esp,(%eax)
/* First locate the start of the environment variables */
/* Get argc in ecx */
movl (%esp),%ecx
/* Save argc */
movl %ecx,operatingsystem_parameter_argc
/* Get argv pointer in ebx */
leal 4(%esp),%ebx
movl operatingsystem_parameter_argc@GOT(%ebx),%eax
movl %ecx,(%eax)
/* Get argv pointer in edx */
leal 4(%esp),%edx
/* Save argv */
movl %ebx,operatingsystem_parameter_argv
movl operatingsystem_parameter_argv@GOT(%ebx),%eax
movl %edx,(%eax)
/* The start of the environment is: esp+ecx*4+12 */
leal 12(%esp,%ecx,4),%eax
leal 12(%esp,%ecx,4),%edx
/* Save envp */
movl %eax,operatingsystem_parameter_envp
movl operatingsystem_parameter_envp@GOT(%ebx),%eax
movl %edx,(%eax)
/* Finally go to libc startup code. It will call "PASCALMAIN" via alias "main" */
/* Finally go to libc startup code. It will call "PASCALMAIN" via alias "main". */
/* No need to align stack since it will aligned by libc. */
jmp _start
/* --------------------------------------------------------- */
.globl _haltproc
.type _haltproc,@function
_haltproc:
movzwl operatingsystem_result,%ebx
pushl %ebx
/* Call libc exit() */
call exit
/* GOT init */
call fpc_geteipasebx
addl $_GLOBAL_OFFSET_TABLE_,%ebx
/* Jump to libc exit(). _haltproc has the same declaration as exit. */
jmp exit@PLT
/* --------------------------------------------------------- */
.data
/* Define a symbol for the first piece of initialized data. */

View File

@ -43,14 +43,12 @@ GotEnv:
la $t1, operatingsystem_parameter_envp
sw $t0, ($t1)
/* Register exit handler */
la $a0, FPC_LIB_EXIT
jal atexit
nop
/* Call main, exit */
/* Call main */
jal PASCALMAIN
nop
/* Call library init */
jal FPC_LIB_INIT_ANDROID
nop
/* restore registers, exit */
lw $ra, 24($sp)

View File

@ -0,0 +1,60 @@
{
This file is part of the Free Pascal run time library.
Copyright (c) 2015 by Yury Sidorov,
member of the Free Pascal development team.
Android-specific part of the System unit.
See the file COPYING.FPC, included in this distribution,
for details about the copyright.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
**********************************************************************}
procedure atexit(p: pointer); cdecl; external;
var
_SaveStdOut: THandle;
_SaveStdErr: THandle;
procedure SysAndroidLibExit; cdecl;
var
ioclosed: boolean;
begin
// Check if stdio is closed now
ioclosed:=do_syscall(syscall_nr_fcntl, TSysParam(1), 1 {F_GETFD}) = -1;
// If stdio is closed, restore stdout and stderr
if ioclosed then
begin
FpDup2(_SaveStdOut, 1);
FpDup2(_SaveStdErr, 2);
end;
// Close saved handles
FpClose(_SaveStdOut);
FpClose(_SaveStdErr);
// Finalize the library
lib_exit;
// Close stdout and stderr if stdio has been closed
if ioclosed then
begin
FpClose(1);
FpClose(2);
end;
end;
procedure SysInitAndroidLib; [public, alias:'FPC_LIB_INIT_ANDROID'];
begin
{ Starting from Android 4.4 stdio handles are closed by libc prior to calling
finalization routines of shared libraries. This causes a error while trying to
writeln during library finalization and finally a crash because the error can
not be printer too.
It is needed to save stdout and stderr handles by duplicating them and restore
them before library finalization.
}
_SaveStdOut:=FpDup(1);
_SaveStdErr:=FpDup(2);
// Register the finalization routine
atexit(@SysAndroidLibExit);
end;

View File

@ -321,15 +321,22 @@ asm
end;
const
moveproc : pointer = @move_blended;
moveproc : procedure(const source;var dest;count:longint) = @move_blended;
procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE'];assembler;nostackframe;
procedure Move(const source;var dest;count:longint);[public, alias: 'FPC_MOVE']; {$ifndef FPC_PIC} assembler;nostackframe; {$endif FPC_PIC}
{$ifdef FPC_PIC}
begin
moveproc(source,dest,count);
end;
{$else FPC_PIC}
asm
ldr ip,.Lmoveproc
ldr pc,[ip]
.Lmoveproc:
.long moveproc
end;
{$endif FPC_PIC}
{$endif CPUARM_HAS_EDSP}
{$endif FPC_SYSTEM_HAS_MOVE}
@ -541,10 +548,49 @@ asm
// Jump without a link, so freemem directly returns to our caller
b FPC_FREEMEM
end;
{$define FPC_SYSTEM_HAS_ANSISTR_INCR_REF}
Procedure fpc_ansistr_incr_ref (S : Pointer); [Public,Alias:'FPC_ANSISTR_INCR_REF'];assembler;nostackframe; compilerproc;
asm
// Null string?
cmp r0, #0
// Load reference counter
ldrne r1, [r0, #-8]
// pointer to counter, calculate here for delay slot utilization
subne r0, r0, #8
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
// Check for a constant string
cmp r1, #0
// Tailcall
// Hopefully the linker will place InterLockedIncrement as layed out here
bge InterLockedIncrement
// Freepascal will generate a proper return here, save some cachespace
end;
{$endif not darwin}
var
fpc_system_lock: longint; export name 'fpc_system_lock';
// --- InterLocked functions begin
{$if not defined(CPUARM_HAS_LDREX) and not defined(SYSTEM_HAS_KUSER_CMPXCHG) }
// Use generic interlock implementation
var
fpc_system_lock: longint;
{$ifdef FPC_PIC}
// Use generic interlock implementation with PIC
// A helper function to get a pointer to fpc_system_lock in the PIC compatible way.
function get_fpc_system_lock_ptr: pointer;
begin
get_fpc_system_lock_ptr:=@fpc_system_lock;
end;
{$endif FPC_PIC}
{$endif}
function InterLockedDecrement (var Target: longint) : longint; assembler; nostackframe;
asm
@ -594,7 +640,18 @@ asm
{$else}
// lock
ldr r3, .Lfpc_system_lock
{$ifdef FPC_PIC}
push {r0,lr}
{$ifdef CPUARM_HAS_BLX}
blx get_fpc_system_lock_ptr
{$else}
bl get_fpc_system_lock_ptr
{$endif CPUARM_HAS_BLX}
mov r3,r0
pop {r0,lr}
{$else FPC_PIC}
ldr r3, .Lfpc_system_lock
{$endif FPC_PIC}
mov r1, #1
.Lloop:
swp r2, r1, [r3]
@ -613,38 +670,15 @@ asm
mov pc,lr
{$endif}
{$ifndef FPC_PIC}
.Lfpc_system_lock:
.long fpc_system_lock
{$endif FPC_PIC}
{$endif}
{$endif}
end;
{$ifndef darwin}
{$define FPC_SYSTEM_HAS_ANSISTR_INCR_REF}
Procedure fpc_ansistr_incr_ref (S : Pointer); [Public,Alias:'FPC_ANSISTR_INCR_REF'];assembler;nostackframe; compilerproc;
asm
// Null string?
cmp r0, #0
// Load reference counter
ldrne r1, [r0, #-8]
// pointer to counter, calculate here for delay slot utilization
subne r0, r0, #8
{$ifdef CPUARM_HAS_BX}
bxeq lr
{$else}
moveq pc,lr
{$endif}
// Check for a constant string
cmp r1, #0
// Tailcall
// Hopefully the linker will place InterLockedIncrement as layed out here
bge InterLockedIncrement
// Freepascal will generate a proper return here, save some cachespace
end;
{$endif not darwin}
function InterLockedIncrement (var Target: longint) : longint; assembler; nostackframe;
asm
{$ifdef CPUARM_HAS_LDREX}
@ -691,7 +725,18 @@ asm
{$else}
// lock
ldr r3, .Lfpc_system_lock
{$ifdef FPC_PIC}
push {r0,lr}
{$ifdef CPUARM_HAS_BLX}
blx get_fpc_system_lock_ptr
{$else}
bl get_fpc_system_lock_ptr
{$endif CPUARM_HAS_BLX}
mov r3,r0
pop {r0,lr}
{$else FPC_PIC}
ldr r3, .Lfpc_system_lock
{$endif FPC_PIC}
mov r1, #1
.Lloop:
swp r2, r1, [r3]
@ -710,13 +755,15 @@ asm
mov pc,lr
{$endif}
{$ifndef FPC_PIC}
.Lfpc_system_lock:
.long fpc_system_lock
{$endif FPC_PIC}
{$endif}
{$endif}
end;
function InterLockedExchange (var Target: longint;Source : longint) : longint; assembler; nostackframe;
asm
{$ifdef CPUARM_HAS_LDREX}
@ -763,7 +810,18 @@ asm
b .Latomic_add_loop // kuser_cmpxchg failed, loop back
{$else}
// lock
ldr r3, .Lfpc_system_lock
{$ifdef FPC_PIC}
push {r0,r1,lr}
{$ifdef CPUARM_HAS_BLX}
blx get_fpc_system_lock_ptr
{$else}
bl get_fpc_system_lock_ptr
{$endif CPUARM_HAS_BLX}
mov r3,r0
pop {r0,r1,lr}
{$else FPC_PIC}
ldr r3, .Lfpc_system_lock
{$endif FPC_PIC}
mov r2, #1
.Lloop:
swp r2, r2, [r3]
@ -782,8 +840,11 @@ asm
mov pc,lr
{$endif}
{$ifndef FPC_PIC}
.Lfpc_system_lock:
.long fpc_system_lock
{$endif FPC_PIC}
{$endif}
{$endif}
end;
@ -839,7 +900,18 @@ asm
{$else}
// lock
ldr r3, .Lfpc_system_lock
{$ifdef FPC_PIC}
push {r0,r1,lr}
{$ifdef CPUARM_HAS_BLX}
blx get_fpc_system_lock_ptr
{$else}
bl get_fpc_system_lock_ptr
{$endif CPUARM_HAS_BLX}
mov r3,r0
pop {r0,r1,lr}
{$else FPC_PIC}
ldr r3, .Lfpc_system_lock
{$endif FPC_PIC}
mov r2, #1
.Lloop:
swp r2, r2, [r3]
@ -859,8 +931,11 @@ asm
mov pc,lr
{$endif}
{$ifndef FPC_PIC}
.Lfpc_system_lock:
.long fpc_system_lock
{$endif FPC_PIC}
{$endif}
{$endif}
end;
@ -918,7 +993,18 @@ asm
{$else}
// lock
ldr r12, .Lfpc_system_lock
{$ifdef FPC_PIC}
push {r0,r1,r2,lr}
{$ifdef CPUARM_HAS_BLX}
blx get_fpc_system_lock_ptr
{$else}
bl get_fpc_system_lock_ptr
{$endif CPUARM_HAS_BLX}
mov r12,r0
pop {r0,r1,r2,lr}
{$else FPC_PIC}
ldr r12, .Lfpc_system_lock
{$endif FPC_PIC}
mov r3, #1
.Lloop:
swp r3, r3, [r12]
@ -938,8 +1024,11 @@ asm
mov pc,lr
{$endif}
{$ifndef FPC_PIC}
.Lfpc_system_lock:
.long fpc_system_lock
{$endif FPC_PIC}
{$endif}
{$endif}
end;
@ -956,6 +1045,8 @@ begin
InterLockedIncrement(l);
end;
// --- InterLocked functions end
procedure fpc_cpucodeinit;
begin
{$ifdef FPC_SYSTEM_FPC_MOVE}

View File

@ -77,6 +77,10 @@ const calculated_cmdline:Pchar=nil;
{$I system.inc}
{$ifdef android}
{$I sysandroid.inc}
{$endif android}
{*****************************************************************************
Misc. System Dependent Functions
*****************************************************************************}