i'm currently still trying to understand the internals of the following code being executed in c++

int main()
{
    std::cout << "Just now entering inside of main" << std::endl << std::endl;
        return 0;
}

Here is the assembly code i obtained from an assembly line debugger

012E1207   |.  A1 44302E01             MOV EAX,DWORD PTR DS:[<&MSVCP100.std::endl>]
012E120C   |.  8B15 70302E01           MOV EDX,DWORD PTR DS:[<&MSVCP100.std::cout>]               ;  MSVCP100.std::cout
012E1212   |.  50                      PUSH EAX
012E1213   |.  8BC8                    MOV ECX,EAX
012E1215   |.  51                      PUSH ECX                                                   ;  MSVCR100.__initenv
012E1216   |.  68 14322E01             PUSH Reversin.012E3214                                     ; /Arg2 = 012E3214 ASCII "Just now entering inside of main"
012E121B   |.  52                      PUSH EDX                                                   ; |Arg1 = 00000000
012E121C   |.  E8 1F070000             CALL Reversin.012E1940                                     ; \Reversin.00D11940
012E1221   |.  83C4 08                 ADD ESP,8
012E1224   |.  8BC8                    MOV ECX,EAX
012E1226   |.  FF15 4C302E01           CALL DWORD PTR DS:[<&MSVCP100.std::basic_ostream<char,std:>;  MSVCP100.std::basic_ostream<wchar_t,std::char_traits<wchar_t> >::operator<<
012E122C   |.  8BC8                    MOV ECX,EAX
012E122E   |.  FF15 4C302E01           CALL DWORD PTR DS:[<&MSVCP100.std::basic_ostream<char,std:>;  MSVCP100.std::basic_ostream<wchar_t,std::char_traits<wchar_t> >::operator<<
012E1234   |.  A1 44302E01             MOV EAX,DWORD PTR DS:[<&MSVCP100.std::endl>]
012E1239   |.  50                      PUSH EAX
012E123A   |.  51                      PUSH ECX                                                   ; /Arg3 = 711C3714

Here is the same code obtained using IDA....it's the same as above but the code below includes my comments on what the code is doing

.text:00401207                 mov     eax, ds:__imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z ; std::endl(std::basic_ostream<char,std::char_traits<char>> &)
.text:0040120C                 mov     edx, ds:__imp_?cout@std@@3V?$basic_ostream@DU?$char_traits@D@std@@@1@A ; std::basic_ostream<char,std::char_traits<char>> std::cout
.text:00401212                 push    eax             ; pushing std::endl function address on stack for use later?
.text:00401213                 mov     ecx, eax        ; move the address of std::endl function into ECX
.text:00401215                 push    ecx             ; Pushing std::cout function address on stack for use later?
.text:00401215                                         ; Parameter 2 - Address of starting location of hardcoded string
.text:00401216                 push    offset aJustNowEnterin ; "Just now entering inside of main"
.text:0040121B                 push    edx             ; Parameter 1 - Address of std::cout function
.text:0040121C                 call    std__operator___std__char_traits_char___ ; operator<<() function( not sure if this is right )
.text:00401221                 add     esp, 8          ; Clearing callee's function parameters of the stack( 8 bytes )
.text:00401224                 mov     ecx, eax        ; store return value of call std_operator_std_char_traits_char__ into eax( which happens to be std::cout )
.text:00401226                 call    ds:__imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z ; std::basic_ostream<char,std::char_traits<char>>::operator<<(std::basic_ostream<char,std::char_traits<char>> & (*)(std::basic_ostream<char,std::char_traits<char>> &)) ( i have no idea what this is )
.text:0040122C                 mov     ecx, eax        ; I dont think a return value since EAX didnt change...not sure tho need to check further
.text:0040122E                 call    ds:__imp_??6?$basic_ostream@DU?$char_traits@D@std@@@std@@QAEAAV01@P6AAAV01@AAV01@@Z@Z ; std::basic_ostream<char,std::char_traits<char>>::operator<<(std::basic_ostream<char,std::char_traits<char>> & (*)(std::basic_ostream<char,std::char_traits<char>> &)) ( i have no idea what this is )
.text:00401234                 mov     eax, ds:__imp_?endl@std@@YAAAV?$basic_ostream@DU?$char_traits@D@std@@@1@AAV21@@Z ; I dont think a return value since EAX didnt change...not sure tho need to check further
.text:00401239                 push    eax
.text:0040123A                 push    ecx

i've commented as much as u could. Im wondering if anyone could verify my comments and/or correct my mistakes.

so, you want help reversing something? Ha. That is a bunch of high level crap, it is easier to figure out C than C++ with all its constructors and classes...

Given that this is a disassembly from VC++ 2010 (as noted by the reference to MSVCP100.DLL), you would expect the disassembler to be using Intel syntax, meaning that MOV operations are dest, src rather than src, dest. Thus, some of your comments are probably backwards with regards to what values are being stored in which registers. Specifically, you reverse the order in at least two cases towards the bottom.

Keep in mind that std::cout is a an ostream object, not a function. thus, when it is pushed onto the stack, it is as an argument to the operator<< function, not as a function pointer.

Also, I think (though I may be mistaken) that stream manipulators such as std::endl are passed to the stream operators as arguments, to be invoked by the stream function as the need arises. This would explain why std::endl is pushed onto the stack twice at the beginning of the function call. You might want to rad up on how manipulators work for further details.

MOV EAX,DWORD PTR DS:[<&MSVCP100.std::endl>]               ; deref the std::endl function ptr from the DLL
MOV EDX,DWORD PTR DS:[<&MSVCP100.std::cout>]               ; deref the std::cout object from the DLL
PUSH EAX                                                   ; /Arg4 = function ptr to std::endl 
MOV ECX,EAX                                                ; copy the ptr to std::endl to ECX (not sure why it does this,
                                                           ; probably an artifact of the compilation process that should have
                                                           ; been optimized out
PUSH ECX                                                   ; /Arg3 = function ptr to std::endl
PUSH Reversin.012E3214                                     ; /Arg2 = ptr to the string object
PUSH EDX                                                   ; /Arg1 = ptr to the std::cout object 
CALL Reversin.012E1940                                     ; call utility function to push string onto stack, I think
ADD ESP,8                                                  ; clear utility function's stack
MOV ECX,EAX                                                ; save the return value to ECX - again, an artifact, I think
CALL DWORD PTR DS:[<&MSVCP100.std::basic_ostream<char,std:>; call operator<< function
MOV ECX,EAX                                                ; save the return value to ECX - again, an artifact, I think
CALL DWORD PTR DS:[<&MSVCP100.std::basic_ostream<char,std:>; call operator<< function for second time - for handling the endl's?
MOV EAX,DWORD PTR DS:[<&MSVCP100.std::endl>]
PUSH EAX
PUSH ECX

Edited 5 Years Ago by Schol-R-LEA: n/a

This article has been dead for over six months. Start a new discussion instead.