Code Monkey home page Code Monkey logo

wiflin.github.io's People

Contributors

wiflin avatar

Watchers

 avatar

wiflin.github.io's Issues

Boom lab 【实验】

整个实验当中收获最大的是对汇编语言结构的理解,包括 栈段,程序段,和常量区。

对gdb的使用上升了一个层次,特别是用set方法改内存值不断验证猜想。

通关密码

We have to stand with our North Korean allies.
0 1 1 2 3 5
1 -641
11 1
5 115
5 6 1 4 3 2

炸弹实验 phase-1

第一关密码:"We have to stand with our North Korean allies."

GDB 使用方法

print

p $eax
显示寄存器的内容

p/格式 变量

格式

t 显示为2进制数
o 显示为8进制数
d 显示为10进制数
u 显示为无符号10进制数
x 显示为16进制数
a 地址
c 显示为字符
s 显示为字符串
f 浮点小数
i 显示为机器语言(仅在显示内存的x命令中可用)

程序指针可以写为 $pc 或者 $eip ,因为Intel IA-32架构中的程序指针名为eip
p $pc
p $eip

examine

x 显示特定的内存位置内容

x/格式 地址

x 命令的格式 x/nyz

n 是要显示的字段数
y 是输出格式 同之前的 print 一样
z 是要显示的字段长度:
b 字节
h 半字(2字节)
w 字(4字节)默认值
g 双字(8字节)

例如:
x $pc
x/i $pc

此处x/i意为显示汇编指令
也有反汇编命令disassemble(或者disas)
格式:
disas
disas 程序计数器
disas 开始地址 结束地址1

炸弹实验 phase-2

第二关密码 “0 1 1 2 3 5 ”

read_six_nums

    (gdb) x/4xw $esp              
    0xffffcda0:     0x0804c430      0x0804a232      0xffffcde8      0xffffcdec                                                           
    0xffffcdb0:     0xffffcdf0      0xffffcdf4      0xffffcdf8      0xffffcdfc

phase_2

$ebp = 0xffffce08

(gdb) x/xw 0xffffcde8
0xffffcde8:     0x00000001    ebp-0x20
0xffffcdec:     0x00000002    ebp-0x1c
0xffffcdf0:     0x00000003    ebp-0x18
0xffffcdf4:     0x00000004    ebp-0x14
0xffffcdf8:     0x00000005    ebp-0x10
0xffffcdfc:     0x00000006    ebp-0xc

过程

(gdb) p $ebp-0x20
$8 = (void *) 0xffffcde8

(gdb) x/xw 0xffffcde8
0xffffcde8:     0x00000001

(gdb) set 0xffffcde8=0x0
Left operand of assignment is not an lvalue.

(gdb) set *0xffffcde8=0x0
(gdb) x/xw 0xffffcde8
0xffffcde8:     0x00000000

第一个数

读取完六个数之后返回 [phase_2] 发现
0x8048d84 <phase_2+26> cmpl $0x0,-0x20(%ebp)

这个正是输入的第一个数的值,取此值和0比较
于是强行修改此值**set *0xffffcde8=0x0**

成功通过测试

第二个数

接下来有
0x8048d8a <phase_2+32> cmpl $0x1,-0x1c(%ebp)
第二个数位为1

第三个数

0x8048d95 <phase_2+43>  lea    -0x18(%ebp),%ebx
0x8048d98 <phase_2+46>  lea    -0x8(%ebp),%esi
0x8048d9b <phase_2+49>  mov    -0x4(%ebx),%eax
0x8048d9e <phase_2+52>  add    -0x8(%ebx),%eax
0x8048da1 <phase_2+55>  cmp    %eax,(%ebx)
0x8048da3 <phase_2+57>  je     0x8048daa <phase_2+64>
0x8048da5 <phase_2+59>  call   0x80490d1 <explode_bomb>
0x8048daa <phase_2+64>  add    $0x4,%ebx
0x8048dad <phase_2+67>  cmp    %esi,%ebx
0x8048daf <phase_2+69>  jne    0x8048d9b <phase_2+49>
0xffffcdf0:     0x00000003    ebp-0x18  <-ebx

炸弹日志 phase_3

有多组答案:
第一组 ”1 -641 “

关键过程

读取输入数据后,第一个数据保存在$ebp-0xc,第二个数据保存在$ebp-0x10

接下来就有代码:
基于第一个输入的输给出的跳转偏移地址 jmp *0x804a1a0(,%eax,4)
查看偏移地址

(gdb) x/4xw 0x804a1a0-0x10
0x804a190:      0x00000000      0x00000000      0x00000000      0x00000000
(gdb) x/4xw 0x804a1a0
0x804a1a0:      0x08048f12      0x08048f19      0x08048f09      0x08048f02
0x804a1b0:      0x08048ef9      0x08048ef2      0x08048ee9      0x08048ee2
0x804a1c0 <array.3488>: 0x0000000a      0x00000002      0x0000000e      0x00000007
0x804a1d0 <array.3488+16>:      0x00000008      0x0000000c      0x0000000f      0x0000000b
0x804a1e0 <array.3488+32>:      0x00000000      0x00000004      0x00000001      0x0000000d

接下来,看看接下来的代码,显然这一段就是要跳转的地方,先跳过这段代码

 8048ee2:	b8 00 00 00 00       	mov    $0x0,%eax
 8048ee7:	eb 53                	jmp    8048f3c <phase_3+0x9b>
 8048ee9:	b8 00 00 00 00       	mov    $0x0,%eax
 8048eee:	66 90                	xchg   %ax,%ax
 8048ef0:	eb 45                	jmp    8048f37 <phase_3+0x96>
 8048ef2:	b8 00 00 00 00       	mov    $0x0,%eax
 8048ef7:	eb 39                	jmp    8048f32 <phase_3+0x91>
 8048ef9:	b8 00 00 00 00       	mov    $0x0,%eax
 8048efe:	66 90                	xchg   %ax,%ax
 8048f00:	eb 2b                	jmp    8048f2d <phase_3+0x8c>
 8048f02:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f07:	eb 1f                	jmp    8048f28 <phase_3+0x87>
 8048f09:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f0e:	66 90                	xchg   %ax,%ax
 8048f10:	eb 11                	jmp    8048f23 <phase_3+0x82>
 8048f12:	b8 14 03 00 00       	mov    $0x314,%eax
 8048f17:	eb 05                	jmp    8048f1e <phase_3+0x7d>
 8048f19:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f1e:	2d 5a 03 00 00       	sub    $0x35a,%eax
 8048f23:	05 ef 02 00 00       	add    $0x2ef,%eax
 8048f28:	2d 16 02 00 00       	sub    $0x216,%eax
 8048f2d:	05 16 02 00 00       	add    $0x216,%eax
 8048f32:	2d 16 02 00 00       	sub    $0x216,%eax
 8048f37:	05 16 02 00 00       	add    $0x216,%eax
 8048f3c:	2d 16 02 00 00       	sub    $0x216,%eax

这段程序后面有两句
cmpl $0x5,-0xc(%ebp)
jg 8048f58 <phase_3+0xb7> <--boom
表明输入第一个数<=5

关键发现

到了程序段结尾,才发现有对$ebp-0x10的读取,即 第二个数
看到这里豁然开朗:因为第一个数的运算结果就保存在$eax

cmp    -0x10(%ebp),%eax
je     8048f5d <phase_3+0xbc>    <<---程序结束

那我就只要找到程序对$eax做了什么运算

解题

可见$eax = 1时,跳转0x08048f19地址最大,执行的代码最少,方便阅读
执行那段代码后运算结果位-641

试图强制设置内存值,发现 程序成功运行

