userland: add assembly support

Move arm assembly cheat here, and start some work on x86 cheat as well.
This commit is contained in:
Ciro Santilli 六四事件 法轮功
2019-03-22 00:00:00 +00:00
parent 4943c9ed2e
commit 287c83f3f9
117 changed files with 3870 additions and 547 deletions

View File

@@ -0,0 +1,39 @@
/* https://github.com/cirosantilli/arm-assembly-cheat#calling-convention */
#include <assert.h>
#include <inttypes.h>
uint64_t my_asm_func(void);
/* { return 42; } */
__asm__(
".global my_asm_func;"
"my_asm_func:"
"mov x0, 42;"
"ret;"
);
/* Now a more complex example that also calls a C function.
* We have to store the return value x30 for later because bl modifies it.
* https://stackoverflow.com/questions/27941220/push-lr-and-pop-lr-in-arm-arch64/34504752#34504752
* We are not modifying any other callee saved register in this function,
* since my_c_func is not either (unless GCC has a bug ;-)), so everything else if fine.
*/
uint64_t my_asm_func_2(void);
/* { return my_c_func(); } */
__asm__(
".global my_asm_func_2;"
"my_asm_func_2:"
"str x30, [sp, -16]!;"
"bl my_c_func;"
"ldr x30, [sp], 16;"
"ret;"
);
uint64_t my_c_func(void) {
return 42;
}
int main(void) {
assert(my_asm_func() == 42);
assert(my_asm_func_2() == 42);
}

View File

@@ -0,0 +1 @@
../build

View File

@@ -0,0 +1,21 @@
/* An example of using the '&' earlyclobber modifier.
* https://stackoverflow.com/questions/15819794/when-to-use-earlyclobber-constraint-in-extended-gcc-inline-assembly/54853663#54853663
* The assertion may fail without it. It actually does fail in GCC 8.2.0 at
* 34017bcd0bc96a3cf77f6acba4d58350e67c2694 + 1.
*/
#include <assert.h>
#include <inttypes.h>
int main(void) {
uint64_t in = 1;
uint64_t out;
__asm__ (
"add %[out], %[in], 1;"
"add %[out], %[in], 1;"
: [out] "=&r" (out)
: [in] "r" (in)
:
);
assert(out == 2);
}

View File

@@ -0,0 +1 @@
../build

View File

@@ -0,0 +1,37 @@
/* https://github.com/cirosantilli/arm-assembly-cheat#freestanding-linux-inline-assembly-system-calls */
#include <inttypes.h>
void _start(void) {
uint64_t exit_status;
/* write */
{
char msg[] = "hello\n";
uint64_t syscall_return;
register uint64_t x0 __asm__ ("x0") = 1; /* stdout */
register char *x1 __asm__ ("x1") = msg;
register uint64_t x2 __asm__ ("x2") = sizeof(msg);
register uint64_t x8 __asm__ ("x8") = 64; /* syscall number */
__asm__ __volatile__ (
"svc 0;"
: "+r" (x0)
: "r" (x1), "r" (x2), "r" (x8)
: "memory"
);
syscall_return = x0;
exit_status = (syscall_return != sizeof(msg));
}
/* exit */
{
register uint64_t x0 __asm__ ("x0") = exit_status;
register uint64_t x8 __asm__ ("x8") = 93;
__asm__ __volatile__ (
"svc 0;"
: "+r" (x0)
: "r" (x8)
:
);
}
}

View File

@@ -0,0 +1,40 @@
/* Like hello.c trying to do it without named register variables.
* The code is more complicated, and I was not able to get as efficient,
* so better just stick to named register variables.
*/
#include <inttypes.h>
void _start(void) {
uint64_t exit_status;
/* write */
{
char msg[] = "hello\n";
uint64_t syscall_return;
__asm__ (
"mov x0, 1;" /* stdout */
"mov x1, %[msg];"
"mov x2, %[len];"
"mov x8, 64;" /* syscall number */
"svc 0;"
"mov %[syscall_return], x0;"
: [syscall_return] "=r" (syscall_return)
: [msg] "p" (msg),
[len] "i" (sizeof(msg))
: "x0", "x1", "x2", "x8", "memory"
);
exit_status = (syscall_return != sizeof(msg));
}
/* exit */
__asm__ (
"mov x0, %[exit_status];"
"mov x8, 93;" /* syscall number */
"svc 0;"
:
: [exit_status] "r" (exit_status)
: "x0", "x8"
);
}

View File

@@ -0,0 +1,13 @@
#include <assert.h>
#include <inttypes.h>
int main(void) {
uint64_t io = 1;
__asm__ (
"add %[io], %[io], 1;"
: [io] "+r" (io)
:
:
);
assert(io == 2);
}

View File

@@ -0,0 +1,28 @@
/* https://stackoverflow.com/questions/53960240/armv8-floating-point-output-inline-assembly
*
* We use the undocumented %s and %d modifiers!
*/
#include <assert.h>
int main(void) {
float my_float = 1.5;
__asm__ (
"fmov s0, 1.0;"
"fadd %s[my_float], %s[my_float], s0;"
: [my_float] "+w" (my_float)
:
: "s0"
);
assert(my_float == 2.5);
double my_double = 1.5;
__asm__ (
"fmov d0, 1.0;"
"fadd %d[my_double], %d[my_double], d0;"
: [my_double] "+w" (my_double)
:
: "d0"
);
assert(my_double == 2.5);
}

View File

@@ -0,0 +1,18 @@
// https://stackoverflow.com/questions/3666013/how-to-write-multiline-inline-assembly-code-in-gcc-c/54575948#54575948
#include <assert.h>
#include <inttypes.h>
int main(void) {
uint64_t io = 0;
__asm__ (
R"(
add %[io], %[io], #1
add %[io], %[io], #1
)"
: [io] "+r" (io)
:
:
);
assert(io == 2);
}

View File

@@ -0,0 +1,27 @@
/* https://github.com/cirosantilli/arm-assembly-cheat#register-variables */
#include <assert.h>
#include <inttypes.h>
int main(void) {
register uint32_t x0 __asm__ ("x0");
register uint32_t x1 __asm__ ("x1");
uint32_t new_x0;
uint32_t new_x1;
{
x0 = 1;
x1 = 2;
__asm__ (
"add %[x0], x0, #1;"
"add %[x1], x1, #1;"
: [x0] "+r" (x0),
[x1] "+r" (x1)
:
:
);
new_x0 = x0;
new_x1 = x1;
}
assert(new_x0 == 2);
assert(new_x1 == 3);
}

View File

@@ -0,0 +1,28 @@
/* https://github.com/cirosantilli/arm-assembly-cheat#register-variables */
#include <assert.h>
#include <inttypes.h>
int main(void) {
register double d0 __asm__ ("d0");
register double d1 __asm__ ("d1");
double new_d0;
double new_d1;
{
d0 = 1.5;
d1 = 2.5;
__asm__ (
"fmov d2, 1.5;"
"fadd %d[d0], d0, d2;"
"fadd %d[d1], d1, d2;"
: [d0] "+w" (d0),
[d1] "+w" (d1)
:
: "d2"
);
new_d0 = d0;
new_d1 = d1;
}
assert(new_d0 == 3.0);
assert(new_d1 == 4.0);
}