mirror of
https://github.com/libretro/cpp-cheat.git
synced 2025-04-12 08:14:07 +00:00
Fix broken asm compilation
This commit is contained in:
parent
c30dad784c
commit
3c43b77b46
@ -829,7 +829,7 @@ int main() {
|
||||
*/
|
||||
{
|
||||
/*
|
||||
if (flush(fp) == EOF) {
|
||||
if (fflush(fp) == EOF) {
|
||||
ERROR
|
||||
}
|
||||
*/
|
||||
|
27
gcc/asm.c
27
gcc/asm.c
@ -18,12 +18,10 @@
|
||||
General syntax:
|
||||
|
||||
asm (
|
||||
"movl %1, %%eax;" //commands string
|
||||
"movl %%eax, %0;"
|
||||
"mov $1, %%eax;" //commands string
|
||||
: "=X" (y), //outputs
|
||||
"=X" (z)
|
||||
: "X" (x) //inputs
|
||||
: "X" (x)
|
||||
: "%eax" //clobbered registers
|
||||
);
|
||||
|
||||
@ -75,10 +73,14 @@ int main() {
|
||||
|
||||
The basic one does not have a colon after the string.
|
||||
|
||||
Basic is strictly less powerful:
|
||||
Basic is strictly less powerful: it can only deal with literal commands.
|
||||
*/
|
||||
{
|
||||
#ifdef __i386__
|
||||
asm volatile ("push %eax; mov $1, %eax; pop %eax;");
|
||||
#else
|
||||
asm volatile ("push %rax; mov $1, %rax; pop %rax;");
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
@ -214,13 +216,28 @@ int main() {
|
||||
*/
|
||||
{
|
||||
volatile int x = 0;
|
||||
asm (
|
||||
asm volatile (
|
||||
"incl %0"
|
||||
: "=a" (x)
|
||||
: "0" (x)
|
||||
);
|
||||
assert(x == 1);
|
||||
}
|
||||
|
||||
/*
|
||||
# Register variables
|
||||
|
||||
http://stackoverflow.com/questions/2114163/reading-a-register-value-into-a-c-variable
|
||||
|
||||
https://gcc.gnu.org/onlinedocs/gcc-4.4.2/gcc/Explicit-Reg-Vars.html
|
||||
*/
|
||||
{
|
||||
register int eax asm ("eax");
|
||||
asm volatile ("mov $1, %%eax;" : : : "%eax");
|
||||
assert(eax == 1);
|
||||
asm volatile ("mov $2, %%eax;" : : : "%eax");
|
||||
assert(eax == 2);
|
||||
}
|
||||
#endif
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -11,8 +11,11 @@
|
||||
#include <sched.h> /* SCHED_BATCH, SCHED_IDLE, sched_getaffinity */
|
||||
#include <unistd.h> /* brk, sbrk sysconf */
|
||||
|
||||
#include <sys/ptrace.h>
|
||||
#include <sys/reg.h>
|
||||
#include <sys/ptrace.h> /* ptrace */
|
||||
#include <sys/syscall.h> /* __NR_XXX, SYS_XXX */
|
||||
#include <sys/types.h>
|
||||
#include <sys/user.h> /* user_regs_struct */
|
||||
#include <sys/wait.h> /* wait, sleep */
|
||||
|
||||
#include <gnu/libc-version.h> /* gnu_get_libc_version */
|
||||
|
114
glibc/ptrace.c
114
glibc/ptrace.c
@ -1,22 +1,114 @@
|
||||
/*
|
||||
# ptrace
|
||||
|
||||
Control a child process. You can observe anything in it's state,
|
||||
including memory and registers.
|
||||
|
||||
The child stops transfers control to parent on the following events:
|
||||
|
||||
- signals are raised
|
||||
- `PTRACE_SYSCALL` is used and a system call is reached. Yes, `strace` is "easy" to write.
|
||||
- `PTRACE_SINGLESTEP` does a single instruction and then stops. So this is how GDB does it.
|
||||
|
||||
Bibliograpy:
|
||||
|
||||
- https://github.com/nelhage/ministrace/blob/for-blog/ministrace.c
|
||||
*/
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef __x86_64__
|
||||
#define REGRAX(regs) (intmax_t)regs.rax
|
||||
#define REGRIP(regs) (intmax_t)regs.rip
|
||||
#elif defined __i386__
|
||||
#define REGRAX(regs) (intmax_t)regs.eax
|
||||
#define REGRIP(regs) (intmax_t)regs.eip
|
||||
#endif
|
||||
|
||||
int main() {
|
||||
long orig_eax;
|
||||
if (fork() == 0) {
|
||||
/* Must be called on the child. */
|
||||
|
||||
pid_t child_pid;
|
||||
int i;
|
||||
struct user_regs_struct regs;
|
||||
int status;
|
||||
|
||||
child_pid = fork();
|
||||
if (child_pid == 0) {
|
||||
/*
|
||||
Says that this child can be traced now.
|
||||
|
||||
Alternatives inclue using PTRACE_ATTACH or PTRACE_SEIZE from the parent.
|
||||
*/
|
||||
ptrace(PTRACE_TRACEME, 0, NULL, NULL);
|
||||
puts("child");
|
||||
|
||||
/* We must stop ourselves, or else the child might just run first and finish before the parent. */
|
||||
kill(getpid(), SIGSTOP);
|
||||
|
||||
/* Not puts because it is cached. */
|
||||
write(1, "child0\n", 7);
|
||||
write(1, "child1\n", 7);
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
wait(NULL);
|
||||
orig_eax = ptrace(PTRACE_PEEKUSER,
|
||||
child, 4 * ORIG_EAX,
|
||||
NULL);
|
||||
printf("The child made a "
|
||||
"system call %ld\n", orig_eax);
|
||||
ptrace(PTRACE_CONT, child, NULL, NULL);
|
||||
|
||||
ptrace(PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACESYSGOOD);
|
||||
|
||||
/*
|
||||
This loop goes over: kill (one stop), 2x write (2 stops each).
|
||||
|
||||
kill stops because of the signal it raises. Stops signals happen only once.
|
||||
|
||||
Writes stop because of `PTRACE_SYSCALL`.
|
||||
|
||||
`exit()` calls `sys_exit_group` (x86_64 231) on Ubuntu 14.04,
|
||||
not `sys_exit`, to deal with multithreading.
|
||||
*/
|
||||
for (i = 0; i < 7; i++) {
|
||||
/*
|
||||
Stops both when the system call enters and leaves!
|
||||
|
||||
The main thing to get out of the exiting syscall is the return value in rax.
|
||||
*/
|
||||
ptrace(PTRACE_SYSCALL, child_pid, NULL, NULL);
|
||||
waitpid(child_pid, &status, 0);
|
||||
ptrace(PTRACE_GETREGS, child_pid, NULL, ®s);
|
||||
/*
|
||||
TODO What is the -38 at exit?
|
||||
http://stackoverflow.com/questions/7514837/why-this-ptrace-programe-always-saying-syscall-returned-38?lq=1
|
||||
*/
|
||||
puts("GETREGS");
|
||||
printf(" rax = %jd\n", REGRAX(regs));
|
||||
printf(" rip = 0x%jx\n", REGRIP(regs));
|
||||
|
||||
puts("PEEKUSER");
|
||||
printf(
|
||||
" ORIG_RAX = %jd\n",
|
||||
ptrace(PTRACE_PEEKUSER, child_pid, sizeof(long)*ORIG_RAX)
|
||||
);
|
||||
printf(
|
||||
" RAX = %jd\n",
|
||||
ptrace(PTRACE_PEEKUSER, child_pid, sizeof(long)*RAX)
|
||||
);
|
||||
|
||||
/* Print one word from the virtual memory of the tracee. */
|
||||
printf(
|
||||
"PEEKTEXT rip = 0x%jx\n",
|
||||
ptrace(PTRACE_PEEKTEXT, child_pid, REGRIP(regs), NULL)
|
||||
);
|
||||
|
||||
/* With PTRACE_O_TRACESYSGOOD this can be used to distinguish between TODO */
|
||||
if (WIFSTOPPED(status) && WSTOPSIG(status) & 0x80)
|
||||
puts("PTRACE_O_TRACESYSGOOD");
|
||||
|
||||
fflush(stdout);
|
||||
if (i == 6) {
|
||||
assert(WIFEXITED(status));
|
||||
assert(!WIFSTOPPED(status));
|
||||
} else {
|
||||
assert(!WIFEXITED(status));
|
||||
assert(WIFSTOPPED(status));
|
||||
}
|
||||
puts("");
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
|
@ -51,6 +51,13 @@
|
||||
|
||||
# WIFEXITED
|
||||
|
||||
True is the process exited normally.
|
||||
|
||||
This is false in the following cases:
|
||||
|
||||
- singals
|
||||
- ptrace
|
||||
|
||||
# WEXITSTATUS
|
||||
|
||||
`status` is not set to the exact exit status, but contains multiple fields.
|
||||
|
Loading…
x
Reference in New Issue
Block a user