(gdb) p $ebp-0x10
$1 = (void *) 0xffffcde8
(gdb) set *0xffffcde8 = -641
(gdb) x/xw 0xffffcde8
0xffffcde8:     0xfffffd7f
(gdb) x/dw 0xffffcde8
0xffffcde8:     -641
(gdb) ni
0x08048f56 in phase_3 ()
0x08048f5d in phase_3 ()

炸弹实验 第四关

理论上有多组密码
密码 "11 1 "

读取数据

8048e50:	e8 eb f9 ff ff       	call   8048840 <__isoc99_sscanf@plt>
8048e55:	83 f8 02             	cmp    $0x2,%eax
8048e58:	75 0c                	jne    8048e66 <phase_4+0x38>  <<---- boom

读出来的数据存在

(gdb) x/xw $ebp-0x10
0xffffcde8:     0x00000002
0xffffcdec:     0x00000001

对第一个数操作

8048e5a:	8b 45 f4             	mov    -0xc(%ebp),%eax
8048e5d:	85 c0                	test   %eax,%eax
8048e5f:	78 05                	js     8048e66 <phase_4+0x38>  <<--- boom
8048e61:	83 f8 0e             	cmp    $0xe,%eax
8048e64:	7e 05                	jle    8048e6b <phase_4+0x3d>  <<--- jmp over boom

接下来传进几个参数执行函数func

0xe	esp+0x8
0x0	esp+0x4
0x1	esp+0x0 <<---输入的第一个数

函数返回后

8048e86:	83 f8 01             	cmp    $0x1,%eax
8048e89:	75 06                	jne    8048e91 <phase_4+0x63>   <<--- boom
8048e8b:	83 7d f0 01          	cmpl   $0x1,-0x10(%ebp)
8048e8f:	74 0c                	je     8048e9d <phase_4+0x6f>   <<--- jmp over boom111
8048e91:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
8048e98:	e8 34 02 00 00       	call   80490d1 <explode_bomb>
8048e9d:	c9                   	leave  

函数执行返回结果保存在 $eax 中,$eax == 0x1
并且 -0x10($ebp) == 0x1

fun4

void fun(int ebx,int eax,int edx)
{
    ecx = ebx - eax;
    ecx += (ecx < 0);
    ecx = ecx / 2 + eax;

    if( ecx > edx )
    {
        ecx--;
        fun(ecx,eax,edx);
        eax *= 2;
    }

    eax = 0;

    if( ecx < edx )
    {
        ecx++;
        fun(ebx,ecx,edx);
        eax = eax * 2 + 1;
    }

    return ;
}

炸弹实验 第五关

密码 “5 115 ”

过程

(gdb) x/xw $ebx
0x804a1c0 <array.3488>:         0x0000000a
0x804a1c4 <array.3488+4>:       0x00000002
0x804a1c8 <array.3488+8>:       0x0000000e
0x804a1cc <array.3488+12>:      0x00000007
0x804a1d0 <array.3488+16>:      0x00000008
0x804a1d4 <array.3488+20>:      0x0000000c
0x804a1d8 <array.3488+24>:      0x0000000f
0x804a1dc <array.3488+28>:      0x0000000b
0x804a1e0 <array.3488+32>:      0x00000000
0x804a1e4 <array.3488+36>:      0x00000004
0x804a1e8 <array.3488+40>:      0x00000001
0x804a1ec <array.3488+44>:      0x0000000d
0x804a1f0 <array.3488+48>:      0x00000003
0x804a1f4 <array.3488+52>:      0x00000009
0x804a1f8 <array.3488+56>:      0x00000006
0x804a1fc <array.3488+60>:      0x00000005

0x0->0x1->0x2->0xe->0x6->(0xf)->0x5->0xc->0x3->0x7->0xb->0xd->0x9->0x4->0x8->0x0

(gdb) x/xw $ebp-0x10
0xffffcde8:     0x00000002
(gdb) set \*0xffffcde8=115
(gdb) p/x $ecx
$3 = 0x73
(gdb) p/d $ecx
$4 = 115

炸弹实验 第六关

通关密码 “5 6 1 4 3 2 ”

第一步

判断输入相等,READ_SIX_NUMBERS读出的数保存在 -0x30(%ebp)开头的地址中

 8048cac:	8b 04 b7             	mov    (%edi,%esi,4),%eax
 8048caf:	83 e8 01             	sub    $0x1,%eax
 8048cb2:	83 f8 05             	cmp    $0x5,%eax
 8048cb5:	76 05                	jbe    8048cbc <phase_6+0x33>
 8048cb7:	e8 15 04 00 00       	call   80490d1 <explode_bomb>
 8048cbc:	83 c6 01             	add    $0x1,%esi
 8048cbf:	83 fe 06             	cmp    $0x6,%esi
 8048cc2:	74 22                	je     8048ce6 <phase_6+0x5d>
 8048cc4:	8d 1c b7             	lea    (%edi,%esi,4),%ebx
 8048cc7:	89 75 b4             	mov    %esi,-0x4c(%ebp)
 8048cca:	8b 44 b7 fc          	mov    -0x4(%edi,%esi,4),%eax
 8048cce:	3b 03                	cmp    (%ebx),%eax
 8048cd0:	75 05                	jne    8048cd7 <phase_6+0x4e>
 8048cd2:	e8 fa 03 00 00       	call   80490d1 <explode_bomb>
 8048cd7:	83 45 b4 01          	addl   $0x1,-0x4c(%ebp)
 8048cdb:	83 c3 04             	add    $0x4,%ebx
 8048cde:	83 7d b4 05          	cmpl   $0x5,-0x4c(%ebp)
 8048ce2:	7e e6                	jle    8048cca <phase_6+0x41>
 8048ce4:	eb c6                	jmp    8048cac <phase_6+0x23>

第二步

把输入数节点按顺序相连

    8048ce6:	bb 00 00 00 00       	mov    $0x0,%ebx
    8048ceb:	8d 7d d0             	lea    -0x30(%ebp),%edi
    8048cee:	eb 16                	jmp    8048d06 <phase_6+0x7d>

--> 8048cf0:	8b 52 08             	mov    0x8(%edx),%edx

    8048cf3:	83 c0 01             	add    $0x1,%eax
    8048cf6:	39 c8                	cmp    %ecx,%eax
    8048cf8:	75 f6                	jne    8048cf0 <phase_6+0x67>

--> 8048cfa:	89 54 b5 b8          	mov    %edx,-0x48(%ebp,%esi,4)

    8048cfe:	83 c3 01             	add    $0x1,%ebx
    8048d01:	83 fb 06             	cmp    $0x6,%ebx
    8048d04:	74 16                	je     8048d1c <phase_6+0x93>
    8048d06:	89 de                	mov    %ebx,%esi
    8048d08:	8b 0c 9f             	mov    (%edi,%ebx,4),%ecx
    8048d0b:	ba c4 c0 04 08       	mov    $0x804c0c4,%edx
    8048d10:	b8 01 00 00 00       	mov    $0x1,%eax
    8048d15:	83 f9 01             	cmp    $0x1,%ecx

    8048d18:	7f d6                	jg     8048cf0 <phase_6+0x67>
    8048d1a:	eb de                	jmp    8048cfa <phase_6+0x71>

关键部分 ---- 链表节点的保存

由第二步中展现出了链表的地址$0x804c0c4

