Hey, I’m back.

Previous: Phase_3

This time we will solve phase 4.

Different from before, we need to handle two functions in this phase.

This is the code of phase 4:

000000000040100c <phase_4>:
  40100c:	48 83 ec 18          	sub    $0x18,%rsp
  401010:	48 8d 4c 24 0c       	lea    0xc(%rsp),%rcx
  401015:	48 8d 54 24 08       	lea    0x8(%rsp),%rdx
  40101a:	be cf 25 40 00       	mov    $0x4025cf,%esi
  40101f:	b8 00 00 00 00       	mov    $0x0,%eax
  401024:	e8 c7 fb ff ff       	callq  400bf0 <__isoc99_sscanf@plt>
  401029:	83 f8 02             	cmp    $0x2,%eax
  40102c:	75 07                	jne    401035 <phase_4+0x29>
  40102e:	83 7c 24 08 0e       	cmpl   $0xe,0x8(%rsp)
  401033:	76 05                	jbe    40103a <phase_4+0x2e>
  401035:	e8 00 04 00 00       	callq  40143a <explode_bomb>
  40103a:	ba 0e 00 00 00       	mov    $0xe,%edx
  40103f:	be 00 00 00 00       	mov    $0x0,%esi
  401044:	8b 7c 24 08          	mov    0x8(%rsp),%edi
  401048:	e8 81 ff ff ff       	callq  400fce <func4>
  40104d:	85 c0                	test   %eax,%eax
  40104f:	75 07                	jne    401058 <phase_4+0x4c>
  401051:	83 7c 24 0c 00       	cmpl   $0x0,0xc(%rsp)
  401056:	74 05                	je     40105d <phase_4+0x51>
  401058:	e8 dd 03 00 00       	callq  40143a <explode_bomb>
  40105d:	48 83 c4 18          	add    $0x18,%rsp
  401061:	c3                   	retq   

We can find that it calls a special function “func4”.

func4:

0000000000400fce <func4>:
  400fce:	48 83 ec 08          	sub    $0x8,%rsp
  400fd2:	89 d0                	mov    %edx,%eax
  400fd4:	29 f0                	sub    %esi,%eax
  400fd6:	89 c1                	mov    %eax,%ecx
  400fd8:	c1 e9 1f             	shr    $0x1f,%ecx
  400fdb:	01 c8                	add    %ecx,%eax
  400fdd:	d1 f8                	sar    %eax
  400fdf:	8d 0c 30             	lea    (%rax,%rsi,1),%ecx
  400fe2:	39 f9                	cmp    %edi,%ecx
  400fe4:	7e 0c                	jle    400ff2 <func4+0x24>
  400fe6:	8d 51 ff             	lea    -0x1(%rcx),%edx
  400fe9:	e8 e0 ff ff ff       	callq  400fce <func4>
  400fee:	01 c0                	add    %eax,%eax
  400ff0:	eb 15                	jmp    401007 <func4+0x39>
  400ff2:	b8 00 00 00 00       	mov    $0x0,%eax
  400ff7:	39 f9                	cmp    %edi,%ecx
  400ff9:	7d 0c                	jge    401007 <func4+0x39>
  400ffb:	8d 71 01             	lea    0x1(%rcx),%esi
  400ffe:	e8 cb ff ff ff       	callq  400fce <func4>
  401003:	8d 44 00 01          	lea    0x1(%rax,%rax,1),%eax
  401007:	48 83 c4 08          	add    $0x8,%rsp
  40100b:	c3                   	retq   

Back to phase 4. At 40101a, we can find that an address was stored in esi and passed to Scanf. We print the content of the address 0x4025cf. It is “%d %d”. So we need to put two integer numbers first. And if we do not do this, it will explode.

The numbers we put into it will be saved in stacks. The first one is 0x8(%rsp) and it must be less or equal to 14, then the next one is 0xc(%rsp). We can also know that the addresses of these numbers are stored in %rcx and %rdx.

Then it will prepare to call func4. Before it wants to do that, it set %edx=15, %esi=0, and %edi = the first number we input. Then it calls func4. After that, when func4 returns to phase 4, test whether %eax(return value from fun4) is 0. Obviously, it must be 0. From 401051 to 401058, it also tests whether the 2nd we input is 0. And the answer is yes again.

OK, we know what phase 4 wants to do. It’s time to explore the operation of func4.

func4 does a lot about ax, di, si, dx, and cx, so we simplify it first.

// write fun4() in c style directly
int fun4(rdi,rsi,rdx)
{
    eax=edx;
    eax=eax-esi;
    ecx=eax;
    ecx>>31;
    eax=eax+ecx;
    eax>>1;
    ecx=rax+rsi;
....
}

Then we can substitute some of them and simplify it.

