The new test rck_e.e segfaults on PowerPC unless I make some changes.
The inline code for _rck_ was wrong because it didn't allow the trap
handler to return. _sig_ forgot to push the old trap handler.
Move plat/linuxppc/libsys/trap.s to mach/powerpc/libem/trp.s and
rewrite it with simplified/extended mnemonics. Remove .trap alias for
.trp procedure. Add a missing `mtspr lr, r0` so we can return from
the trap handler. Call write() and _exit() so trp.s works with both
linuxppc and osxppc. Before, Mac OS X was wrongly using the trap.s
for Linux.
In powerpc/libem, simplify .aar4; teach .csa and .csb to raise the
trap if the default target is zero.
C programs don't need these changes. You may relink your C programs
with the changed .csa and .csb, but C code doesn't raise the trap.
Modula-2 code can raise traps, so you may want to relink your Modula-2
programs with the changed libem, but you might keep your old .o files
from Modula-2. You may need to recompile your Pascal programs (delete
old .o files from Pascal) because the Pascal compiler might use _rck_.
.define .aar4
.aar4:
- lis r0, hi16[.trap_earray]
- ori r0, r0, lo16[.trap_earray]
- mtspr ctr, r0 ! load CTR with trap address
-
lwz r4, 0(sp) ! r4 = address of descriptor
lwz r5, 4(sp) ! r5 = index
lwz r6, 8(sp) ! r6 = address of array
lwz r0, 0(r4)
subf. r5, r0, r5 ! subtract lower bound from index
- bltctr ! check lower bound
+ blt .trap_earray ! check lower bound
lwz r0, 4(r4)
cmplw r5, r0
- bgtctr ! check upper bound
+ bgt .trap_earray ! check upper bound
lwz r3, 8(r4) ! r3 = size of element
mullw r5, r5, r3 ! scale index by size
stw r6, 8(sp) ! push address of element
addi sp, sp, 8
blr
+
+.trap_earray:
+ li r3, 0 ! EARRAY = 0 in h/em_abs.h
+ b .trp
acklibrary {
name = "lib_"..plat,
srcs = {
- "./*.s", -- exg.s
+ "./*.s", -- trp.s
},
vars = { plat = plat },
deps = {
}
}
end
-
lwz r4, 4(sp)
addi sp, sp, 8
- lwz r5, 0(r3) ! load default
- mtspr ctr, r5
-
- lwz r5, 4(r3) ! fetch lower bound
- subf. r4, r5, r4 ! adjust value
- bltctr ! jump to default if out of range
+ lwz r5, 0(r3) ! r5 = default target
- lwz r5, 8(r3) ! fetch range
- cmplw r4, r5
- bgtctr ! jump to default if out of range
+ lwz r6, 4(r3) ! fetch lower bound
+ subf. r4, r6, r4 ! adjust value
+ blt 1f ! jump to default if out of range
+
+ lwz r6, 8(r3) ! fetch range
+ cmplw r4, r6
+ bgt 1f ! jump to default if out of range
addi r3, r3, 12 ! skip header
slwi r4, r4, 2 ! scale value (<<2)
- lwzx r5, r3, r4 ! load target
- mtspr ctr, r5
+ lwzx r5, r3, r4 ! r5 = new target
- or. r5, r5, r5 ! test it
+1: mtspr ctr, r5
+ mr. r5, r5 ! test it
bnectr ! jump to target if non-zero
b .trap_ecase ! otherwise trap
lwz r4, 4(sp)
addi sp, sp, 8
- lwz r5, 0(r3) ! load default
- mtspr ctr, r5
+ lwz r5, 0(r3) ! r5 = default target
lwz r6, 4(r3) ! fetch count
-
-1:
- or. r6, r6, r6 ! test count
- beqctr ! exit if zero
- addi r6, r6, -1 ! otherwise decrement
-
- lwzu r7, 8(r3) ! fetch target index, increment pointer
+ mr. r6, r6 ! skip loop if count is zero
+ beq 3f ! (needed by Modula-2 "CASE i OF END")
+ mtspr ctr, r6
+1: lwzu r7, 8(r3) ! fetch target index, increment pointer
cmpw r4, r7 ! compare with value
- bne 1b ! if not equal, go again
-
- lwz r7, 4(r3) ! fetch target address
- mtspr ctr, r7
+ beq 2f
+ bdnz 1b ! if not equal, go again
+ b 3f
- or. r7, r7, r7 ! test it
+2: lwz r5, 4(r3) ! r5 = new target
+3: mtspr ctr, r5
+ mr. r5, r5 ! test target
bnectr ! jump to target if non-zero
b .trap_ecase ! otherwise trap
bgt .trap_erange
blr
+
+.trap_erange:
+ li r3, 1 ! ERANGE = 1 in h/em_abs.h
+ b .trp
--- /dev/null
+.sect .text
+
+.define .trap_ecase
+.trap_ecase:
+ li r3, 20 ! ECASE = 20 in h/em_abs.h
+ ! FALLTHROUGH to .trp
+
+! Raises an EM trap.
+! Expects r3 = trap number.
+
+.define .trp
+.trp:
+ cmplwi r3, 15 ! traps > 15 can't be ignored
+ bgt 1f
+
+ lis r4, ha16[.ignmask]
+ lwz r4, lo16[.ignmask](r4) ! load ignore mask
+ srw r4, r4, r3
+ andi. r4, r4, 1
+ bnelr ! return if ignoring trap
+
+1: lis r4, ha16[.trppc]
+ lwz r5, lo16[.trppc](r4) ! r5 = user trap routine
+ mr. r5, r5
+ beq 2f ! if no user trap routine, bail out
+
+ mtspr ctr, r5
+ mfspr r6, lr
+ li r0, 0
+ stwu r3, -8(sp) ! push trap number
+ stw r0, lo16[.trppc](r4) ! reset trap routine
+ stw r6, 4(sp) ! save old lr
+ bctrl ! call trap routine
+
+ lwz r0, 4(sp)
+ mtspr lr, r0
+ addi sp, sp, 8 ! retract over stack usage
+ blr
+
+2: ! No trap handler. Write error message, exit.
+ li r3, 2
+ stwu r3, -12(sp)
+ lis r4, ha16[message]
+ addi r4, r4, lo16[message]
+ li r5, 6
+ stw r4, 4(sp)
+ stw r5, 8(sp)
+ bl _write ! write(2, message, 6)
+
+ li r3, 1
+ stw r3, 0(sp)
+ bl __exit ! _exit(1)
+
+.sect .rom
+message:
+ .ascii "TRAP!\n"
pat trp /* Raise EM trap */
with REG3
kills ALL
- gen bl {LABEL, ".trap"}
+ gen bl {LABEL, ".trp"}
- pat sig /* Set trap handler */
- leaving ste ".trppc"
+ pat sig /* Set trap handler, yield old */
+ leaving
+ loe ".trppc"
+ exg 4
+ ste ".trppc"
pat rtt /* Return from trap */
leaving ret 0
with REG
gen move %1, sp
- pat lae rck $2==4 /* Range check */
- with REG
- kills ALL
- gen
- cmpwi %1, {C, rom($1, 1)}
- blt {LABEL, ".trap_erange"}
- cmpwi %1, {C, rom($1, 2)}
- bgt {LABEL, ".trap_erange"}
- yields %1
+ pat rck $1==4 /* Range check */
+ leaving cal ".rck"
/* Single-precision floating-point */
pat zrf $1==4 /* Push zero */
- leaving
- loe ".fs_00000000"
+ leaving loe ".fs_00000000"
pat adf $1==4 /* Add single */
with FSREG FSREG
"./_syscall.s",
"./sigaction.s",
"./signal.c",
- "./trap.s",
"plat/linux/libsys/_exit.c",
"plat/linux/libsys/_hol0.s",
"plat/linux/libsys/close.c",
+++ /dev/null
-#
-! $Source: /cvsroot/tack/Ack/plat/linux386/libsys/_syscall.s,v $
-! $State: Exp $
-! $Revision: 1.1 $
-
-! Declare segments (the order is important).
-
-.sect .text
-.sect .rom
-.sect .data
-.sect .bss
-
-.sect .text
-
-#define IFFALSE 4
-#define IFTRUE 12
-#define ALWAYS 20
-
-#define LT 0
-#define GT 1
-#define EQ 2
-#define OV 3
-
-EARRAY = 0
-ERANGE = 1
-ESET = 2
-EIOVFL = 3
-EFOVFL = 4
-EFUNFL = 5
-EIDIVZ = 6
-EFDIVZ = 7
-EIUND = 8
-EFUND = 9
-ECONV = 10
-ESTACK = 16
-EHEAP = 17
-EILLINS = 18
-EODDZ = 19
-ECASE = 20
-EMEMFLT = 21
-EBADPTR = 22
-EBADPC = 23
-EBADLAE = 24
-EBADMON = 25
-EBADLIN = 26
-EBADGTO = 27
-EUNIMPL = 63 ! unimplemented em-instruction called
-
-! EM trap handling.
-
-.define .trap_ecase
-.trap_ecase:
- addi r3, r0, ECASE
- b .trap
-
-.define .trap_earray
-.trap_earray:
- addi r3, r0, EARRAY
- b .trap
-
-.define .trap_erange
-.trap_erange:
- addi r3, r0, ERANGE
- b .trap
-
-.define .trp
-.define .trap
-.trp:
-.trap:
- cmpi cr0, 0, r3, 15 ! traps >15 can't be ignored
- bc IFTRUE, LT, 1f
-
- addi r4, r0, 1
- rlwnm r4, r4, r3, 0, 31 ! calculate trap bit
- li32 r5, .ignmask
- lwz r5, 0(r5) ! load ignore mask
- and. r4, r4, r5 ! compare
- bclr IFFALSE, EQ, 0 ! return if non-zero
-
-1:
- li32 r4, .trppc
- lwz r5, 0(r4) ! load user trap routine
- or. r5, r5, r5 ! test
- bc IFTRUE, EQ, fatal ! if no user trap routine, bail out
-
- addi r0, r0, 0
- stw r0, 0(r4) ! reset trap routine
-
- mfspr r0, lr
- stwu r0, -4(sp) ! save old lr
-
- stwu r3, -4(sp)
- mtspr ctr, r5
- bcctrl ALWAYS, 0, 0 ! call trap routine
-
- lwz r0, 4(sp) ! load old lr again
- addi sp, sp, 8 ! retract over stack usage
- bclr ALWAYS, 0, 0 ! return
-
-fatal:
- addi r3, r0, 1
- li32 r4, message
- addi r5, r0, 6
- addi r0, r0, 4 ! write()
- sc 0
-
- addi r0, r0, 1 ! exit()
- sc 0
-
-.sect .rom
-message:
- .ascii "TRAP!\n"
"./sigaction.s",
"./stat.s",
"./write.s",
- "plat/linuxppc/libsys/trap.s",
"plat/osx/libsys/brk.c",
"plat/osx/libsys/creat.c",
"plat/osx/libsys/isatty.c",
"tests/plat/dup_e.e",
"tests/plat/exg_e.e",
"tests/plat/inn_e.e",
+ "tests/plat/rck_e.e",
"tests/plat/rotate_e.e",
"tests/plat/*.p",
"tests/plat/b/*.b",
--- /dev/null
+#
+ mes 2, EM_WSIZE, EM_PSIZE
+
+/*
+ * Uses _rck_ for range checks. Catches the EM trap if a value is out
+ * of range, and continues with the next instruction after _rck_.
+ *
+ * Some back ends, like i80, ignore _rck_, so this test fails.
+ */
+
+testnr
+ con 1 ; test number
+caught
+ con 0 ; number of caught traps
+
+ inp $next
+ inp $catch
+ inp $never
+ exp $_m_a_i_n
+ pro $_m_a_i_n,0
+
+ lim ; load ignore mask
+ loc 2
+ and EM_WSIZE ; check bit 1 << ERANGE
+ zeq *1 ; fail if ignoring ERANGE
+.1
+ rom 1I4
+ lae .1
+ loi 4
+ cal $fail
+ asp 4
+1
+
+ cal $next ; increment testnr, catch next trap
+ loc 10125
+.2
+ rom 4283, 13644
+ lae .2
+ rck EM_WSIZE ; testnr 2 in range
+ asp EM_WSIZE
+
+ cal $next
+ loc 4282
+ lae .2
+ rck EM_WSIZE ; testnr 3 out of range
+ asp EM_WSIZE
+
+ cal $next
+ loc 4283
+ lae .2
+ rck EM_WSIZE ; testnr 4 in range
+ asp EM_WSIZE
+
+ cal $next
+ loc 13644
+ lae .2
+ rck EM_WSIZE ; testnr 5 in range
+ asp EM_WSIZE
+
+ cal $next
+ loc 13655
+ lae .2
+ rck EM_WSIZE ; testnr 6 out of range
+ asp EM_WSIZE
+
+ cal $next
+ loc -13015
+.7
+ rom -31344, -1898
+ lae .7
+ rck EM_WSIZE ; testnr 7 in range
+ asp EM_WSIZE
+
+ cal $next
+ loc 8580
+.8
+ rom -26315, 4588
+ lae .8
+ rck EM_WSIZE ; testnr 8 out of range
+ asp EM_WSIZE
+
+ ; The last test raised a trap, so now there is no trap handler.
+ lpi $never
+ sig ; push old trap handler
+ loc 0
+ loc EM_WSIZE
+ loc EM_PSIZE
+ cuu ; push NULL pointer
+ cmp
+ zeq *17 ; fail unless old handler is NULL
+.17
+ rom 17I4
+ lae .17
+ loi 4
+ cal $fail
+ asp 4
+17
+ ; Change the trap handler from $never to $catch.
+ lpi $catch
+ sig
+ lpi $never
+ cmp
+ zeq *18
+.18
+ rom 18I4
+ lae .18
+ loi 4
+ cal $fail
+ asp 4
+18
+ ; Begin ignoring range traps.
+ loc 2 ; 1 << ERANGE
+ sim
+ loc 18
+ ste testnr
+ loc 8580
+ lae .8
+ rck EM_WSIZE ; testnr 18 out of range but ignored
+
+ ; Fail if we caught the wrong number of traps.
+ loe caught
+ loc 3
+ beq *20
+.20
+ rom 20I4
+ lae .20
+ loi 4
+ cal $fail
+ asp 4
+20
+ cal $finished
+ end
+
+ pro $next,0
+ ine testnr ; next test
+ lpi $catch
+ sig ; catch next EM trap (only one trap)
+ asp EM_PSIZE
+ ret 0
+ end
+
+ pro $catch,0
+ ine caught ; count this trap
+
+ lol 0 ; load trap number
+ loc 1
+ beq *1 ; fail if trap != ERANGE
+.101
+ rom 257I4
+ lae .101
+ loi 4
+ cal $fail
+ ; Wrong type of trap. _rtt_ might not work, so exit now.
+ cal $finished
+1
+ ; Fail if the wrong test raised this trap.
+ loe testnr
+ loc 3
+ beq *2
+ loe testnr
+ loc 6
+ beq *2
+ loe testnr
+ loc 8
+ beq *2
+ loc 256
+ loe testnr
+ adi EM_WSIZE ; 0x100 + testnr
+ loc EM_WSIZE
+ loc 4
+ cuu
+ cal $fail
+ asp 4
+2
+ rtt ; return from trap handler
+ end
+
+ pro $never,0
+.200
+ rom 200I4
+ lae .200
+ loi 4
+ cal $fail
+ asp 4
+ rtt
+ end