0x804c084:      0x00000000
0x804c088 <node6>:      0x00000255
0x804c08c <node6+4>:    0x00000006
0x804c090 <node6+8>:    0x00000000
0x804c094 <node5>:      0x000003bd
0x804c098 <node5+4>:    0x00000005
0x804c09c <node5+8>:    0x0804c088
0x804c0a0 <node4>:      0x00000187
0x804c0a4 <node4+4>:    0x00000004
0x804c0a8 <node4+8>:    0x0804c094
0x804c0ac <node3>:      0x00000155
0x804c0b0 <node3+4>:    0x00000003
0x804c0b4 <node3+8>:    0x0804c0a0
0x804c0b8 <node2>:      0x0000006c
0x804c0bc <node2+4>:    0x00000002
0x804c0c0 <node2+8>:    0x0804c0ac
0x804c0c4 <node1>:      0x000001a7
0x804c0c8 <node1+4>:    0x00000001
0x804c0cc <node1+8>:    0x0804c0b8

第三步

把六个数字对应的链表节点相连

8048d1c:	8b 5d b8             	mov    -0x48(%ebp),%ebx
8048d1f:	8b 45 bc             	mov    -0x44(%ebp),%eax
8048d22:	89 43 08             	mov    %eax,0x8(%ebx)
8048d25:	8b 55 c0             	mov    -0x40(%ebp),%edx
8048d28:	89 50 08             	mov    %edx,0x8(%eax)
8048d2b:	8b 45 c4             	mov    -0x3c(%ebp),%eax
8048d2e:	89 42 08             	mov    %eax,0x8(%edx)
8048d31:	8b 55 c8             	mov    -0x38(%ebp),%edx
8048d34:	89 50 08             	mov    %edx,0x8(%eax)
8048d37:	8b 45 cc             	mov    -0x34(%ebp),%eax
8048d3a:	89 42 08             	mov    %eax,0x8(%edx)
8048d3d:	c7 40 08 00 00 00 00 	movl   $0x0,0x8(%eax)
8048d44:	be 00 00 00 00       	mov    $0x0,%esi

通关条件

8048d44:	be 00 00 00 00       	mov    $0x0,%esi
8048d49:	8b 43 08             	mov    0x8(%ebx),%eax
8048d4c:	8b 13                	mov    (%ebx),%edx
8048d4e:	3b 10                	cmp    (%eax),%edx
8048d50:	7d 05                	jge    8048d57 <phase_6+0xce>
8048d52:	e8 7a 03 00 00       	call   80490d1 <explode_bomb>
8048d57:	8b 5b 08             	mov    0x8(%ebx),%ebx
8048d5a:	83 c6 01             	add    $0x1,%esi
8048d5d:	83 fe 05             	cmp    $0x5,%esi
8048d60:	75 e7                	jne    8048d49 <phase_6+0xc0>

可见
$eax保存的是0x8($ebx),即下一个额节点的地址
$edx保存的是($edx),即是当前节点的值
cmp (%eax),%edx 比较两个数,后面的值较大时跳过爆炸
即---链表后面的节点都比前面的节点数值小

5 > 6 > 1 > 4 > 3 > 2

从Alto的感受到游戏创新的思考

本文仅叙述个人观点。


Alto’s Adventure

早有看到过Alto’s Adventure这款游戏,但并没有玩过,今天看到play商店的推荐,瞄了一眼视频觉得画风精致操作简洁,于是来尝尝味道如何。

套用百度的描述:Alto’s Adventure《阿尔托的冒险》(话说原来中文名是这个啊,于是在国内的应用商店也找到了。毕竟是单机游戏,不像<agar.io>,下文有提及)是游戏开发商 Snowman 最新推出的一款滑雪跑酷游戏,游戏中,玩家将扮演 Alto 置身于唯美的雪地场景中飞奔。不管是闪电划破泛着浅紫色的夜空,还是一群小鹿从皑皑白雪的山顶上奔跑而过,每一个场景都是制作精良,文艺味十足。

官方预告视频:

体验时间:

vell good! 如官方截图一致的唯美画风、有趣的玩法,让我比较欣喜,深感国内游戏(特别是手游)的同质化以及山寨模式严重,见下下下文。

玩法方面虽然不算新颖,属于神庙大逃亡一类的跑酷游戏,但有异于神庙的操作模式,具体游戏玩法并不详尽介绍,更多>>>click<<<

游戏的画风:perfect

扁平风的清淡口味

 

抽象表达的效果

日月山川丛林冰川小屋(小屋被我吃了)

 

以上的以上都不是真正吸引我的地方

弹幕:张sir你个骗子,你现在跟我说这些

MrZ:orz……

真正令我迷醉的:轻柔舒缓的背景音乐

悦耳动听的背景音乐也与游戏搭配得天衣无缝,由于音乐只会在滑雪的过程中播放,一旦滑雪中断即戛然而止,相信我,在游戏初期,你一定会为了追寻这个洗涤心灵的听觉感受,不断玩下去的……(from:少数派

真的我就是为了这洗涤心灵般的音乐玩了禅模式一个小时,逼真动听的雷雨声,唤醒了我逢雨天看雨的记忆,有一种说不出的美妙酝酿着,雨点飘洒脸庞,宁静。


关于Alto’s Adventure剩下的内容就留给你自己去体验,下面才是我想说的。

WHAT?WHY?——游戏之创新

国内的游戏行业存在明显的现象:

A、创新程度低

B、同质化及山寨情况严重

也许是当局者迷旁观者清,又或者是内行看门道外行看热闹,又又可能是GFW引起的资本保护,甚至是社会性质的差异所致。

如此深奥的问题,就让那些经济学者去下定论吧。

我仅在于表达自己对国内的游戏(不止于游戏)的观点:


利益→市场→竞争→资本

Point 1)产品成为资本快餐的牺牲品,运营者为了尽快回笼资本榨干游戏的价值.eg.[PC]Planetside2(MMOFPS),DNF(RPG),LOL,CSOL(FPS)诸如此类的各种页游.[PHONE]天天**,各种.....
Point 2)如果说前者是好产品活不长的原因,那么这一个则是好产品产不出的根本->>>资本快餐是个竞争激烈的市场,三个卖快餐的商家只有一个买家当然看谁的快餐最快,没有商家再有耐心去熬老火靓汤..于是山寨成风

Point 3)以上两点对于有雄厚财力的资本企业来说,闭门造车也是能做出好产品的,但是,Point 4)但是,没有人愿意这样做,百度,阿里,网易,新浪,腾讯,甚至说山寨之风就是由这些巨头带起来的,有创新想法的只有小型的创业团队,他们在获得大量投资之前根本无法抵抗腾讯之流的强势

举例时间

以上文Alto’s Adventure为例,个人认为是做得算是完美的一款游戏,打分4.5/5.0,

1)游戏模式的单一本身不能为它吸引太多用户

2)收费方式使资本回笼太慢

3)山寨后容易被山寨产品超越(收益方面)

唯一的有利点是本身质量高,可是……

One more example

