aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog5
-rw-r--r--gcc/config/arm/README-interworking527
-rw-r--r--gcc/config/arm/arm.c23
-rw-r--r--gcc/config/arm/arm.md3
-rw-r--r--gcc/config/arm/thumb.c12
5 files changed, 388 insertions, 182 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 2cb1e09..f2868a6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -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.
diff --git a/gcc/config/arm/README-interworking b/gcc/config/arm/README-interworking
index a0069a9..46b76c9 100644
--- a/gcc/config/arm/README-interworking
+++ b/gcc/config/arm/README-interworking
@@ -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 arm (void) { return 1 + thumb (); }
+
+ int thumb (void) { return 2 + arm (); }
+
+ The following pieces of assembler are produced by the ARM and Thumb
+version of GCC depending upon the command line options used:
+
+ `-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}
+
+ 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.
+
+ `-O2 -mthumb-interwork':
+
+ .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
+
+ 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.
+
+ `-O2 -mcallee-super-interworking':
+
+ .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
+
+ 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
+=================================
- int func (void) { return 1; }
+ 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 previous version.
+
+ `-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}
+
+ 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.
+
+ `-O2 -mcallee-super-interworking':
+
+ .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
+
+ 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%.
- int call (int (* ptr)(void)) { return ptr (); }
+ If a prototype for call() is added to the source code, and this
+prototype includes the `interfacearm' attribute:
+
+ int __attribute__((interfacearm)) call (int (* ptr)(void));
+
+ then this code is produced (with only -O2 specified on the command
+line):
+
+ .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
+
+ 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.
+
+
+10. How to use dlltool to build ARM/Thumb DLLs
+==============================================
+ Given a program (`prog.c') like this:
-The following varying pieces of assembler are produced depending upon
-the command line options used:
+ extern int func_in_dll (void);
+
+ int main (void) { return func_in_dll(); }
-no options:
+ And a DLL source file (`dll.c') like this:
- @ 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
+ int func_in_dll (void) { return 1; }
- .globl _call
- .thumb_func
- _call:
- push {lr}
- bl __call_via_r0
- pop {pc}
+ Here is how to build the DLL and the program for a purely ARM based
+environment:
-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.
+*Step One
+ Build a `.def' file describing the DLL:
-If -mthumb-interwork is specified on the command line:
+ ; example.def
+ ; This file describes the contents of the DLL
+ LIBRARY example
+ HEAPSIZE 0x40000, 0x2000
+ EXPORTS
+ func_in_dll 1
- @ 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
+*Step Two
+ Compile the DLL source code:
- .globl _call
- .thumb_func
- _call:
- push {lr}
- bl __call_via_r0
- pop {r1}
- bx r1
+ arm-pe-gcc -O2 -c dll.c
-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.
+*Step Three
+ Use `dlltool' to create an exports file and a library file:
-If -mcaller-super-interworking is specified:
+ dlltool --def example.def --output-exp example.o --output-lib example.a
- @ 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
+*Step Four
+ Link together the complete DLL:
- .globl _call
- .thumb_func
- _call:
- push {lr}
- bl __interwork_call_via_r0
- pop {pc}
-
-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.
-
-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
+ arm-pe-ld dll.o example.o -o example.dll
- .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
+*Step Five
+ Compile the program's source code:
-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%.
+ arm-pe-gcc -O2 -c prog.c
-If the source code is slightly altered so that only the call function
-has an (interfacearm) attribute:
+*Step Six
+ Link together the program and the DLL's library file:
- 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)); }
+ arm-pe-gcc prog.o example.a -o prog
-then this code is produced (with no command line switches):
+ 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):
- @ 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
+*Step Two
+ Compile the DLL source code (using the Thumb compiler):
- .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
+ thumb-pe-gcc -O2 -c dll.c -mthumb-interwork
- .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"
-
-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():
-
- Disassembly of section .text:
-
- 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}
+*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.
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index a4719c6..feaf7ba 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -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 );
}
}
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 20b8d57..ffbff79 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -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")
diff --git a/gcc/config/arm/thumb.c b/gcc/config/arm/thumb.c
index c7cc7a2..bd302a5 100644
--- a/gcc/config/arm/thumb.c
+++ b/gcc/config/arm/thumb.c
@@ -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;
+ }
}