MINICRT 64-bit Linux system migration record: 64-bit GCC notes

Source: Internet
Author: User

Code download for 32-bit unmodified source and modified version:

git clone git@github.  com:youzhonghui/minicrt.git  

MINICRT 64-bit Linux system migration record

MINICRT is a small C runtime library written by Shiki, author of "Programmer Self-Accomplishment: link, reprinted in Library". It provides a more commonly used function implementation such as Printf,malloc,free,fopen.

The reason is to do this thing, because to write a linker, link standard library Time out of trouble, some symbols in the whole libc can not find the definition, standard library is too large, research source, the document is not convenient, rather take a small available minicrt come over, the source in hand, know everything.

But it is not smooth sailing, I now use the system is 64-bit archlinux, Shiki when writing a book or 32-bit system. Handling to the 64-bit system also encountered write trouble, but compared to 64 is the trend, not the den in 32, in the previous experience of the sheltered study it. So pounded totem a day, modified the source code, transplanted him to 64-bit Linux system, the process also learned some interesting things. The following is a procedure record.

Under the source code, according to the Readme.txt compiled codes

# ld-static-e mini_crt_entry entry.o test.o minicrt.a-o test

But in the first sentence, ENTRY.C cannot compile. Error message:

error:unsupported instruction ' mov '

Open found wrong in a sentence inline assembly:

ASM ("Movl%%ebp,%0 \ n":"=r" (Ebp_reg)); 

I learned that the assembly is written in Windows, the compilation of the T-grammar is not familiar, Google, to find a good information:
Http://argcandargv.com/articles/84.c

