digitalmars.D.learn - two mains
- Tyro[17] (41/41) Jan 26 2013 Trying to learn from the ground up and would appreciate some assistance
- Tyro[17] (5/23) Jan 26 2013 [1] This seems to be a problem with the disassembler @DPaste
- David Nadlinger (16/28) Jan 27 2013 Both functions could be replaced with
- Vladimir Panteleev (15/18) Jan 27 2013 The x64 calling convention passes the first few arguments via
- David Nadlinger (12/16) Jan 27 2013 This might not be directly relevant here, but in general, I'd
- Tyro[17] (3/18) Jan 27 2013 Thank you much. Things are starting to get a little clearer. Oh, thanks
Trying to learn from the ground up and would appreciate some assistance making sense of the following: // void main(){} [1] .text._Dmain segment assume CS:.text._Dmain _Dmain: push RBP mov RBP,RSP xor EAX,EAX pop RBP ret .text._Dmain ends .cto // void main(string[] args) {} [2] .text._Dmain segment assume CS:.text._Dmain _Dmain: push RBP mov RBP,RSP sub RSP,010h xor EAX,EAX leave ret .text._Dm Both segments of code deal with a minimal D program: the first taking no arguments and the second taking a string array. Information prior to the ".text_Dmain segment" in both files mirror each other with the exception of module name differences. The first difference that jumps out at me is that the ".text._Dmain segment" in [1] properly terminates with ".text._Dmain ends" like all other segments in the file up to this point. [2] is improperly: ".text._Dm". The second is the use of leave in [2]. If I understand correctly, leave is the exact same as: mov RBP,RSP pop RBP So why do we need to mov RBP, RSP in [2] but not in [1]? I'm thinking this is because RBP contains the address of args but not sure. Last is the .cto at the end of [1], what on earth is it and what is it used for? Why does it not exist in [2]? Thanks, Andrew
Jan 26 2013
On 1/26/13 3:42 PM, Tyro[17] wrote: [Snip]Both segments of code deal with a minimal D program: the first taking no arguments and the second taking a string array. Information prior to the ".text_Dmain segment" in both files mirror each other with the exception of module name differences. The first difference that jumps out at me is that the ".text._Dmain segment" in [1] properly terminates with ".text._Dmain ends" like all other segments in the file up to this point. [2] is improperly: ".text._Dm".[1] This seems to be a problem with the disassembler DPasteThe second is the use of leave in [2]. If I understand correctly, leave is the exact same as: mov RBP,RSP pop RBP So why do we need to mov RBP, RSP in [2] but not in [1]? I'm thinking this is because RBP contains the address of args but not sure.Still not clear on this choice.Last is the .cto at the end of [1], what on earth is it and what is it used for? Why does it not exist in [2]?See [1] above.Thanks, Andrew
Jan 26 2013
On Saturday, 26 January 2013 at 20:57:54 UTC, Tyro[17] wrote:On 1/26/13 3:42 PM, Tyro[17] wrote:Both functions could be replaced with --- _Dmain: xor EAX, EAX ret --- as they don't need to store anything on the stack at all. What you are seeing is just an odd result of the way the compiler generates the code internally, especially if you are compiling without optimizations on. For further information on what EBP/RBP is needed for, try searching for discussions about the (mis)use of GCC's omit-frame-pointer option, such as: http://stackoverflow.com/questions/579262/what-is-the-purpose-of-the-frame-pointer DavidThe second is the use of leave in [2]. If I understand correctly, leave is the exact same as: mov RBP,RSP pop RBP So why do we need to mov RBP, RSP in [2] but not in [1]? I'm thinking this is because RBP contains the address of args but not sure.Still not clear on this choice.
Jan 27 2013
On Saturday, 26 January 2013 at 20:42:27 UTC, Tyro[17] wrote:So why do we need to mov RBP, RSP in [2] but not in [1]? I'm thinking this is because RBP contains the address of args but not sure.The x64 calling convention passes the first few arguments via registers. I think it's most likely that the function prolog is allocating stack space to save the value of whatever registers (RDI/RDX?) which contain the string[] parameter, so that it could reuse those registers in the code of the function - but the assignment seems to have been optimized out, yet the stack allocation wasn't. FWIW, on Windows x64, DMD generates slightly different code, presumably because it's using the Microsoft x64 calling convention instead of the System V one. There is no stack allocation when compiled with -O, however without -O, DMD adds a "mov [RBP+10h], RCX" instruction. I assume it makes use of the 32-byte "shadow space" to "spill" ECX: http://en.wikipedia.org/wiki/X86_calling_conventions#x86-64_calling_conventions
Jan 27 2013
On Saturday, 26 January 2013 at 20:42:27 UTC, Tyro[17] wrote:Trying to learn from the ground up and would appreciate some assistance making sense of the following: // void main(){} [1] [...]This might not be directly relevant here, but in general, I'd steer clear of main() for such experiments. Due to its special nature (several possible signatures, but the calling code in druntime stays the same), there is quite a bit of extra magic going on internally. For example, you wouldn't normally find "xor EAX, EAX" in a void-returning functions, as its purpose is to set the return value to 0, which implicitly happens to make the void main() and void main(string[]) variants conform to the "full" int main(string[]) signature. David
Jan 27 2013
On 1/27/13 8:57 AM, David Nadlinger wrote:On Saturday, 26 January 2013 at 20:42:27 UTC, Tyro[17] wrote:Thank you much. Things are starting to get a little clearer. Oh, thanks Vlad.Trying to learn from the ground up and would appreciate some assistance making sense of the following: // void main(){} [1] [...]This might not be directly relevant here, but in general, I'd steer clear of main() for such experiments. Due to its special nature (several possible signatures, but the calling code in druntime stays the same), there is quite a bit of extra magic going on internally. For example, you wouldn't normally find "xor EAX, EAX" in a void-returning functions, as its purpose is to set the return value to 0, which implicitly happens to make the void main() and void main(string[]) variants conform to the "full" int main(string[]) signature. David
Jan 27 2013