agar.io(Google年度搜索排行第七,总排行not游戏排行,---外媒报道

vs 某球大*战  (版权问题,请自行百度图片)


总结

仁者见仁智者见智~意见不同欢迎提出。

2016年9月25日 07:19

Wordpress博客上的第一篇文章。
2017/07/09 注

嵌入式系统的硬件

嵌入式微处理器

  嵌入式系统硬件层的核心是嵌入式微处理器,嵌入式微处理器与通用CPU最大的不同在于嵌入式微处理器大多工作在为特定用户群所专用设计的系统中,它将通用CPU许多由板卡完成的任务集成在芯片内部,从而有利于嵌入式系统在设计时趋于小型化,同时还具有很高的效率和可靠性。

  嵌入式微处理器的体系结构可以采用冯·诺依曼体系或哈佛体系结构;指令系统可以选用精简指令系统和复杂指令系统。RISC计算机在通道中只包含最有用的指令,确保数据通道快速执行每一条指令,从而提高了执行效率并使CPU硬件结构设计变得更为简单。

  嵌入式微处理器有各种不同的体系,即使在同一体系中也可能具有不同的时钟频率和数据总线宽度,或集成了不同的外设和接口。据不完全统计,目前全世界嵌入式微处理器已经超过1000多种,体系结构有30多个系列,其中主流的体系有ARM、MIPS、PowerPC、X86和SH等。但与全球PC市场不同的是,没有一种嵌入式微处理器可以主导市场,仅以32位的产品而言,就有100种以上的嵌入式微处理器。嵌入式微处理器的选择是根据具体的应用而决定的。

存储器

  嵌入式系统需要存储器来存放和执行代码。嵌入式系统的存储器包含Cache、主存和辅助存储器。

Cache

  Cache是一种容量小、速度快的存储器阵列它位于主存和嵌入式微处理器内核之间,存放的是最近一段时间微处理器使用最多的程序代码和数据。在需要进行数据读取操作时,微处理器尽可能的从Cache中读取数据,而不是从主存中读取,这样就大大改善了系统的性能,提高了微处理器和主存之间的数据传输速率。Cache的主要目标就是:减小存储器(如主存和辅助存储器)给微处理器内核造成的存储器访问瓶颈,使处理速度更快,实时性更强。

  在嵌入式系统中Cache全部集成在嵌入式微处理器内,可分为数据Cache、指令Cache或混合Cache,Cache的大小依不同处理器而定。一般中高档的嵌入式微处理器才会把Cache集成进去。

主存

  主存是嵌入式微处理器能直接访问的寄存器,用来存放系统和用户的程序及数据。它可以位于微处理器的内部或外部,其容量为256KB~1GB,根据具体的应用而定,一般片内存储器容量小,速度快,片外存储器容量大。

  常用作主存的存储器有:
  ROM类 NOR Flash、EPROM和PROM等。
  RAM类 SRAM、DRAM和SDRAM等。

  其中NOR Flash 凭借其可擦写次数多、存储速度快、存储容量大、价格便宜等优点,在嵌入式领域内得到了广泛应用。

辅助存储器

  辅助存储器用来存放大数据量的程序代码或信息,它的容量大、但读取速度与主存相比就慢的很多,用来长期保存用户的信息。

  嵌入式系统中常用的外存有:硬盘、NAND Flash、CF卡、MMC和SD卡等。

通用设备接口和I/O接口

  嵌入式系统和外界交互需要一定形式的通用设备接口,如A/D、D/A、I/O等,外设通过和片外其他设备的或传感器的连接来实现微处理器的输入/输出功能。每个外设通常都只有单一的功能,它可以在芯片外也可以内置芯片中。外设的种类很多,可从一个简单的串行通信设备到非常复杂的802.11无线设备。

  目前嵌入式系统中常用的通用设备接口有A/D(模/数转换接口)、D/A(数/模转换接口),I/O接口有RS-232接口(串行通信接口)、Ethernet(以太网接口)、USB(通用串行总线接口)、音频接口、VGA视频输出接口、I2C(现场总线)、SPI(串行外围设备接口)和IrDA(红外线接口)等。

first blood : new blog again

新的历史

曾经用过wordpress、typecho框架搭建自己的博客,然而自己并非那种大批量的内容生产商。很多时候,更多的只是脑海里萌生出一小段想法,成就不了一篇博客,而作为一个讲究逻辑并且不在意页面效果的异类,需要的是能记录一段想法的东西,于是在此从typecho转用git page & issues !

SPI

SPI是串行外设接口(Serial Peripheral Interface)的缩写。SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线,节约了芯片的管脚,同时为PCB的布局上节省空间,提供方便,正是出于这种简单易用的特性,如今越来越多的芯片集成了这种通信协议,比如AT91RM9200。

SPI,UART,I2C都有什么区别,及其各自的特点

SPI:高速同步串行口。3~4线接口,收发独立、可同步进行

UART:通用异步串行口。按照标准波特率完成双向通讯,速度慢

I2C:一种串行传输方式,三线制,网上可找到其通信协议和用法的

更详细的区别

  • 第一个区别当然是名字

    SPI(Serial Peripheral Interface:串行外设接口);
    I2C(INTER IC BUS:意为IC之间总线)
    UART(Universal Asynchronous Receiver Transmitter:通用异步收发器)

  • 第二区别在电气信号线上

    SPI总线由三条信号线组成:串行时钟(SCLK)、串行数据输出(SDO)、串行数据输入(SDI)。SPI总线可以实现 多个SPI设备互相连接。提供SPI串行时钟的SPI设备为SPI主机或主设备(Master),其他设备为SPI从机或从设备(Slave)。主从设备间可以实现全双工通信,当有多个从设备时,还可以增加一条从设备选择线。

    如果用通用IO口模拟SPI总线,必须要有一个输出口(SDO),一个输入口(SDI),另一个口则视实现的设备类型而定,如果要实现主从设备,则需输入输出口,若只实现主设备,则需输出口即可,若只实现从设备,则只需输入口即可。

    I2C总线是双向、两线(SCL、SDA)、串行、多主控(multi-master)接口标准,具有总线仲裁机制,非常适合在器件之间进行近距离、非经常性的数据通信。在它的协议体系中,传输数据时都会带上目的设备的设备地址,因此可以实现设备组网。

    如果用通用IO口模拟I2C总线,并实现双向传输,则需一个输入输出口(SDA),另外还需一个输出口(SCL)。(注:I2C资料了解得比较少,这里的描述可能很不完备)

    UART总线是异步串口,因此一般比前两种同步串口的结构要复杂很多,一般由波特率产生器(产生的波特率等于传输波特率的16倍)、UART接收器、UART发送器组成,硬件上由两根线,一根用于发送,一根用于接收。

    显然,如果用通用IO口模拟UART总线,则需一个输入口,一个输出口。

  • 第三,从第二点明显可以看出,SPI和UART可以实现全双工,但I2C不行;

简记

规则:
php-fig(php标准规范)
git 规范
框架(统一接口):路由、数据库连接层+防注入、通用函数(session统一验证,结果统一返回)

Boom lab

整个实验当中收获最大的是对汇编语言结构的理解,包括 栈段,程序段,和常量区。

炸弹实验 phase-1

第一关密码:"We have to stand with our North Korean allies."

GDB 使用方法

print

p $eax
显示寄存器的内容

p/格式 变量

格式

t 显示为2进制数
o 显示为8进制数
d 显示为10进制数
u 显示为无符号10进制数
x 显示为16进制数
a 地址
c 显示为字符
s 显示为字符串
f 浮点小数
i 显示为机器语言(仅在显示内存的x命令中可用)

程序指针可以写为 $pc 或者 $eip ,因为Intel IA-32架构中的程序指针名为eip
p $pc
p $eip

examine

x 显示特定的内存位置内容

x/格式 地址

x 命令的格式 x/nyz

n 是要显示的字段数
y 是输出格式 同之前的 print 一样
z 是要显示的字段长度:
b 字节
h 半字(2字节)
w 字(4字节)默认值
g 双字(8字节)

例如:
x $pc
x/i $pc

此处x/i意为显示汇编指令
也有反汇编命令disassemble(或者disas)
格式:
disas
disas 程序计数器
disas 开始地址 结束地址1

炸弹实验 phase-2

第二关密码 “0 1 1 2 3 5 ”

read_six_nums

    (gdb) x/4xw $esp              
    0xffffcda0:     0x0804c430      0x0804a232      0xffffcde8      0xffffcdec                                                           
    0xffffcdb0:     0xffffcdf0      0xffffcdf4      0xffffcdf8      0xffffcdfc

phase_2

$ebp = 0xffffce08

(gdb) x/xw 0xffffcde8
0xffffcde8:     0x00000001    ebp-0x20
0xffffcdec:     0x00000002    ebp-0x1c
0xffffcdf0:     0x00000003    ebp-0x18
0xffffcdf4:     0x00000004    ebp-0x14
0xffffcdf8:     0x00000005    ebp-0x10
0xffffcdfc:     0x00000006    ebp-0xc

过程

(gdb) p $ebp-0x20
$8 = (void *) 0xffffcde8

(gdb) x/xw 0xffffcde8
0xffffcde8:     0x00000001

(gdb) set 0xffffcde8=0x0
Left operand of assignment is not an lvalue.

(gdb) set *0xffffcde8=0x0
(gdb) x/xw 0xffffcde8
0xffffcde8:     0x00000000

第一个数

读取完六个数之后返回 [phase_2] 发现
0x8048d84 <phase_2+26> cmpl $0x0,-0x20(%ebp)

这个正是输入的第一个数的值,取此值和0比较
于是强行修改此值**set *0xffffcde8=0x0**

成功通过测试

第二个数

接下来有
0x8048d8a <phase_2+32> cmpl $0x1,-0x1c(%ebp)
第二个数位为1

第三个数

0x8048d95 <phase_2+43>  lea    -0x18(%ebp),%ebx
0x8048d98 <phase_2+46>  lea    -0x8(%ebp),%esi
0x8048d9b <phase_2+49>  mov    -0x4(%ebx),%eax
0x8048d9e <phase_2+52>  add    -0x8(%ebx),%eax
0x8048da1 <phase_2+55>  cmp    %eax,(%ebx)
0x8048da3 <phase_2+57>  je     0x8048daa <phase_2+64>
0x8048da5 <phase_2+59>  call   0x80490d1 <explode_bomb>
0x8048daa <phase_2+64>  add    $0x4,%ebx
0x8048dad <phase_2+67>  cmp    %esi,%ebx
0x8048daf <phase_2+69>  jne    0x8048d9b <phase_2+49>
0xffffcdf0:     0x00000003    ebp-0x18  <-ebx

炸弹日志 phase_3

有多组答案:
第一组 ”1 -641 “

关键过程

读取输入数据后,第一个数据保存在$ebp-0xc,第二个数据保存在$ebp-0x10

接下来就有代码:
基于第一个输入的输给出的跳转偏移地址 jmp *0x804a1a0(,%eax,4)
查看偏移地址

(gdb) x/4xw 0x804a1a0-0x10
0x804a190:      0x00000000      0x00000000      0x00000000      0x00000000
(gdb) x/4xw 0x804a1a0
0x804a1a0:      0x08048f12      0x08048f19      0x08048f09      0x08048f02
0x804a1b0:      0x08048ef9      0x08048ef2      0x08048ee9      0x08048ee2
0x804a1c0 <array.3488>: 0x0000000a      0x00000002      0x0000000e      0x00000007
0x804a1d0 <array.3488+16>:      0x00000008      0x0000000c      0x0000000f      0x0000000b
0x804a1e0 <array.3488+32>:      0x00000000      0x00000004      0x00000001      0x0000000d

接下来,看看接下来的代码,显然这一段就是要跳转的地方,先跳过这段代码

 8048ee2:	b8 00 00 00 00       	mov    $0x0,%eax
 8048ee7:	eb 53                	jmp    8048f3c <phase_3+0x9b>
 8048ee9:	b8 00 00 00 00       	mov    $0x0,%eax
 8048eee:	66 90                	xchg   %ax,%ax
 8048ef0:	eb 45                	jmp    8048f37 <phase_3+0x96>
 8048ef2:	b8 00 00 00 00       	mov    $0x0,%eax
 8048ef7:	eb 39                	jmp    8048f32 <phase_3+0x91>
 8048ef9:	b8 00 00 00 00       	mov    $0x0,%eax
 8048efe:	66 90                	xchg   %ax,%ax
 8048f00:	eb 2b                	jmp    8048f2d <phase_3+0x8c>
 8048f02:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f07:	eb 1f                	jmp    8048f28 <phase_3+0x87>
 8048f09:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f0e:	66 90                	xchg   %ax,%ax
 8048f10:	eb 11                	jmp    8048f23 <phase_3+0x82>
 8048f12:	b8 14 03 00 00       	mov    $0x314,%eax
 8048f17:	eb 05                	jmp    8048f1e <phase_3+0x7d>
 8048f19:	b8 00 00 00 00       	mov    $0x0,%eax
 8048f1e:	2d 5a 03 00 00       	sub    $0x35a,%eax
 8048f23:	05 ef 02 00 00       	add    $0x2ef,%eax
 8048f28:	2d 16 02 00 00       	sub    $0x216,%eax
 8048f2d:	05 16 02 00 00       	add    $0x216,%eax
 8048f32:	2d 16 02 00 00       	sub    $0x216,%eax
 8048f37:	05 16 02 00 00       	add    $0x216,%eax
 8048f3c:	2d 16 02 00 00       	sub    $0x216,%eax

这段程序后面有两句
cmpl $0x5,-0xc(%ebp)
jg 8048f58 <phase_3+0xb7> <--boom
表明输入第一个数<=5

关键发现

到了程序段结尾,才发现有对$ebp-0x10的读取,即 第二个数
看到这里豁然开朗:因为第一个数的运算结果就保存在$eax

cmp    -0x10(%ebp),%eax
je     8048f5d <phase_3+0xbc>    <<---程序结束

那我就只要找到程序对$eax做了什么运算

解题

可见$eax = 1时,跳转0x08048f19地址最大,执行的代码最少,方便阅读
执行那段代码后运算结果位-641

试图强制设置内存值,发现 程序成功运行

(gdb) p $ebp-0x10
$1 = (void *) 0xffffcde8
(gdb) set *0xffffcde8 = -641
(gdb) x/xw 0xffffcde8
0xffffcde8:     0xfffffd7f
(gdb) x/dw 0xffffcde8
0xffffcde8:     -641
(gdb) ni
0x08048f56 in phase_3 ()
0x08048f5d in phase_3 ()

炸弹实验 第四关

理论上有多组密码
密码 "11 1 "

读取数据

8048e50:	e8 eb f9 ff ff       	call   8048840 <__isoc99_sscanf@plt>
8048e55:	83 f8 02             	cmp    $0x2,%eax
8048e58:	75 0c                	jne    8048e66 <phase_4+0x38>  <<---- boom

读出来的数据存在

(gdb) x/xw $ebp-0x10
0xffffcde8:     0x00000002
0xffffcdec:     0x00000001

对第一个数操作

8048e5a:	8b 45 f4             	mov    -0xc(%ebp),%eax
8048e5d:	85 c0                	test   %eax,%eax
8048e5f:	78 05                	js     8048e66 <phase_4+0x38>  <<--- boom
8048e61:	83 f8 0e             	cmp    $0xe,%eax
8048e64:	7e 05                	jle    8048e6b <phase_4+0x3d>  <<--- jmp over boom

接下来传进几个参数执行函数func

0xe	esp+0x8
0x0	esp+0x4
0x1	esp+0x0 <<---输入的第一个数

函数返回后

8048e86:	83 f8 01             	cmp    $0x1,%eax
8048e89:	75 06                	jne    8048e91 <phase_4+0x63>   <<--- boom
8048e8b:	83 7d f0 01          	cmpl   $0x1,-0x10(%ebp)
8048e8f:	74 0c                	je     8048e9d <phase_4+0x6f>   <<--- jmp over boom111
8048e91:	8d b4 26 00 00 00 00 	lea    0x0(%esi,%eiz,1),%esi
8048e98:	e8 34 02 00 00       	call   80490d1 <explode_bomb>
8048e9d:	c9                   	leave  

函数执行返回结果保存在 $eax 中,$eax == 0x1
并且 -0x10($ebp) == 0x1

fun4

void fun(int ebx,int eax,int edx)
{
    ecx = ebx - eax;
    ecx += (ecx < 0);
    ecx = ecx / 2 + eax;

    if( ecx > edx )
    {
        ecx--;
        fun(ecx,eax,edx);
        eax *= 2;
    }

    eax = 0;

    if( ecx < edx )
    {
        ecx++;
        fun(ebx,ecx,edx);
        eax = eax * 2 + 1;
    }

    return ;
}

炸弹实验 第五关

密码 “5 115 ”

过程

(gdb) x/xw $ebx
0x804a1c0 <array.3488>:         0x0000000a
0x804a1c4 <array.3488+4>:       0x00000002
0x804a1c8 <array.3488+8>:       0x0000000e
0x804a1cc <array.3488+12>:      0x00000007
0x804a1d0 <array.3488+16>:      0x00000008
0x804a1d4 <array.3488+20>:      0x0000000c
0x804a1d8 <array.3488+24>:      0x0000000f
0x804a1dc <array.3488+28>:      0x0000000b
0x804a1e0 <array.3488+32>:      0x00000000
0x804a1e4 <array.3488+36>:      0x00000004
0x804a1e8 <array.3488+40>:      0x00000001
0x804a1ec <array.3488+44>:      0x0000000d
0x804a1f0 <array.3488+48>:      0x00000003
0x804a1f4 <array.3488+52>:      0x00000009
0x804a1f8 <array.3488+56>:      0x00000006
0x804a1fc <array.3488+60>:      0x00000005

0x0->0x1->0x2->0xe->0x6->(0xf)->0x5->0xc->0x3->0x7->0xb->0xd->0x9->0x4->0x8->0x0

(gdb) x/xw $ebp-0x10
0xffffcde8:     0x00000002
(gdb) set \*0xffffcde8=115
(gdb) p/x $ecx
$3 = 0x73
(gdb) p/d $ecx
$4 = 115

炸弹实验 第六关

通关密码 “5 6 1 4 3 2 ”

第一步

判断输入相等,READ_SIX_NUMBERS读出的数保存在 -0x30(%ebp)开头的地址中

 8048cac:	8b 04 b7             	mov    (%edi,%esi,4),%eax
 8048caf:	83 e8 01             	sub    $0x1,%eax
 8048cb2:	83 f8 05             	cmp    $0x5,%eax
 8048cb5:	76 05                	jbe    8048cbc <phase_6+0x33>
 8048cb7:	e8 15 04 00 00       	call   80490d1 <explode_bomb>
 8048cbc:	83 c6 01             	add    $0x1,%esi
 8048cbf:	83 fe 06             	cmp    $0x6,%esi
 8048cc2:	74 22                	je     8048ce6 <phase_6+0x5d>
 8048cc4:	8d 1c b7             	lea    (%edi,%esi,4),%ebx
 8048cc7:	89 75 b4             	mov    %esi,-0x4c(%ebp)
 8048cca:	8b 44 b7 fc          	mov    -0x4(%edi,%esi,4),%eax
 8048cce:	3b 03                	cmp    (%ebx),%eax
 8048cd0:	75 05                	jne    8048cd7 <phase_6+0x4e>
 8048cd2:	e8 fa 03 00 00       	call   80490d1 <explode_bomb>
 8048cd7:	83 45 b4 01          	addl   $0x1,-0x4c(%ebp)
 8048cdb:	83 c3 04             	add    $0x4,%ebx
 8048cde:	83 7d b4 05          	cmpl   $0x5,-0x4c(%ebp)
 8048ce2:	7e e6                	jle    8048cca <phase_6+0x41>
 8048ce4:	eb c6                	jmp    8048cac <phase_6+0x23>

第二步

把输入数节点按顺序相连

    8048ce6:	bb 00 00 00 00       	mov    $0x0,%ebx
    8048ceb:	8d 7d d0             	lea    -0x30(%ebp),%edi
    8048cee:	eb 16                	jmp    8048d06 <phase_6+0x7d>

--> 8048cf0:	8b 52 08             	mov    0x8(%edx),%edx

    8048cf3:	83 c0 01             	add    $0x1,%eax
    8048cf6:	39 c8                	cmp    %ecx,%eax
    8048cf8:	75 f6                	jne    8048cf0 <phase_6+0x67>

--> 8048cfa:	89 54 b5 b8          	mov    %edx,-0x48(%ebp,%esi,4)

    8048cfe:	83 c3 01             	add    $0x1,%ebx
    8048d01:	83 fb 06             	cmp    $0x6,%ebx
    8048d04:	74 16                	je     8048d1c <phase_6+0x93>
    8048d06:	89 de                	mov    %ebx,%esi
    8048d08:	8b 0c 9f             	mov    (%edi,%ebx,4),%ecx
    8048d0b:	ba c4 c0 04 08       	mov    $0x804c0c4,%edx
    8048d10:	b8 01 00 00 00       	mov    $0x1,%eax
    8048d15:	83 f9 01             	cmp    $0x1,%ecx

    8048d18:	7f d6                	jg     8048cf0 <phase_6+0x67>
    8048d1a:	eb de                	jmp    8048cfa <phase_6+0x71>

关键部分 ---- 链表节点的保存

由第二步中展现出了链表的地址$0x804c0c4

0x804c084:      0x00000000
0x804c088 <node6>:      0x00000255
0x804c08c <node6+4>:    0x00000006
0x804c090 <node6+8>:    0x00000000
0x804c094 <node5>:      0x000003bd
0x804c098 <node5+4>:    0x00000005
0x804c09c <node5+8>:    0x0804c088
0x804c0a0 <node4>:      0x00000187
0x804c0a4 <node4+4>:    0x00000004
0x804c0a8 <node4+8>:    0x0804c094
0x804c0ac <node3>:      0x00000155
0x804c0b0 <node3+4>:    0x00000003
0x804c0b4 <node3+8>:    0x0804c0a0
0x804c0b8 <node2>:      0x0000006c
0x804c0bc <node2+4>:    0x00000002
0x804c0c0 <node2+8>:    0x0804c0ac
0x804c0c4 <node1>:      0x000001a7
0x804c0c8 <node1+4>:    0x00000001
0x804c0cc <node1+8>:    0x0804c0b8

第三步

把六个数字对应的链表节点相连

8048d1c:	8b 5d b8             	mov    -0x48(%ebp),%ebx
8048d1f:	8b 45 bc             	mov    -0x44(%ebp),%eax
8048d22:	89 43 08             	mov    %eax,0x8(%ebx)
8048d25:	8b 55 c0             	mov    -0x40(%ebp),%edx
8048d28:	89 50 08             	mov    %edx,0x8(%eax)
8048d2b:	8b 45 c4             	mov    -0x3c(%ebp),%eax
8048d2e:	89 42 08             	mov    %eax,0x8(%edx)
8048d31:	8b 55 c8             	mov    -0x38(%ebp),%edx
8048d34:	89 50 08             	mov    %edx,0x8(%eax)
8048d37:	8b 45 cc             	mov    -0x34(%ebp),%eax
8048d3a:	89 42 08             	mov    %eax,0x8(%edx)
8048d3d:	c7 40 08 00 00 00 00 	movl   $0x0,0x8(%eax)
8048d44:	be 00 00 00 00       	mov    $0x0,%esi

通关条件

8048d44:	be 00 00 00 00       	mov    $0x0,%esi
8048d49:	8b 43 08             	mov    0x8(%ebx),%eax
8048d4c:	8b 13                	mov    (%ebx),%edx
8048d4e:	3b 10                	cmp    (%eax),%edx
8048d50:	7d 05                	jge    8048d57 <phase_6+0xce>
8048d52:	e8 7a 03 00 00       	call   80490d1 <explode_bomb>
8048d57:	8b 5b 08             	mov    0x8(%ebx),%ebx
8048d5a:	83 c6 01             	add    $0x1,%esi
8048d5d:	83 fe 05             	cmp    $0x5,%esi
8048d60:	75 e7                	jne    8048d49 <phase_6+0xc0>

可见
$eax保存的是0x8($ebx),即下一个额节点的地址
$edx保存的是($edx),即是当前节点的值
cmp (%eax),%edx 比较两个数,后面的值较大时跳过爆炸
即---链表后面的节点都比前面的节点数值小

5 > 6 > 1 > 4 > 3 > 2

shadowsocks-config

install

yum update && yum install python-setuptools && easy_install pip && pip install shadowsocks

config

{
  "server":"0.0.0.0",
  "port_password":{
    "****":"****"
  },
  "timeout":300,
  "method":"aes-256-cfb",
  "fast_open":false,
  "workers":1
}

autostart

vi /etc/rc.local

ssserver -c /etc/shadowsocks.json -d start

what's more

google 拥挤算法 ‘tcp-bbr’

STC15F2K60S2

PSW:(D0H)程序状态字寄存器

AUXR:(8EH)辅助寄存器

BUSSPEED:(A1H)总线速率控制

P1.7/XTAL1

P1.6/XTAL2 外部晶振引脚

P5.4/RST 复位引脚

用io复用和预线程化技术完成web代理实验

A.建立接受请求的代理,分析HTTP,转发給服务器,并且返回结果给浏览器。将所有请求url记录在磁盘日志文件上,同时猪排过滤文件的url请求
B.实现多线程的生产者-消费者模式并行处理请求

datalab 【实验】

整个实验下来,虽然并不是全部都是独立思考的,不过也算是全部题目都细想过一遍。
整个实验结束之后给我的感觉就是 加深了对数值编码上的理解,也显漏出一些对编码理解上的问题,过后还需翻书仔细琢磨琢磨。

interger 类型的题目是比较有意思的,而且也值得仔细思考的。
整型的题目基本都限定了可以运用的操作符,而且基本上除了 + 两个逻辑运算外,其他允许的操作符都是位运算。因为曾经体验过位运算程序的美妙之处,所以在遇到困难时都会停下来仔细斟酌。

有一些题目是细节上的考察,而另外有三题需要特别指出的则是对 整型 形式上的理解以及 递归 运算的考察。

interger 4 bitcounts

计算有效位数:很巧妙的一点是递归的运用,我们都知道计算位数把每一位的值相加得到的最终结果就是位数。那么不用循环如何处理?
任意相邻的两位,将高位右移再与原来的数(高位清零)相加!
所得的新两位的值则是这两位的有效位数。
接下来,这个32位整数就变成了一个16格保存有效位数数值的形式。接着再在循环前一过程 :)

