Mon 21 May 02:03
Interesting read...
Sun 20 May 18:14 I'm gonna leave in some days for a lot of time and before that I wanted to do some experiments. I know that there is a protection againts recursive loops, but it isnt in normal loops, so I was gonna see how the cpu knows it is a recursive loop.
First I'm gonna start with a normal loop, inside a function, and I'm gonna check it normal and inline.
#include <iostream>

using namespace std;

unsigned int lv;

void normalLoop() {
	while ( true ) {
		cout << lv++ << endl;
	}
}

int main ( int argc, char const *argv[] ) {
	normalLoop();
	return 0;
}
With this code I get a relatively expected output (in intel) for the compiled binary:
(gdb) disas main
Dump of assembler code for function main:
   0x00000000000008e2 <+0>:	push   rbp
   0x00000000000008e3 <+1>:	mov    rbp,rsp
   0x00000000000008e6 <+4>:	sub    rsp,0x10
   0x00000000000008ea <+8>:	mov    DWORD PTR [rbp-0x4],edi
   0x00000000000008ed <+11>:	mov    QWORD PTR [rbp-0x10],rsi
   0x00000000000008f1 <+15>:	call   0x8aa <normalLoop()>
   0x00000000000008f6 <+20>:	mov    eax,0x0
   0x00000000000008fb <+25>:	leave  
   0x00000000000008fc <+26>:	ret    
End of assembler dump.
(gdb) disas 0x8aa
Dump of assembler code for function _Z10normalLoopv:
   0x00000000000008aa <+0>:	push   rbp
   0x00000000000008ab <+1>:	mov    rbp,rsp
   0x00000000000008ae <+4>:	mov    eax,DWORD PTR [rip+0x2008c0]        # 0x201174 
   0x00000000000008b4 <+10>:	lea    edx,[rax+0x1]
   0x00000000000008b7 <+13>:	mov    DWORD PTR [rip+0x2008b7],edx        # 0x201174 
   0x00000000000008bd <+19>:	mov    esi,eax
   0x00000000000008bf <+21>:	lea    rdi,[rip+0x20079a]        # 0x201060 <std::cout>
   0x00000000000008c6 <+28>:	call   0x770 <[email protected]>
   0x00000000000008cb <+33>:	mov    rdx,rax
   0x00000000000008ce <+36>:	mov    rax,QWORD PTR [rip+0x2006fb]        # 0x200fd0
   0x00000000000008d5 <+43>:	mov    rsi,rax
   0x00000000000008d8 <+46>:	mov    rdi,rdx
   0x00000000000008db <+49>:	call   0x760 <[email protected]>
   0x00000000000008e0 <+54>:	jmp    0x8ae <normalLoop()>
End of assembler dump.
See the line in 0x8aa+49? Demangled that is

std::ostream::operator<<(std::ostream& (*)(std::ostream&))

I guess that's part of cout, maybe turning the unsigned integer to a string?
Whatever, who cares. So first we move the value of the instruction pointer rip + 0x2008c0 = 0x201174 to the eax register, this pointer points to the address in memory of lv in our C++ code. Now it's value is 0 because we didn't even start running the program

0x201174 <lv>: 0x00000000

. eax is a 32 bit register, so it will loop from 0 to the max 32 bit unsigned integer since in binary when you add to the max value, it starts back from 0.
So after we get this value from the lv pointer (0x2008b7 away from the current position = 0x555555755174 running) we use another 32 bit register, edx, to add the value of rax and 0x1, (rax is storing 0x1 at this point somehow after 1 loop), I continue and then stop in the instruction before that, now lv storing 2, and rax storing 0x555555755060 a pointer to std::cout? But then I check the next instruction and rax magically stores 0x2 now, honestly I'm kinda confused how rax is getting this value, if you know the answer please tell me c at capuno.cat.
At lest we know now how we add 0x1 every time, we lea it to edx doing rax (somehow storing the value of lv) and 0x1.
Whatever, that is not our main goal, to know the mysteries of rax, the loop, is just a jmp, we don't even cmp nothing, in normalLoop()+54 we jump to normalLoop()+4, that is a while true, simple, let's try inline.
(gdb) disas main
Dump of assembler code for function main(int, char const**):
   0x00000000000008aa <+0>:	push   rbp
   0x00000000000008ab <+1>:	mov    rbp,rsp
   0x00000000000008ae <+4>:	sub    rsp,0x10
   0x00000000000008b2 <+8>:	mov    DWORD PTR [rbp-0x4],edi
   0x00000000000008b5 <+11>:	mov    QWORD PTR [rbp-0x10],rsi
   0x00000000000008b9 <+15>:	mov    eax,DWORD PTR [rip+0x2008b5]        # 0x201174 
   0x00000000000008bf <+21>:	lea    edx,[rax+0x1]
   0x00000000000008c2 <+24>:	mov    DWORD PTR [rip+0x2008ac],edx        # 0x201174 
   0x00000000000008c8 <+30>:	mov    esi,eax
   0x00000000000008ca <+32>:	lea    rdi,[rip+0x20078f]        # 0x201060 <std::cout>
   0x00000000000008d1 <+39>:	call   0x770 <[email protected]>
   0x00000000000008d6 <+44>:	mov    rdx,rax
   0x00000000000008d9 <+47>:	mov    rax,QWORD PTR [rip+0x2006f0]        # 0x200fd0
   0x00000000000008e0 <+54>:	mov    rsi,rax
   0x00000000000008e3 <+57>:	mov    rdi,rdx
   0x00000000000008e6 <+60>:	call   0x760 <[email protected]>
   0x00000000000008eb <+65>:	jmp    0x8b9 <main(int, char const**)+15>