The grammar of this assembly is correct, I also after several experiments suddenly found that the pointer unexpectedly is 64-bit. I realized that I was really on a 64-bit system (aren't you using it all the time –-). The error is obvious, MOVL and EBP are 32 bits, and%0 is Ebp_reg 64 bits.

Revision changed to

ASM (%%rbp,%0 \ n ":" =r "(Ebp_reg));  

Compiled by.
The following pile of warnings, or 64-bit pointers to blame.
converting int from all source files to the int return type of the Long,main function can be preserved, then compiled, and the warning disappears.
But run./test
Unexpected, no output.

Replace the test.c with a simpler file to debug

#include "minicrt.h"int main () {        printf ("Hello world\n");        0;}   

Single-step tracking found that the INT 0x80 4th interrupt is not good. No information was found on the Internet.
My friends and I are a little discouraged (if the 64-bit system does not support this number 4th interrupt, I also have an egg!) )
But in a force of unwilling power driven, and did several experiments, the code to separate out, into 32 bits, run, surprise found, output Hello world.
So the 64-bit system still supports this system call, why 32 bit can, and 64 bit not?

Guess:
This interrupt can only output a string of 4GB addresses, that is, supports ECX, but does not support RCX.
The test of validation is easy to do and is found to be true.

Readelf-s Test
A look at the global variables, static lightened addresses are within 0X400000–0X60FFFFF. The only thing that can cross the border is the local variables in the stack.

Then I have to copy the contents of the stack to the global variable before calling the number 4th interrupt, and then hand the global variable pointer to the number 4th interrupt, which solves the problem of crossing the boundary.

Modified the FPUTC and fputs functions:

StaticChar __fputc_tmp_val__ =0;Long FPUTC (Char c,file* stream) {__fputc_tmp_val__ = C;if (Fwrite (&__fputc_tmp_val__,1,1,stream)! =1) {return EOF;} else {return c;}} static char __fputs_tmp_array__[256] = {0}; static int __fputs_tmp_size__ = 256;long fputs (const char* str,file *stream) { long len = strlen (str); if (len >= __fputs_tmp_size__) return EOF; strcpy (__fputs_tmp_array__ , str); if (fwrite (__fputs_tmp_array__,1,len,stream)! = Len) { return EOF;} else {return len;}}         

Test, smooth output Hello World
Originally thought this is done, but in exchange for the original TES into t.c a try, and no output.

Halo, Single Step!
Found that the parameter was not passed correctly at all. See Disassembly:

Before printf calls

18printf ( "%d %s\n", Len, BUF); 00000000004014db:mov-0x10 (%RBP), %rdx00000000004014df:mov-0x18 (%RBP) , %rax00000000004014e3:mov %rax,%rsi00000000004014e6:mov $0X4015F6, %edi00000000004014eb:mov $0 x0,%eax00000000004014f< Span class= "number" >0:CALLQ 0x400e5b         

Enter printf

Printf:0000000000400e5b: push %RBP 0000000000400e5c:mov %rsp,%RBP 0000000000400e5f: sub $0xd0,%rsp0000000000400e66: mov%rsi,-0xa8 (%RBP) 0000000000400e6d:mov%rdx,-0xa0 (%RBP) 0000000000400e74:mov%rcx,-0x98 (%RBP) 0000000000400e7b: mov%r8,-0x90 (%RBP) 0000000000400e82:mov%r9,-0x88 (%RBP) 0000000000400e89:test%al,%al0000000000400e8b:je 0x400ead0000000000400e8d:movaps%xmm0,-0x80 (%RBP) 0000000000400e91:movaps%xmm1,-0x70 (%RBP) 0000000000400e95: Movaps%xmm2,-0x60 (%RBP) 0000000000400e99:movaps%xmm3,-0x50 (%RBP) 0000000000400e9d:movaps%xmm4,-0x40 (%RBP) 0000000000400ea1:movaps%xmm5,-0x30 (%RBP) 0000000000400ea5:movaps%xmm6,-0x20 (%RBP) 0000000000400ea9:movaps%xmm7,- 0x10 (%RBP) 0000000000400ead:mov%rdi,-0xc8 (%RBP)         

Before writing the operating system, also self-implemented printf, but. But, this is the sister Ah! Why does the parameter not pass through the stack!
Find information, while the heart silently will gcc scold 10 times.

Found a piece of information: http://blog.csdn.net/videosender/article/details/6425671

I picked out a more important paragraph from the inside:
"and GCC's calling convention is different from VC. The first 6 integer parameters are placed in RDI, RSI, RDX, RCX, R8, R9, and the first 8 floating-point parameters in XMM0 to XMM7. In addition to using more registers, unlike VCs, integers and floating-point registers are mixed and not reserved for useless parameters. As an example, the first argument is int, the second is double, the third char*, and the fourth double, and the number of arguments is placed in rdi,xmm0,rsi,xmm1. Additionally, no register area is reserved on the stack. More parameters, like VCs, are placed on the stack. 」

It was found through the experiment that the setting passed through the register was not able to be closed by __attribute__ ((regparm (0))).
This will only modify the code.
As you can see, to implement a register parameter version of the va_start,va_arg,va_end is troublesome, I do not want to modify too much code.
It was observed that under the-o0 optimization option (the default option for GCC), after entering printf, the rsi,rdx ... These registers are placed in a stack. As shown above, but the number of parameters actually passed in.
But it is strange that RDI should be the first parameter, but RDI does not appear before the RSI.
Don't forget, the first parameter of printf is to display the declaration, is a string, the last sentence of the assembly above, MOV%rdi,-0xc8 (%RBP) shows exactly that.
So the list of parameters we want starts with the RSI, which is copied to the -0xa8 (%RBP) position. check! This is where we're looking.
It is also important to note that floating-point parameters are placed in xmm0 to XMM7, as can be seen from the assembly above, RSI,RDX. Xmm0 ... are arranged in a fixed order. Before copying xmm0-xmm7, there is a sentence of test%al,%al, when you call printf, there is an incoming floating-point argument eax=1, otherwise 0. More than six integer parameters are pressed into the stack.
Well, as long as we don't pass in the floating-point parameter, we can find arg_list by 0xa8 offset. And Minicrt's printf does not support floating-point output, so let's trickery it.

Put printf by

*format,...) {        va_list (arglist);        Va_start (arglist,format);        return vfprintf (stdout,format,arglist);}  

Revision changed to

*format,...) {        char* arglist;         %%RBP,%0 ":return vfprintf (stdout,format,arglist);}   

OK, then enter the four command in Readme.txt, run test, do you see the output?

Source: Http://www.tuicool.com/articles/Zzqye2

MINICRT 64-bit Linux system migration record: 64-bit GCC notes

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.