interger 5 bang

实现逻辑运算 :实际上是利用 x=0 -> -x=0。利用了 补码 的巧妙之处!
除了 0INT_MIN 以外其他任意一个数的负数 ~x+1 符号与原数相反。

interger 12 ilog2

求取 x 基于 2 的指数值:这道题是取网上的答案,同样巧妙于 递归 的应用。
由于下取整,因此只用考虑 最高有效位 的位置即可;
先取高16位计算,如果有效,则基值加上16,并且右移16位;
接着取8~16位计算,同理递归算出各自的基值相加。

各题题解过程

interger 1

/*
 * bitAnd - x&y using only ~ and |
 *   Example: bitAnd(6, 5) = 4
 *   Legal ops: ~ |
 *   Max ops: 8
 *   Rating: 1
 */
int bitAnd(int x, int y) {
  return ~(~x|~y); //x&y等于~(~x|~y)
}

interger 2

/*
 * getByte - Extract byte n from word x
 *   Bytes numbered from 0 (LSB) to 3 (MSB)
 *   Examples: getByte(0x12345678,1) = 0x56
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 6
 *   Rating: 2
 */
int getByte(int x, int n) {
  return (x>>(n<<3))&0xFF;	//求数据指定字节位置的值,高字节编号比低字节大,将对应字节编号乘以2^编号得到需要右移的位数,右移后和数字0xFF取与,将除了最低字节以外位置的位全部置0
}

