This is the mail archive of the
newlib@sourceware.org
mailing list for the newlib project.
RFA: Update RX assembler files to conditionally avoid string instructions
- From: Nick Clifton <nickc at redhat dot com>
- To: newlib at sourceware dot org
- Date: Wed, 08 Apr 2015 17:52:36 +0100
- Subject: RFA: Update RX assembler files to conditionally avoid string instructions
- Authentication-results: sourceware.org; auth=none
Hi Guys,
A problem has come to light with the RX string instructions (SMOVF,
SUNTIL, etc). They must not be used in the I/O address space as they
prefetch data from addresses that might be invalid. So the attached
patch adds alternative versions to all of the RX assembler source
files that use these instructions, predicated on a C preprocessor
macro called __RX_DISALLOW_STRING_INSNS__. (A future patch to GCC
will allow it to set this macro and create a multilib for it, but that
has to wait until the gcc sources are unfrozen).
Tested with no regressions on an rx-elf toolchain.
OK to apply ?
Cheers
Nick
newlib/ChangeLog
2015-04-08 Nick Clifton <nickc@redhat.com>
* libc/machine/rx/memchr.S: Add non-string insn using version.
* libc/machine/rx/memcpy.S: Likewise.
* libc/machine/rx/memmove.S: Likewise.
* libc/machine/rx/mempcpy.S: Likewise.
* libc/machine/rx/strcat.S: Likewise.
* libc/machine/rx/strcmp.S: Likewise.
* libc/machine/rx/strcpy.S: Likewise.
* libc/machine/rx/strlen.S: Likewise.
* libc/machine/rx/strncat.S: Likewise.
* libc/machine/rx/strncmp.S: Likewise.
* libc/machine/rx/strncpy.S: Likewise.
libgloss/ChangeLog
2015-04-08 Nick Clifton <nickc@redhat.com>
* rx/crt0.S (_start): If string instructions are not allowed,
avoid using SMOVF.
diff --git a/libgloss/rx/crt0.S b/libgloss/rx/crt0.S
index 2227423..6d7089d 100644
--- a/libgloss/rx/crt0.S
+++ b/libgloss/rx/crt0.S
@@ -40,11 +40,24 @@ _start:
mov #__stack, r0
mvtc #__vectors, intb
+ /* Copy the .data section from ROM into RAM. */
mov #__datastart, r1
mov #__romdatastart, r2
mov #__romdatacopysize, r3
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ cmp #0, r3
+ beq 2f
+
+1: mov.b [r2+], r5
+ mov.b r5, [r1+]
+ sub #1, r3
+ bne 1b
+2:
+#else
smovf
+#endif
+ /* Initialise the contents of the .bss section. */
mov #__bssstart, r1
mov #0, r2
mov #__bsssize, r3
diff --git a/newlib/libc/machine/rx/memchr.S b/newlib/libc/machine/rx/memchr.S
index 937753c..cdc97c8 100644
--- a/newlib/libc/machine/rx/memchr.S
+++ b/newlib/libc/machine/rx/memchr.S
@@ -5,9 +5,28 @@
.global _memchr
.type _memchr,@function
_memchr:
+ ;; R1: string pointer
+ ;; R2: byte sought
+ ;; R3: max number to scan
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ mov.b r2, r2 ; The mov.b below sign extends as it loads, so make sure that r2 is sign-extended as well.
+2: cmp #0, r3
+ beq 1f
+ sub #1, r3
+ mov.b [r1+], r5
+ cmp r5, r2
+ bne 2b
+
+ sub #1, r1 ; We have found a match, bit now R1 points to the byte after the match.
+1: rts
+#else
cmp #0, r3 ; If r3 is 0 suntil.b will do nothing and not set any flags...
stz #1, r1 ; ...so store 1 into r1. It will be decremented by the SUB later.
suntil.b ; Search until *r1 == r2 or r3 bytes have been examined.
stnz #1, r1 ; If no match was found return NULL.
sub #1, r1 ; suntil.b leaves r1 pointing at the address *after* the match.
rts
+#endif
+
+ .size _memchr, . - _memchr
+
diff --git a/newlib/libc/machine/rx/memcpy.S b/newlib/libc/machine/rx/memcpy.S
index 3e0d500..eb671c0 100644
--- a/newlib/libc/machine/rx/memcpy.S
+++ b/newlib/libc/machine/rx/memcpy.S
@@ -4,7 +4,28 @@
.global _memcpy
.type _memcpy,@function
_memcpy:
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ /* Do not use the string instructions - they might prefetch
+ bytes from outside of valid memory. This is particularly
+ dangerous in I/O space. */
+
+ ;; FIXME: It would be more space efficient to just branch to _memmove...
+
+ cmp #0, r3 ; If the count is zero, do nothing
+ beq 1f
+
+ mov r1, r14 ; Save a copy of DEST
+
+2: mov.b [r2+], r5
+ mov.b r5, [r14+]
+ sub #1, r3
+ bne 2b
+
+1: rts
+#else
mov r1, r4 ; Save a copy of DEST
smovf ; Copy R2 (source) to R1 (dest). Stop after R3 bytes.
mov r4, r1 ; Return DEST
rts
+#endif
+ .size _memcpy, . - _memcpy
diff --git a/newlib/libc/machine/rx/memmove.S b/newlib/libc/machine/rx/memmove.S
index 4b126ba..60b7683 100644
--- a/newlib/libc/machine/rx/memmove.S
+++ b/newlib/libc/machine/rx/memmove.S
@@ -4,6 +4,39 @@
.global _memmove
.type _memmove,@function
_memmove:
+ ;; R1: DEST
+ ;; R2: SRC
+ ;; R3: COUNT
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ /* Do not use the string instructions - they might prefetch
+ bytes from outside of valid memory. This is particularly
+ dangerous in I/O space. */
+
+ cmp #0, r3 ; If the count is zero, do nothing
+ beq 4f
+
+ cmp r1, r2
+ blt 3f ; If SRC < DEST copy backwards
+
+ mov r1, r14 ; Save a copy of DEST
+
+5: mov.b [r2+], r5
+ mov.b r5, [r14+]
+ sub #1, r3
+ bne 5b
+
+4: rts
+
+3: add r3, r1
+ add r3, r2
+
+6: mov.b [-r2], r5
+ mov.b r5, [-r1]
+ sub #1, r3
+ bne 6b
+
+ rts
+#else
mov r1, r4 ; Save a copy of DEST
cmp r1, r2
blt 2f ; If SRC (r2) is less than DEST (r1) then copy backwards
@@ -18,3 +51,7 @@ _memmove:
sub #1, r1 ; additions and subtractions.
smovb
bra 1b
+
+#endif /* SMOVF allowed. */
+
+ .size _memmove, . - _memmove
diff --git a/newlib/libc/machine/rx/mempcpy.S b/newlib/libc/machine/rx/mempcpy.S
index c679d04..f824524 100644
--- a/newlib/libc/machine/rx/mempcpy.S
+++ b/newlib/libc/machine/rx/mempcpy.S
@@ -4,5 +4,22 @@
.global _mempcpy
.type _mempcpy,@function
_mempcpy:
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ /* Do not use the string instructions - they might prefetch
+ bytes from outside of valid memory. This is particularly
+ dangerous in I/O space. */
+
+ cmp #0, r3 ; If the count is zero, do nothing
+ beq 2f
+
+1: mov.b [r2+], r5
+ mov.b r5, [r1+]
+ sub #1, r3
+ bne 1b
+
+2: rts
+#else
smovf
rts
+#endif
+ .size _mempcpy, . - _mempcpy
diff --git a/newlib/libc/machine/rx/memset.S b/newlib/libc/machine/rx/memset.S
index edab446..5ce7a3b 100644
--- a/newlib/libc/machine/rx/memset.S
+++ b/newlib/libc/machine/rx/memset.S
@@ -8,3 +8,6 @@ _memset:
sstr.b
mov r4, r1
rts
+
+ .size _memset, . - _memset
+
diff --git a/newlib/libc/machine/rx/strcat.S b/newlib/libc/machine/rx/strcat.S
index 7ceffb7..22533fc 100644
--- a/newlib/libc/machine/rx/strcat.S
+++ b/newlib/libc/machine/rx/strcat.S
@@ -6,6 +6,22 @@
_strcat:
;; On entry: r1 => Destination
;; r2 => Source
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ mov r1, r4 ; Save a copy of the dest pointer.
+
+1: mov.b [r4+], r5 ; Find the NUL byte at the end of R4.
+ cmp #0, r5
+ bne 1b
+
+ sub #1, r4 ; Move R4 back to point at the NUL byte.
+
+2: mov.b [r2+], r5 ; Copy bytes from R2 to R4 until we reach a NUL byte.
+ mov.b r5, [r4+]
+ cmp #0, r5
+ bne 2b
+
+ rts
+#else
mov r1, r4 ; Save a copy of the dest pointer.
mov r2, r5 ; Save a copy of the source pointer.
@@ -20,3 +36,6 @@ _strcat:
mov r4, r1 ; Return the original dest pointer.
rts
+#endif
+ .size _strcat, . - _strcat
+
diff --git a/newlib/libc/machine/rx/strcmp.S b/newlib/libc/machine/rx/strcmp.S
index 397415b..6a06e6c 100644
--- a/newlib/libc/machine/rx/strcmp.S
+++ b/newlib/libc/machine/rx/strcmp.S
@@ -5,6 +5,21 @@
.global _strcmp
.type _strcmp,@function
_strcmp:
+#ifdef __RX_DISALLOW_STRING_INSNS__
+2: mov.b [r1+], r4
+ mov.b [r2+], r5
+ cmp #0, r4
+ beq 3f
+ cmp #0, r5
+ beq 3f
+ cmp r4, r5
+ beq 2b
+
+3: and #0xff, r4 ; We need to perform an unsigned comparison of the bytes.
+ and #0xff, r5
+ sub r5, r4, r1
+ rts
+#else
mov #-1, r3 ; Strictly speaking this is incorrect, but I doubt if anyone will ever know.
scmpu ; Perform the string comparison
bnc 1f ; If Carry is not set skip over
@@ -13,3 +28,6 @@ _strcmp:
1: ;
mov #-1,r1 ; Carry not set, result should be negative
rts ;
+#endif
+ .size _strcmp, . - _strcmp
+
diff --git a/newlib/libc/machine/rx/strcpy.S b/newlib/libc/machine/rx/strcpy.S
index a2dc174..05766cc 100644
--- a/newlib/libc/machine/rx/strcpy.S
+++ b/newlib/libc/machine/rx/strcpy.S
@@ -4,8 +4,22 @@
.global _strcpy
.type _strcpy,@function
_strcpy:
+ ;; R1: dest
+ ;; R2: source
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ mov r1, r4 ; Leave the destination address unchanged in the result register.
+
+1: mov.b [r2+], r5
+ mov.b r5, [r4+]
+ cmp #0, r5
+ bne 1b
+
+ rts
+#else
mov r1, r4
mov #-1, r3 ; Strictly speaking this is incorrect, but I doubt if anyone will ever know.
smovu
mov r4, r1
rts
+#endif
+ .size _strcpy, . - _strcpy
diff --git a/newlib/libc/machine/rx/strlen.S b/newlib/libc/machine/rx/strlen.S
index c07b429..bf12c0c 100644
--- a/newlib/libc/machine/rx/strlen.S
+++ b/newlib/libc/machine/rx/strlen.S
@@ -5,6 +5,17 @@
.global _strlen
.type _strlen,@function
_strlen:
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ mov r1, r4
+
+1: mov.b [r1+], r5
+ cmp #0, r5
+ bne 1b
+
+ sub #1, r1
+ sub r4, r1
+ rts
+#else
add #0, r1, r4 ; Save a copy of the string start address and set the condition flags.
beq null_string ; Test for a NULL pointer.
mov #-1, r3 ; Set a limit on the number of bytes examined.
@@ -14,3 +25,5 @@ _strlen:
null_string:
sub r4, r1 ; Compute the length.
rts
+#endif
+ .size _strlen, . - _strlen
diff --git a/newlib/libc/machine/rx/strncat.S b/newlib/libc/machine/rx/strncat.S
index 3bc6b75..ba544a4 100644
--- a/newlib/libc/machine/rx/strncat.S
+++ b/newlib/libc/machine/rx/strncat.S
@@ -7,7 +7,27 @@ _strncat:
;; On entry: r1 => Destination
;; r2 => Source
;; r3 => Max number of bytes to copy
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ cmp #0, r3 ; If max is zero we have nothing to do.
+ beq 2f
+ mov r1, r4 ; Leave the desintation pointer intact for the return value.
+
+1: mov.b [r4+], r5 ; Find the NUL byte at the end of the destination.
+ cmp #0, r5
+ bne 1b
+
+ sub #1, r4
+
+3: mov.b [r2+], r5 ; Copy bytes from the source into the destination ...
+ mov.b r5, [r4+]
+ cmp #0, r5 ; ... until we reach a NUL byte ...
+ beq 2f
+ sub #1, r3
+ bne 3b ; ... or we have copied N bytes.
+
+2: rts
+#else
mov r1, r4 ; Save a copy of the dest pointer.
mov r2, r5 ; Save a copy of the source pointer.
mov r3, r14 ; Save a copy of the byte count.
@@ -33,3 +53,6 @@ _strncat:
1:
mov r4, r1 ; Return the original dest pointer.
rts
+#endif
+ .size _strncat, . - _strncat
+
diff --git a/newlib/libc/machine/rx/strncmp.S b/newlib/libc/machine/rx/strncmp.S
index 929e9cb..4be8076 100644
--- a/newlib/libc/machine/rx/strncmp.S
+++ b/newlib/libc/machine/rx/strncmp.S
@@ -4,6 +4,32 @@
.global _strncmp
.type _strncmp,@function
_strncmp:
+ ;; R1: string1
+ ;; R2: string2
+ ;; R3: max number of bytes to compare
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ cmp #0, r3 ; For a length of zero, return zero
+ beq 4f
+
+2: mov.b [r1+], r4
+ mov.b [r2+], r5
+ cmp #0, r4
+ beq 3f
+ cmp #0, r5
+ beq 3f
+ sub #1, r3
+ beq 3f
+ cmp r4, r5
+ beq 2b
+
+3: and #0xff, r4 ; We need to perform an unsigned comparison of the bytes.
+ and #0xff, r5
+ sub r5, r4, r1
+ rts
+
+4: mov #0, r1
+ rts
+#else
scmpu ; Perform the string comparison
bnc 1f ; If Carry is not set skip over
scne.L r1 ; Set result based on Z flag
@@ -11,3 +37,5 @@ _strncmp:
1: ;
mov #-1,r1 ; Carry not set, result should be negative
rts ;
+#endif
+ .size _strncmp, . - _strncmp
diff --git a/newlib/libc/machine/rx/strncpy.S b/newlib/libc/machine/rx/strncpy.S
index e04922a..e5b6a83 100644
--- a/newlib/libc/machine/rx/strncpy.S
+++ b/newlib/libc/machine/rx/strncpy.S
@@ -4,6 +4,26 @@
.global _strncpy
.type _strncpy,@function
_strncpy:
+#ifdef __RX_DISALLOW_STRING_INSNS__
+ cmp #0, r3
+ beq 3f
+
+ mov r1, r4 ; Preserve R1 for the return value.
+
+2: mov.b [r2+], r5 ; Copy bytes until...
+ mov.b r5, [r4+]
+ sub #1, r3
+ beq 3f ; ... our count reaches zero
+ cmp #0, r5
+ bne 2b ; ... or we have written a NUL byte
+
+4: mov.b r5, [r4+] ; Continue to write further NUL bytes
+ sub #1, r3
+ bne 4b ; until the count reaches zero.
+
+3: rts
+
+#else
mov r1, r4 ; Save a copy of the dest pointer.
mov r3, r5 ; Save a copy of the byte count
smovu ; Copy the bytes
@@ -16,3 +36,6 @@ _strncpy:
1:
mov r4, r1 ; Return the destination pointer
rts
+#endif
+ .size _strncpy, . - _strncpy
+