Jump to content

  • Log In with Google      Sign In   
  • Create Account

Understanding internals of std::cout?


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
6 replies to this topic

#1 shoez   Members   -  Reputation: 104

Like
1Likes
Like

Posted 10 June 2011 - 01:04 PM

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.

Sponsor:

#2 frob   Moderators   -  Reputation: 22714

Like
1Likes
Like

Posted 10 June 2011 - 04:02 PM

That has nothing to do with cout specifically, that is a general disassembly of some function calls.


Why are you doing this?


Disassembled code is not generally meant for human consumption.

The disassembled outputs have already been heavily processed by the compiler. While the results often coincide into a direct correspondence with C++ code, other times they are confoundedly different.

In order to really understand it, you need to understand both what the assembly is doing, and why it is doing it.



If you want to learn assembly, there are many books on that. Like this one if you can't find a reputable dead-tree version.

AFTER you know enough about assembly to understand how it works, look to books like this one to help you understand the patterns the compiler uses so you can make sense of the resulting disassembly.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#3 owl   Banned   -  Reputation: 364

Like
0Likes
Like

Posted 10 June 2011 - 04:13 PM

That has nothing to do with cout specifically, that is a general disassembly of some function calls.

Why are you doing this?

Disassembled code is not generally meant for human consumption.


He was suggested to do so in a previous thread. I'd also be interested in knowing how does the standard library behaves "in action" when you call std::cout.

OP: One way you could trace it's functioning could be building an executable debug version of it. I'm guessing that doing that could be quite tricky, but if you manage to put your hands on the source and add a main entry point to it and run it in debug mode, you'd be able to follow the entire process (I suppose).

The question is, are you obsessive compulsive enough to do that? :)
I like the Walrus best.

#4 shoez   Members   -  Reputation: 104

Like
1Likes
Like

Posted 10 June 2011 - 04:27 PM

The reason i'm doing this is because i would like to eventually get into reversing malware. I know i'm nowhere near it now, but i'd figure the best place to start would be with my own code. Also i decided to post on this forum because it's the only other forum that gives me "intelligent" awnsers to my questions i have with c++ :)

MOV EAX,DWORD PTR DS:[<&MSVCP100.std::endl>]
MOV EDX,DWORD PTR DS:[<&MSVCP100.std::cout>]

1.) std::cout is an instantied global object correct?
2.) What is std::endl? is it an object? a function? what is it?

#5 rip-off   Moderators   -  Reputation: 8721

Like
1Likes
Like

Posted 10 June 2011 - 04:56 PM

1) Yes
2) std::endl is a function. The ostream class provides an overload of operator<< for unary functions taking an ostream and simply call the function on itself.

For example:
#include <iostream>

std::ostream &hello_world(std::ostream &out)
{
    return out << "Hello, World";
}

int main()
{
   std::cout << hello_world << endl;
}


#6 frob   Moderators   -  Reputation: 22714

Like
1Likes
Like

Posted 10 June 2011 - 10:34 PM

He was suggested to do so in a previous thread. I'd also be interested in knowing how does the standard library behaves "in action" when you call std::cout.


The source is readily available for most compilers.

For Visual Studio, open up the path C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src for the source to the standard libraries, including the asm code for various intrinsic functions like memcpy().

Looking at the source (which includes comments) is much easier than reverse engineering it (which does not include comments).

In many ways the source looks very similar to the language standard, which is also a recommended read if you intend to figure out the inner details of the language. The language standard is a prose description, the source is a direct implementation of that prose. Read together it makes a lot of sense.


The compiler uses rules for operator overloading to select the correct function at compile time. Generally there is an exactly matching function available.

For example, open up C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src\ostream and read all 32 different specializations of the ostream::operator<<(), which is partly what the OP was asking for. Real C++ source with somewhat descriptive comments. Just remember that it has been worked over many times to compile into fast executable code, not written as a tutorial for clarity.

The specialization for strings is part of the string library, found in C:\Program Files (x86)\Microsoft Visual Studio 10.0\VC\crt\src\string starting at line 489 and is 45 lines long. It's a short read, but again written for the sake of compiling to good code rather than learning.

Check out my book, Game Development with Unity, aimed at beginners who want to build fun games fast.

Also check out my personal website at bryanwagstaff.com, where I write about assorted stuff.


#7 owl   Banned   -  Reputation: 364

Like
0Likes
Like

Posted 10 June 2011 - 11:19 PM


He was suggested to do so in a previous thread. I'd also be interested in knowing how does the standard library behaves "in action" when you call std::cout.


The source is readily available for most compilers.


I've been browsing the code online, which comes with quite cool documentation attached on many of it's files. Still, being able to step it's execution would be a lot more clearer imo than trying to figure it out from the sources.
I like the Walrus best.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS