Understanding internals of std::cout?

Started by
5 comments, last by owl 12 years, 10 months ago
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.
Advertisement
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.

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? :)
[size="2"]I like the Walrus best.
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?
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;
}

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.

[quote name='owl' timestamp='1307744025' post='4821886']
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.
[/quote]

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.
[size="2"]I like the Walrus best.

This topic is closed to new replies.

Advertisement