interger 3

/*
 * logicalShift - shift x to the right by n, using a logical shift
 *   Can assume that 0 <= n <= 31
 *   Examples: logicalShift(0x87654321,4) = 0x08765432
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 20
 *   Rating: 3
 */
int logicalShift(int x, int n) {
	int z = ~(0x1 << 31);
	z = z >> n;
	z = (z << 1)|0x1;
	x = x >> n;
	x = x & z;
  	return x;
  	/*对数据进行逻辑移位,要在空出的位上补0。借用二进制数z=0x7fffffff,最高位为0,其余位均为1。对z执行算术右移n位的操作后,将得到n+1个0,要求移动n+1位,则再执行一次算术左移,
	  此时z的最低位变为0,再将z和1相与,得到高n位均为0的一个数字。
	  对x执行算术右移n位的操作,再和z相与,将高n位全部置0即可。
	  */
}

interger 4

/*
 * bitCount - returns count of number of 1's in word
 *   Examples: bitCount(5) = 2, bitCount(7) = 3
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 40
 *   Rating: 4
 */
int bitCount(int x) {
	int num1,num2,num3,num4,num5;
	int temp = 0x55|(0x55<<8);
	num1 = temp|(temp<<16);
	temp = 0x33|(0x33<<8);
	num2 = temp|(temp<<16);
	temp = 0x0f|(0x0f<<8);
	num3 = temp|(temp<<16);
	num4 = 0xff|(0xff<<16);
	num5 = 0xff|(0xff<<8);
	x = (x &num1) + ((x >>1) &num1);
    x = (x &num2) + ((x >>2) &num2);
    x = (x &num3) + ((x >>4) &num3);
    x = (x &num4) + ((x >>8) &num4);
    x = (x &num5) + ((x >>16) &num5);
    return x;
}

