thumb.c - add warning about PIC code not being supported just yet.

arm.c - synchronised with devo
arm.md - synchronised with devo
README-interworking - sychronised with devo.

From-SVN: r23013
This commit is contained in:
Nick Clifton 1998-10-12 10:53:08 +00:00 committed by Nick Clifton
parent 5d4a5ee6d9
commit 25b1c156df
5 changed files with 379 additions and 173 deletions

View File

@ -1,3 +1,8 @@
Mon Oct 12 10:50:44 1998 Nick Clifton <nickc@cygnus.com>
* config/arm/thumb.c (thumb_override_options): Add warning about
PIC code not being supported just yet.
Sun Oct 11 16:49:15 EDT 1998 John Wehle (john@feith.com)
* flow.c: Update comment.

View File

@ -145,14 +145,14 @@ declspec for individual functions, indicating that that particular
function should support being called by non-interworking aware code.
The function should be defined like this:
int function __attribute__((interfacearm))
int __attribute__((interfacearm)) function
{
... body of function ...
}
or
int function __declspec(interfacearm)
int __declspec(interfacearm) function
{
... body of function ...
}
@ -162,8 +162,63 @@ or
4. Interworking support in dlltool
==================================
Currently there is no interworking support in dlltool. This may be a
future enhancement.
It is possible to create DLLs containing mixed ARM and Thumb code. It
is also possible to call Thumb code in a DLL from an ARM program and
vice versa. It is even possible to call ARM DLLs that have been compiled
without interworking support (say by an older version of the compiler),
from Thumb programs and still have things work properly.
A version of the `dlltool' program which supports the `--interwork'
command line switch is needed, as well as the following special
considerations when building programs and DLLs:
*Use `-mthumb-interwork'*
When compiling files for a DLL or a program the `-mthumb-interwork'
command line switch should be specified if calling between ARM and
Thumb code can happen. If a program is being compiled and the
mode of the DLLs that it uses is not known, then it should be
assumed that interworking might occur and the switch used.
*Use `-m thumb'*
If the exported functions from a DLL are all Thumb encoded then the
`-m thumb' command line switch should be given to dlltool when
building the stubs. This will make dlltool create Thumb encoded
stubs, rather than its default of ARM encoded stubs.
If the DLL consists of both exported Thumb functions and exported
ARM functions then the `-m thumb' switch should not be used.
Instead the Thumb functions in the DLL should be compiled with the
`-mcallee-super-interworking' switch, or with the `interfacearm'
attribute specified on their prototypes. In this way they will be
given ARM encoded prologues, which will work with the ARM encoded
stubs produced by dlltool.
*Use `-mcaller-super-interworking'*
If it is possible for Thumb functions in a DLL to call
non-interworking aware code via a function pointer, then the Thumb
code must be compiled with the `-mcaller-super-interworking'
command line switch. This will force the function pointer calls
to use the _interwork_call_via_rX stub functions which will
correctly restore Thumb mode upon return from the called function.
*Link with `libgcc.a'*
When the dll is built it may have to be linked with the GCC
library (`libgcc.a') in order to extract the _call_via_rX functions
or the _interwork_call_via_rX functions. This represents a partial
redundancy since the same functions *may* be present in the
application itself, but since they only take up 372 bytes this
should not be too much of a consideration.
*Use `--support-old-code'*
When linking a program with an old DLL which does not support
interworking, the `--support-old-code' command line switch to the
linker should be used. This causes the linker to generate special
interworking stubs which can cope with old, non-interworking aware
ARM code, at the cost of generating bulkier code. The linker will
still generate a warning message along the lines of:
"Warning: input file XXX does not support interworking, whereas YYY does."
but this can now be ignored because the --support-old-code switch
has been used.
@ -363,191 +418,325 @@ be restored upon exit from the function.
8. Some examples
================
Given this test file:
Given these two test files:
int func (void) { return 1; }
int arm (void) { return 1 + thumb (); }
int call (int (* ptr)(void)) { return ptr (); }
int thumb (void) { return 2 + arm (); }
The following varying pieces of assembler are produced depending upon
the command line options used:
The following pieces of assembler are produced by the ARM and Thumb
version of GCC depending upon the command line options used:
no options:
`-O2':
.code 32 .code 16
.global _arm .global _thumb
.thumb_func
_arm: _thumb:
mov ip, sp
stmfd sp!, {fp, ip, lr, pc} push {lr}
sub fp, ip, #4
bl _thumb bl _arm
add r0, r0, #1 add r0, r0, #2
ldmea fp, {fp, sp, pc} pop {pc}
@ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe
.code 16
.text
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
Note how the functions return without using the BX instruction. If
these files were assembled and linked together they would fail to work
because they do not change mode when returning to their caller.
.globl _call
.thumb_func
_call:
push {lr}
bl __call_via_r0
pop {pc}
`-O2 -mthumb-interwork':
Note how the two functions have different exit sequences. In
particular call() uses pop {pc} to return. This would not work if the
caller was in ARM mode.
.code 32 .code 16
.global _arm .global _thumb
.thumb_func
_arm: _thumb:
mov ip, sp
stmfd sp!, {fp, ip, lr, pc} push {lr}
sub fp, ip, #4
bl _thumb bl _arm
add r0, r0, #1 add r0, r0, #2
ldmea fp, {fp, sp, lr} pop {r1}
bx lr bx r1
If -mthumb-interwork is specified on the command line:
Now the functions use BX to return their caller. They have grown by
4 and 2 bytes respectively, but they can now successfully be linked
together and be expect to work. The linker will replace the
destinations of the two BL instructions with the addresses of calling
stubs which convert to the correct mode before jumping to the called
function.
@ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe
.code 16
.text
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
`-O2 -mcallee-super-interworking':
.globl _call
.thumb_func
_call:
push {lr}
bl __call_via_r0
pop {r1}
bx r1
.code 32 .code 32
.global _arm .global _thumb
_arm: _thumb:
orr r12, pc, #1
bx r12
mov ip, sp .code 16
stmfd sp!, {fp, ip, lr, pc} push {lr}
sub fp, ip, #4
bl _thumb bl _arm
add r0, r0, #1 add r0, r0, #2
ldmea fp, {fp, sp, lr} pop {r1}
bx lr bx r1
This time both functions return by using the BX instruction. This
The thumb function now has an ARM encoded prologue, and it no longer
has the `.thumb-func' pseudo op attached to it. The linker will not
generate a calling stub for the call from arm() to thumb(), but it will
still have to generate a stub for the call from thumb() to arm(). Also
note how specifying `--mcallee-super-interworking' automatically
implies `-mthumb-interworking'.
9. Some Function Pointer Examples
=================================
Given this test file:
int func (void) { return 1; }
int call (int (* ptr)(void)) { return ptr (); }
The following varying pieces of assembler are produced by the Thumb
version of GCC depending upon the command line options used:
`-O2':
.code 16
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
.globl _call
.thumb_func
_call:
push {lr}
bl __call_via_r0
pop {pc}
Note how the two functions have different exit sequences. In
particular call() uses pop {pc} to return, which would not work if the
caller was in ARM mode. func() however, uses the BX instruction, even
though `-mthumb-interwork' has not been specified, as this is the most
efficient way to exit a function when the return address is held in the
link register.
`-O2 -mthumb-interwork':
.code 16
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
.globl _call
.thumb_func
_call:
push {lr}
bl __call_via_r0
pop {r1}
bx r1
This time both functions return by using the BX instruction. This
means that call() is now two bytes longer and several cycles slower
than the version that is not interworking enabled.
than the previous version.
If -mcaller-super-interworking is specified:
`-O2 -mcaller-super-interworking':
.code 16
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
.globl _call
.thumb_func
_call:
push {lr}
bl __interwork_call_via_r0
pop {pc}
@ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe
.code 16
.text
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
Very similar to the first (non-interworking) version, except that a
different stub is used to call via the function pointer. This new stub
will work even if the called function is not interworking aware, and
tries to return to call() in ARM mode. Note that the assembly code for
call() is still not interworking aware itself, and so should not be
called from ARM code.
.globl _call
.thumb_func
_call:
push {lr}
bl __interwork_call_via_r0
pop {pc}
`-O2 -mcallee-super-interworking':
Very similar to the first (non-interworking) version, except that a
different stub is used to call via the function pointer. Note that
the assembly code for call() is not interworking aware, and so should
not be called from ARM code.
.code 32
.globl _func
_func:
orr r12, pc, #1
bx r12
.code 16
.globl .real_start_of_func
.thumb_func
.real_start_of_func:
mov r0, #1
bx lr
.code 32
.globl _call
_call:
orr r12, pc, #1
bx r12
.code 16
.globl .real_start_of_call
.thumb_func
.real_start_of_call:
push {lr}
bl __call_via_r0
pop {r1}
bx r1
If -mcallee-super-interworking is specified:
@ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe
.code 16
.text
.globl _func
.code 32
_func:
orr r12, pc, #1
bx r12
.code 16
.globl .real_start_of_func
.thumb_func
.real_start_of_func:
mov r0, #1
bx lr
.globl _call
.code 32
_call:
orr r12, pc, #1
bx r12
.code 16
.globl .real_start_of_call
.thumb_func
.real_start_of_call:
push {lr}
bl __call_via_r0
pop {r1}
bx r1
Now both functions have an ARM coded prologue, and both functions
Now both functions have an ARM coded prologue, and both functions
return by using the BX instruction. These functions are interworking
aware therefore and can safely be called from ARM code. The code for
the call() function is now 10 bytes longer than the original, non
interworking aware version, an increase of over 200%.
If the source code is slightly altered so that only the call function
has an (interfacearm) attribute:
If a prototype for call() is added to the source code, and this
prototype includes the `interfacearm' attribute:
int func (void) { return 1; }
int call () __attribute__((interfacearm));
int call (int (* ptr)(void)) { return ptr (); }
int main (void) { return printf ("result: %d\n", call (func)); }
int __attribute__((interfacearm)) call (int (* ptr)(void));
then this code is produced (with no command line switches):
then this code is produced (with only -O2 specified on the command
line):
@ Generated by gcc cygnus-2.91.07 980205 (gcc-2.8.0 release) for ARM/pe
.code 16
.text
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
.code 16
.globl _func
.thumb_func
_func:
mov r0, #1
bx lr
.globl _call
.code 32
_call:
orr r12, pc, #1
bx r12
.code 16
.globl .real_start_of_call
.thumb_func
.real_start_of_call:
push {lr}
bl __call_via_r0
pop {r1}
bx r1
.globl _call
.code 32
_call:
orr r12, pc, #1
bx r12
.code 16
.globl .real_start_of_call
.thumb_func
.real_start_of_call:
push {lr}
bl __call_via_r0
pop {r1}
bx r1
So now both call() and func() can be safely called via
non-interworking aware ARM code. If, when such a file is assembled,
the assembler detects the fact that call() is being called by another
function in the same file, it will automatically adjust the target of
the BL instruction to point to .real_start_of_call. In this way there
is no need for the linker to generate a Thumb-to-ARM calling stub so
that call can be entered in ARM mode.
.globl _main
.thumb_func
_main:
push {r4, lr}
bl ___gccmain
ldr r4, .L4
ldr r0, .L4+4
bl _call
add r1, r0, #0
add r0, r4, #0
bl _printf
pop {r4, pc}
.L4:
.word .LC0
.word _func
.section .rdata
.LC0:
.ascii "result: %d\n\000"
10. How to use dlltool to build ARM/Thumb DLLs
==============================================
Given a program (`prog.c') like this:
So now only call() can be called via non-interworking aware ARM code.
When this program is assembled, the assembler detects the fact that
main() is calling call() in Thumb mode, and so automatically adjusts
the BL instruction to point to the real start of call():
extern int func_in_dll (void);
int main (void) { return func_in_dll(); }
Disassembly of section .text:
And a DLL source file (`dll.c') like this:
00000028 <_main>:
28: b530 b530 push {r4, r5, lr}
2a: fffef7ff f7ff bl 2a <_main+0x2>
2e: 4d06 4d06 ldr r5, [pc, #24] (48 <.L7>)
30: ffe8f7ff f7ff bl 4 <_doit>
34: 1c04 1c04 add r4, r0, #0
36: 4805 4805 ldr r0, [pc, #20] (4c <.L7+0x4>)
38: fff0f7ff f7ff bl 1c <.real_start_of_call>
3c: 1824 1824 add r4, r4, r0
3e: 1c28 1c28 add r0, r5, #0
40: 1c21 1c21 add r1, r4, #0
42: fffef7ff f7ff bl 42 <_main+0x1a>
46: bd30 bd30 pop {r4, r5, pc}
int func_in_dll (void) { return 1; }
Here is how to build the DLL and the program for a purely ARM based
environment:
*Step One
Build a `.def' file describing the DLL:
; example.def
; This file describes the contents of the DLL
LIBRARY example
HEAPSIZE 0x40000, 0x2000
EXPORTS
func_in_dll 1
*Step Two
Compile the DLL source code:
arm-pe-gcc -O2 -c dll.c
*Step Three
Use `dlltool' to create an exports file and a library file:
dlltool --def example.def --output-exp example.o --output-lib example.a
*Step Four
Link together the complete DLL:
arm-pe-ld dll.o example.o -o example.dll
*Step Five
Compile the program's source code:
arm-pe-gcc -O2 -c prog.c
*Step Six
Link together the program and the DLL's library file:
arm-pe-gcc prog.o example.a -o prog
If instead this was a Thumb DLL being called from an ARM program, the
steps would look like this. (To save space only those steps that are
different from the previous version are shown):
*Step Two
Compile the DLL source code (using the Thumb compiler):
thumb-pe-gcc -O2 -c dll.c -mthumb-interwork
*Step Three
Build the exports and library files (and support interworking):
dlltool -d example.def -z example.o -l example.a --interwork -m thumb
*Step Five
Compile the program's source code (and support interworking):
arm-pe-gcc -O2 -c prog.c -mthumb-interwork
If instead, the DLL was an old, ARM DLL which does not support
interworking, and which cannot be rebuilt, then these steps would be
used.
*Step One
Skip. If you do not have access to the sources of a DLL, there is
no point in building a `.def' file for it.
*Step Two
Skip. With no DLL sources there is nothing to compile.
*Step Three
Skip. Without a `.def' file you cannot use dlltool to build an
exports file or a library file.
*Step Four
Skip. Without a set of DLL object files you cannot build the DLL.
Besides it has already been built for you by somebody else.
*Step Five
Compile the program's source code, this is the same as before:
arm-pe-gcc -O2 -c prog.c
*Step Six
Link together the program and the DLL's library file, passing the
`--support-old-code' option to the linker:
arm-pe-gcc prog.o example.a -Wl,--support-old-code -o prog
Ignore the warning message about the input file not supporting
interworking as the --support-old-code switch has taken care if this.

View File

@ -222,11 +222,14 @@ arm_override_options ()
int arm_thumb_aware = 0;
int flags = 0;
unsigned i;
struct arm_cpu_select *ptr;
static struct cpu_default {
int cpu;
char *name;
} cpu_defaults[] = {
struct arm_cpu_select * ptr;
static struct cpu_default
{
int cpu;
char * name;
}
cpu_defaults[] =
{
{ TARGET_CPU_arm2, "arm2" },
{ TARGET_CPU_arm6, "arm6" },
{ TARGET_CPU_arm610, "arm610" },
@ -3642,7 +3645,7 @@ find_barrier (from, max_count)
/* Walk back to be just before any jump. */
while (GET_CODE (from) == JUMP_INSN
|| GET_CODE (from) == NOTE
|| GET_CODE (from) == NOTE
|| GET_CODE (from) == CODE_LABEL)
from = PREV_INSN (from);
@ -4857,7 +4860,7 @@ output_return_instruction (operand, really_return, reverse)
else if (really_return)
{
if (TARGET_THUMB_INTERWORK)
sprintf (instr, "bx%%?%%%s\t%%|lr", reverse ? "D" : "d");
sprintf (instr, "bx%%?%%%s0\t%%|lr", reverse ? "D" : "d");
else
sprintf (instr, "mov%%?%%%s0%s\t%%|pc, %%|lr",
reverse ? "D" : "d", TARGET_APCS_32 ? "" : "s");
@ -5156,10 +5159,10 @@ output_func_epilogue (f, frame_size)
/* And finally, go home */
if (TARGET_THUMB_INTERWORK)
fprintf (f, "\tbx\t%slr\n", REGISTER_PREFIX);
else if (TARGET_APCS_32)
fprintf (f, "\tmov\t%spc, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX );
else
fprintf (f, (TARGET_APCS_32 ? "\tmov\t%spc, %slr\n"
: "\tmovs\t%spc, %slr\n"),
REGISTER_PREFIX, REGISTER_PREFIX, f);
fprintf (f, "\tmovs\t%spc, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX );
}
}

View File

@ -5888,7 +5888,8 @@
"sub%?s\\t%0, %1, #0"
[(set_attr "conds" "set")])
; Peepholes to spot possible load- and store-multiples.
; Peepholes to spot possible load- and store-multiples, if the ordering is
; reversed, check that the memory references aren't volatile.
(define_peephole
[(set (match_operand:SI 0 "s_register_operand" "=r")

View File

@ -1465,7 +1465,8 @@ thumb_unexpanded_epilogue ()
if ((live_regs_mask & (1 << PROGRAM_COUNTER)) == 0)
thumb_exit (asm_out_file,
(had_to_push_lr
&& is_called_in_ARM_mode (current_function_decl)) ? -1 : LINK_REGISTER);
&& is_called_in_ARM_mode (current_function_decl)) ?
-1 : LINK_REGISTER);
}
else
{
@ -1971,7 +1972,8 @@ thumb_return_in_memory (type)
return 1;
}
void thumb_override_options()
void
thumb_override_options ()
{
if (structure_size_string != NULL)
{
@ -1982,4 +1984,10 @@ void thumb_override_options()
else
warning ("Structure size boundary can only be set to 8 or 32");
}
if (flag_pic)
{
warning ("Position independent code not supported. Ignored");
flag_pic = 0;
}
}