关于技术的一些奇奇怪怪的知识点

include

include本质就是把include的文件内容拷贝到当前插入include的位置.
所以就可以有一些奇怪的用法:
a.h

1
2
3
4
5
6
#ifndef _AAA
#define _AAA
else:
printf("1\n");

#endif

a.c

1
2
3
4
5
6
7
8
9
10
#include <stdio.h>

void main(void){
int a = 0;
if(a==1){
...
}
#include "a.h"
return;
}

c的结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
struct new1 {
int a1;
};

struct a2 {
struct new1;// 这个位置我们没有给结构体变量名
int a22;
};


int main() {
struct a2 b1;
b1.a1;// 但是, 我们可以直接引用结构体的成员!
return 0;
}

int 到 size_t

对于x64, 无论是gcc还是msvc, 编译int a=-1;size_t new = (size_t)a;的结果, new都是0xffffffffffffffff.

关于clone的编写bug

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
#include<linux/sched.h>
int this_pthread_create(int *tid, void(*thread_func)(void *), void *arg, void *stack_end){
int pid;
*(long*)(stack_end-0x100) = (long)thread_func;
*(long*)(stack_end-0x108) = (long)arg;

// __asm__ __volatile__ (
// "movq $56, %%rax\n\t" // syscall number for clone
// "movl %1, %%edi\n\t" // flags
// "movq %2, %%rsi;\n\t" // child_stack
// "xorq %%rdx, %%rdx;\n\t" // ptid (NULL)
// "xorq %%r10, %%r10;\n\t" // ctid (NULL)
// "movq %3, %%r8;\n\t" // newtls (NULL)
// "syscall;\n\t" // make the system call
// "movl %%eax, %0;" // store the return value in pid
// : "=r" (pid)
// : "r"(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD),
// "r" (stack_end), "r"((long)0)
// : "rax", "rdi", "rsi", "rdx", "r10", "r8"
// );
pid = (int)this_syscall((CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_THREAD),
(long)stack_end,
0,
0,
0,
0,
56 // clone
);
if (pid == -1) {
perror("clone");
return 0;
}
if(pid)
return 1;
else{
printf("child thread\n");
__asm__ __volatile__(
"movq -0x108(%%rsp), %0\n\t"
"movq -0x100(%%rsp), %1\n\t"
:"=r"(arg),"=r"(thread_func)
);
thread_func(arg);
}
// __asm__ __volatile__ (
// "movq $60, %%rax;\n\t" // syscall for exit
// "movq $0, %%rdi;\n\t"
// "syscall;"::
// );
}

int x = 0;
void fnc(void *new){
x = 1;
return;
}
void main(){
int pid;
void *a = calloc(0x1000, 2);
this_pthread_create(&pid, fnc, 0, a+0x1000);
while(1);
}
1
2
3
4
5
6
7
8
9
this_syscall:
push rbp
mov rbp, rsp
mov r10, rcx
mov rax, qword ptr[rbp+0x10]
syscall
pop rbp
ret

这段代码一运行, 就会出现崩溃, 且rip等于0, 用上gdb调试, 也摸不着头脑, 最后终于知道问题在哪, 问题就在this_syscall的实现上.

clone这个syscall调用, 成功时, 会返回两种值, 一种是线程pid, 此时就运行在调用方的线程里. 一种是0, 此时在新建的线程里. 当从新线程返回时, rsp会被更新为新线程的rsp(即函数里的stack_end参数).

this_syscall的第七行调用了pop rbpret, 如果当前线程是新线程, rsp已经被更新了, pop和ret操作都是在新的栈里操作的, 导致ret获取了0作为rip, 从而造成了崩溃.