interger 5

/*
 * bang - Compute !x without using !
 *   Examples: bang(3) = 0, bang(0) = 1
 *   Legal ops: ~ & ^ | + << >>
 *   Max ops: 12
 *   Rating: 4
 */
int bang(int x) {
	int y = (~(((~x+1)|x)>>31))&0x1;
  	return y;
  	/*对于32位整型,除了0这一特殊情况外,每个数字的补码和它本身的和都是2^32,且除0以外,每个数的补码和它本身的最高位都不可能同时为0。所以将x本身和它的补码取或
	  并右移31位时,只有当x本身等于0这种情况才会得到全0的答案。
	  */
}

interger 6

/*
 * tmin - return minimum two's complement integer
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 4
 *   Rating: 1
 */
int tmin(void) {
	int x = 0x1 << 31;
  	return x;
  	//整型的最小数是-2^31。
}

interger 7

/*
 * fitsBits - return 1 if x can be represented as an
 *  n-bit, two's complement integer.
 *   1 <= n <= 32
 *   Examples: fitsBits(5,3) = 0, fitsBits(-4,3) = 1
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 */
int fitsBits(int x, int n) {
	int shift = ~n+33;
	int flag = !(x^((x<<shift)>>shift));
	return flag;
}

interger 8

/*
 * divpwr2 - Compute x/(2^n), for 0 <= n <= 30
 *  Round toward zero
 *   Examples: divpwr2(15,1) = 7, divpwr2(-33,4) = -2
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 15
 *   Rating: 2
 */
