0

Background

Hello! New user. I am working on a personal computer science project that involves research on loop statements such as the for and while loops in C - these loops can apply to other programming and scripting languages but, to keep things simple I want to focus primarily on C.


Issue

I would like to know how developers of programming and scripting languages are able to create for and while loops for those same languages. How can I achieve this for experimentation purposes? Do I have to learn assembly? If so, can anyone provide me with guidance?

Apologies if my original question was too vague.

Cheers!

3
  • 1
    what do you mean by "recreate"? Please explain what is the problem you're trying to solve; maybe add some examples.
    – Igor Skochinsky
    Dec 2 '21 at 19:11
  • I thought I was clear. I guess not. I am not trying to do anything fancy. I just want to know how developers of programming and scripting languages were able to create for and while loops. I do not know how to do this. Given this is site is focused on reverse engineering, I assumed it would be appropriate to ask my question here. Do you have any suggestions on how I should edit my question? Dec 2 '21 at 20:34
  • @MichaelŠòdéké it really still isn't very clear. Are you asking about specific scripting languages and their implementation of for and while loops? If so, you'd have to give the language at least some reference to find a sample and an interpreter for said language. Are you asking conceptually how one would implement such a thing? In that case it's not reverse engineering at all. Please edit the details into your question and then vote to Reopen (link right under your question)
    – 0xC0000022L
    Dec 16 '21 at 9:38
0

basic construct in c,.... languages

for (index =start_value; index< end_value; (pre/post) inc/dec(index))
like 
for (i = 0; i< 10; i++) , ( i=10,i>0;i--) , (i=35; i> 25; --i) ,(i=35; i< 25; ++i)

the compiler takes this human readable code and converts it into assembly for the specific platform

for x86 this could look like

mov end_value to another register like mov edx,10 
mov index to a register like mov,ecx,0
body {
do anything but preserve  ecx,edx
}
inc/dec regsiter ecx
compare ecx with edx,
do an if < or > decision and either go back to doing the body or exit 

a real world example

int main (void) {
    register int a =4;
    for (register int i =3; i<10; i++){
        a = a + i*2;
    }
    return a;
}

compiled and disassembled using vs and windbg

:\>ls
loopy.cpp

:\>cl /Zi /W4 /analyze:autolog- /Od /EHsc /nologo -GS loopy.cpp  /link /release /subsystem:windows /entry:main /fixed
loopy.cpp

:\>ls
loopy.cpp  loopy.exe  loopy.obj  loopy.pdb  vc140.pdb

disassembly of compiled code

:\>cdb -c "uf loopy!main;q" loopy.exe | awk "/Reading/,/quit/"
0:000> cdb: Reading initial command 'uf loopy!main;q'
loopy!main:
00000000`00401000 55              push    rbp
00000000`00401001 8bec            mov     ebp,esp
00000000`00401003 83ec08          sub     esp,8
=====================
memory location instead of register  used
00000000`00401006 c745f804000000  mov     dword ptr [rbp-8],4 
00000000`0040100d c745fc03000000  mov     dword ptr [rbp-4],3
=====================
00000000`00401014 eb09            jmp     loopy!main+0x1f (00000000`0040101f)

loopy!main+0x16:
00000000`00401016 8b45fc          mov     eax,dword ptr [rbp-4]
increment ==================
00000000`00401019 83c001          add     eax,1
00000000`0040101c 8945fc          mov     dword ptr [rbp-4],eax

loopy!main+0x1f:
============ comparison and decision
00000000`0040101f 837dfc0a        cmp     dword ptr [rbp-4],0Ah
00000000`00401023 7d0e            jge     loopy!main+0x33 (00000000`00401033)
============== body
loopy!main+0x25:
00000000`00401025 8b4dfc          mov     ecx,dword ptr [rbp-4]
00000000`00401028 8b55f8          mov     edx,dword ptr [rbp-8]
00000000`0040102b 8d044a          lea     eax,[rdx+rcx*2]
00000000`0040102e 8945f8          mov     dword ptr [rbp-8],eax
00000000`00401031 ebe3            jmp     loopy!main+0x16 (00000000`00401016)
=========== body end goes back to re doing again 
================ exit
loopy!main+0x33:
00000000`00401033 8b45f8          mov     eax,dword ptr [rbp-8]
00000000`00401036 8be5            mov     esp,ebp
00000000`00401038 5d              pop     rbp
00000000`00401039 c3              ret
quit:

in laymans terms this assembly is now further converted to binary (base 2 ,or 0,1) and fed into a network of logic gates which use and , or , not , nand ,xor, xnor circuitry to do the actual work so simply a not gate might return false or true based on the input of index 0b101 versus 0b1000

if you need the basic electronics and logic gate circuitry you should look for electronics stack exchange

you can also check online logic simulators like this

enter image description here

1

I'll assume you're slightly familiar with machine code / assembly language. The high-level statement

while (x >= 0) {
    print(x);
    --x;
}
/* rest of code */

needs to be translated down to simple machine code instructions like add, compare, call, and -- specifically for the loop, jump and branch instructions. Every processor has a different instruction repertoire, but similar instructions tend to be present in most modern CPU architectures

Here is one possible translation of the while loop for the Intel x86 architecture (in 64-bit mode):

    jmp    loop_test
loop_body:
    mov rcx,rsi
    call print
    dec rsi
loop_test:
    test  rsi,rsi
    jns loop_body
; rest of code

The very first instruction is a jmp instruction that jumps past the loop body directly to loop_test. The reason for doing this has to do with efficiency, and is worth a separate question. Here, we'll content ourselves with knowing that the next instruction will be the one after the label loop_test.

The instructions between the labels loop_body and loop_test correspond to the body of the loop. The compiler has decided to put the high-level language variable x in the rsi register. Because calling the procedure print requires its parameter to be in the rcx register, the mov rcx,rsi copies the value of rsi into rcx. Then the procedure print is called. Finally the value in the rsi instruction is decremented by one.

Control then falls into the loop_test block. Here, the statement test rsi,rsi compares rsi with itself. As a side effect, it happens to set or clear the processor's S flag, which indicates whether the value in rsi was negative or not -- that is, whether the highest order bit 63 was set or not. On the x86 architecture, signed numbers are represented in two's complement, so negative numbers will have their high order bit set.

If the high order bit of rsi is not set, then the S flag will be cleared by the test instruction. The next instruction jns jumps back to loop_body if the S flag is not set (hence the jns - "jump if not signed" if you want). The jns instruction is a conditional jump; the jump is either taken back to loop_body or it falls through to the code following the loop.

For-loops are basically while-loops with extra chrome. With some exceptions, a for-loop

for (x = 0; x < 42; ++x) {
    /* loop body */
}

is transformed into

x = 0;
while (x < 42) {
    /* loop body */
    ++x;
}

and then the compiler will translate that into something similar to the while-loop above.

Not the answer you're looking for? Browse other questions tagged or ask your own question.