This is a creation in Article, where the information may have evolved or changed.
A. Preface
As a beginner of embedded software development practitioners, most of the work is implemented in C language. Using the C language to write code, we can usually predict the compilation/machine coding of the compile-generated general situation, on different chip architectures, has its corresponding ABI standard. In recent years, the Go language programming, although the same syntax and C language grammar have simpler features, are also compiled static language, but we have it in the basic type-function parameters of the way to understand very little. In addition, the function of the go language can have multiple return values, the underlying mechanism is how to implement, but also need analysis to explore.
This article will document the analysis of functions passed by the Golang official compiler generated executable file on the Arm/linux platform. The device used for the test is an Android phone with open source software such as bash, Git, Vim, and GDB installed (please refer to "Installation record. docx" in https://pan.baidu.com/s/1i5o6Lwh for installation procedures). And found in the c4droid of the GCC compiler can be executed in Android, so you can compile the Golang compiler on the phone, its version is 1.4.3. This version of the Golang compiler is chosen because the compilation of subsequent versions of the Golang compiler may depend on the existing Golang compiler, which results in a chicken-laying and egg-laying problem. After using Telnet login, you can see that it is now working correctly:
Two Gets the current stack pointer
We know that the function definition of the Go language is func, the return value can be null, or there are multiple return values, so we guess it is the stack to pass parameters and return values, of course, the fact is true, then the analysis function in the call moment, the function returns an instant, We need to get the stack pointer of the current function execution before the argument and return value are allocated on the stack space. But unlike the C language, the go language does not support inline assembly, so we need to use other methods.
This method is also relatively straightforward, using a compilation to implement, referring to some of the Golang Code Library assembly format, we created a Nonsafe package, provides a FETCHSP () function:
When this function is referenced, the assembly generated in the resulting executable file is:
As you can see, we store the stack pointer at the 4-byte offset of the stack pointer, which implies the method we know about the return value of the function, which we will further verify later. In addition, RET pseudo-instructions are compiled into Add pc, LR, #0, visible Golang 1.4. The 3 version of the arm assembler is still imperfect.
Three Parameter passing and return values for simple functions
With the stack pointer of the current function, we can directly view the data above the stack of the function before and after the call using the class printf function output in the FMT package. The corresponding code is:
Compile and execute directly to get the result:
Nonetheless, we are not sure that FETCHSP () returns the correct stack, which requires further viewing of the resulting executable, and the address of the instruction before calling FETCHSP ():
The highlight of the section is where we are interested. Using GDB debugging, let it stop before calling FETCHSP ():
In this way, we can determine that the FETCHSP function is correct in the Golang 1.4.3 version. By careful analysis of the results of execution, it can be concluded that:
When the function passes a parameter, it begins the argument at the current function stack pointer 4 byte offset, [sp + 0x4] is the first parameter of the function (0x7e0 =), [sp + 0x8] is the second parameter of the function (0x7d9 = 2009), and when the function returns, The return parameter is placed after the last parameter, i.e. [sp+ 0xc] (0x3ee = 2016 * 2009/(2016 + 2009) = 1006).
Four interface{} as a function parameter pass
Functions in the Go language also support multiple, indeterminate parameter passes, which are mentioned in the 5.2.2.2 section of programming in Go, with the following modified functions:
As you can see, the function classifier () except that the first parameter type is deterministic, the other parameters are of indeterminate type and number. In the C language, there are similar functions, such as printf (const char *, ...). such as But we know that functions such as printf (), the mutable parameters section is basically pushed into the stack, and there is no type information, its type is based on the format of the string to speculate. While the go language supports type detection, what is the mechanism for implementing it?
By parsing the resulting executable file, you can determine that four parameters are stacked or four values are stacked before calling the classifier () function:
In addition to the first pointer function, it can be said that only three values are passed for multiple parameters of interface{}. So we guessed that the three values are similar to a struct, containing all the variable parameter type information and its corresponding value. After testing, we use the following code to output it:
This piece of code is ugly, not because it's complicated, but because it uses a lot of "coercion type conversions." In the go language, pointers do not participate in mathematical operations, but they are converted to uintptr types and then converted to pointers and referenced by them. Let's take a look at the results of the execution:
As can be seen, the above solution constructs the function of the analytic variable parameter can obtain the variable parameter information, and the type detection obtains the parameter value very close, this explains the above parsing is correct. So what is the information structure of a mutable parameter list?
You can confirm that a mutable argument list is passed on the stack with three values, where the last two values are likely to be the same, expressed as the number of variable parameters (we passed 6 variable parameters in the example), and the first value points to a stack of space, which will have twice the data of the variable parameter, each of the two is a group, The first value is a pointer or an identity that determines the type of the parameter, the second value is a pointer to the parameter, and the same pointer points to the stack space, where the value of the parameter is stored. One of the exceptions is nil, and its type and pointer are all 0. To further confirm this, you can view the last parameter, float32 (2016), using MATLAB to verify that its hexadecimal representation is 0x44fc0000:
Five Summarize
Understanding the function-passing mechanism of the executable file compiled by the Golang language may not be helpful for learning the go language. In addition, the mechanism of these function arguments does not exist in the executable file generated by the GCCGO compilation. Nevertheless, it is still interesting to know some of the implementation details of the golang underlying, or to slightly satisfy our Golang's "ABI" inquiry.