int divpwr2(int x, int n) {
	int y = 0x1 << n;
	int s = x >> 31;
    return (x+(s&(y+(~0)))) >> n;
    /*如果x为正数,则x/2^n应该等于x算术右移n位,如果x为负数,则x/2^n应该等于x+1算术右移n位(以补码形式表示和移位),x>>31记录下x的符号位,y+(~0)的低n-1位为1,其余位均为0。
	 如果x为负数,则s=1,x+1再右移,如果x为正数,则s=0,x直接右移。 */
}

interger 9

/*
 * negate - return -x
 *   Example: negate(1) = -1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 5
 *   Rating: 2
 */
int negate(int x) {
  	return ~x+1;	//取补码操作
}

interger 10

/*
 * isPositive - return 1 if x > 0, return 0 otherwise
 *   Example: isPositive(-1) = 0.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 8
 *   Rating: 3
 */
int isPositive(int x) {
	return 0x01 & ((~x+1)>>31);
	/*将x的最高位(符号位)移动31位到最低位,若为正数,最低位为0,返回值必须为1;若为负数,最低位为1,返回值必须为0。若x=0,考虑特殊情况,此时将返回0,
	加上一个|(!x)可以解决此问题。
	*/
}

interger 11

/*
 * isLessOrEqual - if x <= y  then return 1, else return 0
 *   Example: isLessOrEqual(4,5) = 1.
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 24
 *   Rating: 3
 */
int isLessOrEqual(int x, int y) {
	int sx = x >> 31;
	int sy = y >> 31;
	int se = (!(sx^sy))&((x+(~y))>>31);	//符号相同时x<=y的情况,因为不能使用减法,所以将x-y转化为x+(~y),原本x-y=x+y的补码(~y+1),不加1的原因是将等于0的情况也包含在里面了。
	int sne = sx&(!sy);	//符号不同时
  	return se|sne;
}

interger 12

/*
 * ilog2 - return floor(log base 2 of x), where x > 0
 *   Example: ilog2(16) = 4
 *   Legal ops: ! ~ & ^ | + << >>
 *   Max ops: 90
 *   Rating: 4
 */
int ilog2(int x) {
	int s,s1,s2,s3,s4,s5;
  	s = !!(x >> 16); //判断x的高16位是否全为0。
  	s1 = s << 4;
  	x = x >> s1; //如果全为0,将x右移16位继续。否则不右移(右移0位)。

  	s = !!(x >> 8); //判断x的高8位是否全为0。
  	s2 = s << 3;
  	x = x >> s2; //如果全为0,将x右移8位继续。否则不右移(右移0位)。

  	s = !!(x >> 4); //判断x的高4位是否全为0。
  	s3 = s << 2;
  	x = x >> s3; //如果全为0,将x右移4位继续。否则不右移(右移0位)。

  	s = !!(x >> 2); //判断x的高2位是否全为0。
  	s4 = s << 1;
  	x = x >> s4; //如果全为0,将x右移2位继续。否则不右移(右移0位)。

  	s = !!(x >> 1);
  	s5 = s; //最后一位。
  	return s1+s2+s3+s4+s5;
}

float 1

/*
 * float_neg - Return bit-level equivalent of expression -f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representations of
 *   single-precision floating point values.
 *   When argument is NaN, return argument.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 10
 *   Rating: 2
 */
unsigned float_neg(unsigned uf) {
	unsigned ret1 = uf ^ 0x80000000;	//修改uf的最高位
	unsigned ret2 = uf & 0x7fffffff;	//修改uf的符号位为0
	if(ret2 > 0x7f800000)	//IEEE 754中NaN的表示方法为阶码全为1,尾数不为0。
	{
		ret1 = uf;
	}
 	return ret1;
}

float 2

/*
 * float_i2f - Return bit-level equivalent of expression (float) x
 *   Result is returned as unsigned int, but
 *   it is to be interpreted as the bit-level representation of a
 *   single-precision floating point values.
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_i2f(int x) {
	unsigned sign,frac=0,flag,temp;
  	unsigned abs_x=x;
  	if(x == 0)
	{
		return 0;	//特殊情况,x=0。直接返回。
	}
  	if(x < 0)
	{	//x为负数的情况,x的绝对值abs_x为-x
     	sign=0x80000000;
     	abs_x=-x;
  	}
  	while(1)
	{	//对abs_x进行移位操作,直到找到第一个不为0的位作为尾数的起始位
     	temp=abs_x;
     	abs_x<<=1;
     	frac++;
     	if(temp&0x80000000)
     	{
     		break;	//当abs_x=0x8xxxxxxx(x表示可以为任意的合法值)时退出。
		}
  	}
  	if((abs_x & 0x01ff) > 0x0100) flag=1;
  	if((abs_x & 0x03ff) == 0x0300) flag=1;
  	//舍入

  	return sign+(abs_x>>9)+((159-frac)<<23)+flag;	//组合
}

float 3

/*
 * float_twice - Return bit-level equivalent of expression 2*f for
 *   floating point argument f.
 *   Both the argument and result are passed as unsigned int's, but
 *   they are to be interpreted as the bit-level representation of
 *   single-precision floating point values.
 *   When argument is NaN, return argument
 *   Legal ops: Any integer/unsigned operations incl. ||, &&. also if, while
 *   Max ops: 30
 *   Rating: 4
 */
unsigned float_twice(unsigned uf) {
	unsigned res = uf;
	if((res & 0x7F800000) == 0)	//非规格化数的情况
    {
            res = ((res & 0x007FFFFF)<<1) | (res & 0x80000000);
    }
    else if((res & 0x7F800000) != 0x7F800000)	//规格化数的情况
    {
            res = res+0x00800000;
    }
    return res;
}

Clean the Git Repository

from: Git 内部原理 - 维护及数据恢复

  • (garbage collect)
    git gc

  • count-objects
    git count-objects -v

  • find pack-idx
    find .git/refs -type f

  • check bigest file
    git verify-pack -v .git/objects/pack/pack-75331d2554390e87f74b962398a9d35e1282610d.idx | sort -k 3 -n | tail -10

  • show bigest filename
    git rev-list --objects --all | grep 7a9eb2fb
    or better
    git rev-list --objects --all | grep "$(git verify-pack -v .git/objects/pack/*.idx | sort -k 3 -n | tail -5 | awk '{print$1}')"

  • check file reflog
    git log --pretty=oneline --branches -- the-filename

IO 模式

原文: https://segmentfault.com/a/1190000003063859

对于一次IO访问(以read举例),数据会先被拷贝到操作系统内核的缓冲区中,然后才会从操作系统内核的缓冲区拷贝到应用程序的地址空间。所以说,当一个read操作发生时,它会经历两个阶段:

  1. 等待数据准备 (Waiting for the data to be ready)
  2. 将数据从内核拷贝到进程中 (Copying the data from the kernel to the process)

正式因为这两个阶段,linux系统产生了下面五种网络模式的方案。

  • 阻塞 I/O(blocking IO)
  • 非阻塞 I/O(nonblocking IO)
  • I/O 多路复用( IO multiplexing)
  • 信号驱动 I/O( signal driven IO)
  • 异步 I/O(asynchronous IO)

注:由于signal driven IO在实际中并不常用,所以我这只提及剩下的四种IO Model。

环境部署

又一次要装环境,干脆记一下自己的安装习惯。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.