End of assembler dump.
(I needed to add

inline void normalLoop() __attribute__((always_inline));

in order to work -_-) It gives the same jmp method, with the same rax magic in main+21. So no big changes in here, I need to clarify that this post is not educational, I'm literally doing this for the first time and I expect the recursive loop to be a lot different but I could be wrong.
Ok, now we can continue with the recursive loop, we know a while true just jmps to the start of the function, and we know a recursive will call itself until the cpu stops it for being too annoying. But let's see how different they are.
#include <iostream>

using namespace std;

unsigned int lv;

void recursiveLoop() {
	cout << lv++ << endl;
	recursiveLoop();
}

int main ( int argc, char const *argv[] ) {
	recursiveLoop();
	return 0;
}
Ok, holy fuck it didn't, there is no max recursive here, I got a segfault, no cpu protection or whatsoever, let's debug it.
(gdb) disas 0x8aa
Dump of assembler code for function recursiveLoop():
   0x00000000000008aa <+0>:	push   rbp
   0x00000000000008ab <+1>:	mov    rbp,rsp
   0x00000000000008ae <+4>:	mov    eax,DWORD PTR [rip+0x2008c0]        # 0x201174 <lv>
   0x00000000000008b4 <+10>:	lea    edx,[rax+0x1]
   0x00000000000008b7 <+13>:	mov    DWORD PTR [rip+0x2008b7],edx        # 0x201174 <lv>
   0x00000000000008bd <+19>:	mov    esi,eax
   0x00000000000008bf <+21>:	lea    rdi,[rip+0x20079a]        # 0x201060 <std::cout>
   0x00000000000008c6 <+28>:	call   0x770 <[email protected]>
   0x00000000000008cb <+33>:	mov    rdx,rax
   0x00000000000008ce <+36>:	mov    rax,QWORD PTR [rip+0x2006fb]        # 0x200fd0
   0x00000000000008d5 <+43>:	mov    rsi,rax
   0x00000000000008d8 <+46>:	mov    rdi,rdx
   0x00000000000008db <+49>:	call   0x760 <[email protected]>
   0x00000000000008e0 <+54>:	call   0x8aa <recursiveLoop()>
   0x00000000000008e5 <+59>:	nop
   0x00000000000008e6 <+60>:	pop    rbp
   0x00000000000008e7 <+61>:	ret    
End of assembler dump.
Just by looking at this I can guess what is going on, at the start of the function we push rbp to the stack, and since at the end we pop it again, I'm guessing it's saving the address of the caller+1, and then with ret we return to there, but since this is a infinite recursive loop, we never pop anything from the stack, meaning we are just pushing the next instruction address from when we call recursiveLoop() to the stack, and never poping it back, so we overflowed the buffer I'm guessing, let's see what rbp really stores.
It stores 0x7fffffffe7e0, that doesn't give a lot of info, but lets make it loop a couple of times and check the stack:
(gdb) info stack
#0  recursiveLoop () at recursive.cpp:7
#1  0x00005555555548e5 in recursiveLoop () at recursive.cpp:9
#2  0x00005555555548e5 in recursiveLoop () at recursive.cpp:9
#3  0x00005555555548e5 in recursiveLoop () at recursive.cpp:9
#4  0x00005555555548e5 in recursiveLoop () at recursive.cpp:9
#5  0x00005555555548e5 in recursiveLoop () at recursive.cpp:9
#6  0x00005555555548fc in main (argc=1, argv=0x7fffffffe8f8) at recursive.cpp:13
Yea, basically it does that, saves rip+1 when it was called 0x00005555555548fc from main, and multiple 0x00005555555548e5 from inside the recursive function, and it never clears since we never pop, now the real deal, can we inline a recursive function? Let's try it.
┌──╼ epsilon > capuno > ~/Code/experiments/loop
└╼ g++ recursive.cpp -g
recursive.cpp: In function ‘int main(int, const char**)’:
recursive.cpp:8:13: error: inlining failed in call to always_inline ‘void recursiveLoop()’:
                                                       function not considered for inlining
 inline void recursiveLoop() {
             ^~~~~~~~~~~~~
recursive.cpp:10:15: note: called from here
  recursiveLoop();
  ~~~~~~~~~~~~~^~
We can't with gcc it seems, and thinking about it, it's obvious why it doesn't work, we can't call ourselves in a inline function, well, we could jmp to the start of it, like we did with the while true loop, but that's not recursive.

At least we learned that recursive loops suck, now I remember one user crying in a forum because someone didn't give him a job because they didn't like recursiveness in their workflow.
Never employ a recursive faggot, lesson learned.
Sun 13 May 18:46 Eskerrik asko, lehendakari! Ikus dezagun Iñigok zuregandik ikasten badu.
Wed 9 May 15:01
nomoremarinara.com
Tue 8 May 10:02 I'm kinda pissed off that the only thing CDR's do is go with their phone to film some spaniard breaking things and saying things like "Noooo home nooo que faaas, paraa homee" and they are already considered a terrorist organization. I really want to help but that doesn't fucking help, if we want to attack them we need to fuck their wallets, their economics, the cupfags need to break shit like monkeys, and the civilized JxCatfags need to use our businesses to attack spanish businesses, then after we are in a good position the ERCfags can go film some spaniard with their phone.
The only cool thing the CDRs are doing now is pacific riots and be like ninjas in the night to put yellow ribbons.
Load more entries...