summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-07-03 18:19:55 -0700
committerAndy Lutomirski <luto@amacapital.net>2014-07-03 18:19:55 -0700
commit54cda8df3f6970ce80fe068b0aa7b244841d0faa (patch)
treea8e164733aea3daa8310f5bdc7414a95d4ef4919
parent2cb30ed696bae0d4bdd882b5be3e05d07beb166e (diff)
downloadmisc-tests-54cda8df3f6970ce80fe068b0aa7b244841d0faa.tar.gz
Add syscall32_from_64
-rw-r--r--Makefile5
-rw-r--r--syscall32_from_64.c22
-rw-r--r--thunks.S60
3 files changed, 86 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 0cd9eb3..e752ac7 100644
--- a/Makefile
+++ b/Makefile
@@ -7,7 +7,7 @@ SIMPLE_CC_TARGETS := evil-clock-test
SPLIT_C_TARGETS := dump-vdso dump-vvar syscall_exit_regs
SPLIT_CC_TARGETS := timing_test test_vsyscall
-ALL_TARGETS := $(SIMPLE_C_TARGETS) $(SIMPLE_CC_TARGETS) $(SPLIT_C_TARGETS:%=%_64) $(SPLIT_CC_TARGETS:%=%_64) $(SPLIT_C_TARGETS:%=%_32) $(SPLIT_CC_TARGETS:%=%_32)
+ALL_TARGETS := $(SIMPLE_C_TARGETS) $(SIMPLE_CC_TARGETS) $(SPLIT_C_TARGETS:%=%_64) $(SPLIT_CC_TARGETS:%=%_64) $(SPLIT_C_TARGETS:%=%_32) $(SPLIT_CC_TARGETS:%=%_32) syscall32_from_64
CFLAGS := -O2 -g -std=gnu99 -pthread -Wall
CCFLAGS := -O2 -g -std=gnu++11 -pthread -Wall
@@ -34,3 +34,6 @@ $(SPLIT_CC_TARGETS:%=%_32): %_32: %.cc
$(SPLIT_CC_TARGETS:%=%_64): %_64: %.cc
g++ -m64 -o $@ $(CCFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
+
+syscall32_from_64: syscall32_from_64.c thunks.S
+ gcc -m64 -o $@ $(CFLAGS) $(EXTRA_CFLAGS) $^ -lrt -ldl
diff --git a/syscall32_from_64.c b/syscall32_from_64.c
new file mode 100644
index 0000000..775cef2
--- /dev/null
+++ b/syscall32_from_64.c
@@ -0,0 +1,22 @@
+#include <stdio.h>
+
+extern unsigned long call32_from_64(void *stack, void (*function)(void));
+
+asm (".pushsection .text\n\t"
+ ".code32\n\t"
+ "syscall32:\n\t"
+ "mov $20,%eax\n\t" // NR_getpid (32-bit)
+ "syscall\n\t"
+ "syscall32_ret:\n\t"
+ "ret\n\t"
+ ".code64");
+extern void syscall32(void);
+
+static char low_stack[4096];
+
+int main()
+{
+ unsigned long ret = call32_from_64(low_stack, syscall32);
+ printf("syscall return = %ld\n", (long)ret);
+ return 0;
+}
diff --git a/thunks.S b/thunks.S
new file mode 100644
index 0000000..ab3a0a0
--- /dev/null
+++ b/thunks.S
@@ -0,0 +1,60 @@
+ .text
+
+ .global init_thunks
+ .type init_thunks, @function
+init_thunks:
+ mov $0x2b, %rax /* USER32_DS */
+ mov %rax,%ss
+ mov %rax,%ds
+ mov %rax,%es
+ ret
+.size init_thunks, .-init_thunks
+
+ .global call32_from_64
+ .type call32_from_64, @function
+call32_from_64:
+ // rdi: stack to use
+ // esi: function to call
+
+ // Save registers
+ pushq %rbx
+ pushq %rbp
+ pushq %r12
+ pushq %r13
+ pushq %r14
+ pushq %r15
+ pushfq
+
+ // Switch stacks
+ mov %rsp,(%rdi)
+ mov %rdi,%rsp
+
+ // Switch to compatibility mode
+ pushq $0x23 /* USER32_CS */
+ pushq $1f
+ lretq
+
+1:
+ .code32
+ // Call the function
+ call *%esi
+ // Switch back to long mode
+ jmp $0x33,$1f
+ .code64
+
+1:
+ // Restore the stack
+ mov (%rsp),%rsp
+
+ // Restore registers
+ popfq
+ popq %r15
+ popq %r14
+ popq %r13
+ popq %r12
+ popq %rbp
+ popq %rbx
+
+ ret
+
+.size call32_from_64, .-call32_from_64