int fun4(rdi,rsi,rdx)
{
    //eax=edx;
    eax=edx-esi;
    ecx=edx-esi;
    ecx>>31;
    //eax=eax+ecx;
    //eax>>1;
    eax=(edx-esi+(edx-esi)>>31)>>1
    ecx=rax+rsi;
...
}

Then we talk about the structure of the rest part.

// In fact, we still write it into c style directly
    if(ecx<=edi)
    {
        goto 400ff2;
    }
    edx=rcx-1;
    fun4();
    eax>>1;
    goto 401007;//return;

400ff2:
    eax=0;
    if(ecx>=edi)
    {
        goto 401007;//return;
    }
    esi=1+rcx;
    fun4();
    eax=rax*2+1;
    return;

401007:
    return;

It seems like only three blocks of code. The first one goes until goto 401007, the second is from 400ff2 to 401007, and the last part is “return”;

Then we substitute the second into the first. After that, they come like these:

int fun4(rdi,rsi,rdx)
{
    eax=edx-esi;
    ecx=edx-esi;
    ecx>>31;
    eax=(edx-esi+(edx-esi)>>31)>>1
    ecx=rax+rsi;

    if(ecx<=edi)
    {
        goto 400ff2;
        eax=0;
        if(ecx>=edi)
        {
            goto 401007;//return;
        }
        esi=1+rcx;
        fun4();
        eax=rax*2+1;
        return;
    }
    else{
        edx=rcx-1;
        fun4();
        eax>>1;
        goto 401007;//return;
    }
    return;
}

We can figure out how the function runs now. It’s time to write it into the executable c function.

//di is x,si is y,dx is z,cx is num,ax is ret
int fun4(int x,int y,int z)
{
    int ret=z-y;
    int num=(z-y)>>31;
    ret=(z-y-(z-y)>>31)>>1;
    num=ret+y;
    if(num<=x)
    {
        ret=0;
        if(num==x)
            return ret;
        y=num+1;
        ret=fun4(x,y,z);
        ret=ret*2+1;
        return ret;
    }
    else
    {
        z=num-1;
        ret=fun4();
        ret>>=2;
        return ret;
    }
}

Ah ha, it looks too long. Simplify it again!

//di is x,si is y,dx is z,cx is num,ax is ret
int fun4(int x,int y,int z)
{
    int ret=z-y;
    int num=(z-y)>>31;
    ret=(ret-num)/2;
    num=ret+y;
    if(num<=x)
    {
        if(num==x)
            return 0;
        return (fun4(x,num+1,z)*2+1);
    }
    else
    {
        return fun4(x,y,num-1)*2;
    }
}

Then…

int fun4(int x,int y,int z)
{
    int num=(z-y)/2+y;//because (z-y)>>31 is 0, it is also equal to num=(y+z)/2,不会证明自己学数论
    if(num<=x)
    {
        if(num>=x)
            return 0;
        return (fun4(x,num+1,z)*2+1);
    }
    else
    {
        return fun4(x,y,num-1)*2;
    }
}

At the beginning, y is 0 and z is 14. We want this function returns 0 at the end. It is obvious that if x==(z-y)/2+y, it will return 0 within the first loop.

So one of the answers is 7 0;

Finished? We are not satisfied with it! There must be more solutions!

We can compare the outer if. The first block of “IF” will return 0 or something plus 1. The else block returns something multiple 2. We expect the function gives us a 0. So when num<=x, num must equal x, otherwise there will be at least 1 in the return value. Then we can find the “*2” in return value is meaningless because we want it 0.

这里英语不会说,英语太烂了,笑死,直接汉语吧。然后再回到第一个注释,我们可以简写成int num=(y+z)/2。这时啥?这是中间值阿。说白了就是一直在中间值查找,要是相等直接返回0,皆大欢喜。要是x比中间值大,直接寄,所以说我们上来肯定要小于等于7。要是x比中间值小,那就上一个中间值处以二再-1,所以他是这个规律:14,7,3,1,0。

这样就真的够了?错了。老外的教材很多时候可不是为了凑体而凑题,应该是一个完整的情景。我们仔细观察一下,当x比中间值小的时候,他是除以2一直走下去一直到0.这也算是一种二分查找,找到的是除以二然后往下取整的数。如果大于呢?给个15看看

这不就是二分查找吗哥哥。

然后他的返回值也很有意思,就是这个数字比中间值小,他就乘以2,比他大,那就加1.

所以是个没啥用的二分查找。

这次鸽的有点久,不过放假就快了,加油,Range!

In the end, let us try our answer!

We got that one! Cheers! 😀

The key of phase 1: Border relations with Canada have never been better.

The key of phase 2: 1 2 4 8 16 32

The key of phase 3: 0 207

The key of phase 4: 0 0, 1 0, 3 0, 7 0

//后记:发现这个题实际上手下留情了,没有pop和push这种需要保存的操作

Next: Phase_5

Views: 99

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.