GCC - everything starts here

xiaoxiao2021-03-06  125

GCC Rules

Can you imagine whether to compile free software with a private compiler with a closed source code? How do you know what the compiler has added in your executable? Various back doors and Trojans may be added. Ken Thompson is a famous hacker, who wrote a compiler, when the compiler compiles yourself, leave the back door and permanent Trojan in the 'login' program. Please read the description of this masterpiece here. Fortunately, we have GCC. When you use configure; make INSTALL, GCC has made a lot of heavy work behind the scenes. How can I get GCC work for us? We will start writing a card game, but we are just to demonstrate the function of the compiler, so we will streamline the code as much as possible. We will do step by step in step to understand the compilation process, understand what to do in order to make executive files, and do it in any order. We will look at how to compile the C program, and how to use the compilation option to make GCC work according to our requirements. Steps (and tools used) are as follows: Precommination (GCC -E), Compilation (GCC), Compilation (AS), and Connection (LD).

?

Start...

First, we should know how to call the compiler. In fact, this is simple. We will start from the famous first C program. (Please forgive me).

#include

int main ()

{

PRINTF ("Hello World!

");

}

Save this file as Game.c. You can compile it under the command line:

GCC Game.c

By default, the C compiler will generate a named

A.out's executable. You can type it as follows:

a.out

Hello World

New time when compiling programs

A.out will overwrite the original program. You can't know which program is created.

a.out. We can use it

-o compile option tells GCC what is the name of the executable file. We will call this program

Game, we can use any name because C does not have a naming limit like Java.

GCC -O Game Game.c

Game

Hello World

So far, we are far away from a useful program. If you feel frustrated, you can think about we have compiled and run a program. Because we will add features to this program, we must ensure that it can run. It seems that each of the programs who have just started learning programming, they see a 1000-row program, and then modify all errors. No one, I said no one, I can do this. You should first compile a small program that can run, modify it, and then let it run again. This can limit the number of errors you modified once. In addition, you know which modifications just do have made the program can't run, so you know where you should put your attention. This prevents such a situation: you think what you have written should work, it can also be compiled, but it is not running. Please remember that the program that can be compiled does not mean it is correct.

Next, write a header file for our game. The header file sets the data type and function declaration to one. This ensures consistency of data structural definitions so that every part of the program can treat everything in the same way.

#ifndef deck_h

#define deck_h

#define decksize 52

Typedef struct deck_t

{

Int card [decksize];

/ * Number of Cards Used * /

Int deal;

} DECK_T;

#ENDIF / * DECK_H * /

Save this file as deck.h. You can only compile .c files, so we must modify Game.c. On the 2nd line of Game.c, write the #include "deck.h". Deck_t deck on the 5th. In order to ensure that we didn't make mistakes, re-compiled it once. GCC -O Game Game.c

If there is no error, there is no problem. If compiled cannot pass, then modify it until it can be passed.

?

Precompiled

How does the compiler know what the dec kit is the type? Because it actually copied the "dec k" file to the "Game.c" file during the pre-compiled period. The pre-compiled instruction in the source code is prefixed as "#". You can call the precompiler by adding the -e option after GCC.

GCC -E -O Game_Precompile.txt game.c

Wc -l game_precompile.txt

3199 Game_Precompile.txt

Almost 3200 lines of output! Most of them come from

Stdio.h contains files, but if you view this file, our statement is there. If you don't have to use

-o Option Specifies the output file name, it outputs it to the console. The pre-compiled process has given a lot of flexibility by completing three main tasks.

Copy the "include" file to the source file to be compiled. Use the actual value to replace "define" text. Macro replacement in the call to the macro. This allows you to use symbol constants throughout the source file (ie use defksize to repay the number of cards in one payment), and the symbol constant is defined in one place. If its value changes, all use symbol constants Places can be automatically updated. In practice, you almost no need to use alone.

-E option, but let it transfer the output to the compiler.

?

Compile

As an intermediate step, GCC translates your code into assembly language. It must do this, it must figure out what you want to do by analyzing your code. If you make a grammatical error, it will tell you that compiled is failed. People sometimes misunderstand this step as the whole process. However, there are still many jobs to do GCC.

?

compilation

AS converts assembly language code into target code. In fact, the target code cannot be run on the CPU, but it is already close to the completion. The compiler option -c converts the .C file to the target file of .o as the extension. If we run

gcc -c game.c

We automatically created a file called Game.o. Here we have encountered an important issue. We can create a target file with any .c file. As we can see below, in the connection step we can combine these object files into executables. Let us continue to introduce our example. Because we are writing a card game, we have defined one pay card as

DECK_T, we will write a shuffle function. This function accepts a pointer to the DECK type and loads a random card into the DECK type. It uses 'DRAWN' array tracking records that those cards have been used. This array with Decksize elements can prevent us from repeating a card.

#include

#include

#include

#include "deck.h"

Static Time_t seed = 0;

Void shuffle (deck_t * pdeck)

{

/ * Keeps TRACK OF What NumBers Have Been Used * /

INT DRAWN [DECKSIZE] = {0};

INT I;

/ * One Time Initialization of Rand * /

IF (0 == SEED)

{

SEED = Time (NULL);

SRAND (SEED);

}

For (i = 0; i

INT value = -1;

DO

{

Value = rand ()% decksize;

}

While (Drawn [Value]! = 0);

/ * Mark Value As Used * /

Drawn [Value] = 1;

/ * Debug Statement * /

PRINTF ("% i

", value);

PDECK-> Card [i] = value;

}

PDECK-> DEALT = 0;

Return;

}

Save this file as shuffle.c. We added a debug statement in this code to run the generated grade. This doesn't add functions to our programs, but now I am a crucial moment, let's see what happened. Because our game is still in the primary stage, we don't have any other way to determine if our functions have realized our requirements. Using that printf statement, we can accurately know what happened now, so that we know that the card has been washed before starting the next phase. After we feel satisfied with its work, we can delete the line of statements from the code. This debugger technology looks rough, but it completes the debug task using the least statement. In the future, we will introduce more complex debuggers. Please pay attention to two problems.

We pass parameters in an addressing, you can see from '&' (take address) operators. This is passed to the function of the machine address, so the function can change the value of the variable. You can also use global variables to write programs, but you should use less global variables as little as possible. The pointer is an important part of C, and you should fully understand it. We use function calls in a new .c file. The operating system is always looking for functions called 'main' and starts there. There is no 'main' function in shuffle.c, so you cannot compile an independent executable. We must combine it with another program with the 'main' function and call 'shuffle'.

Run command

gcc -c shuffle.c

And determine that it has created a name

Shuffle.o new file. Edit the Game.c file, on line 7, variables in DECK_T type

After the declaration, add this line:

Shuffle (& deb);

Now, we will get an error if we are creating executables as before.

GCC -O Game Game.c

/ TMP/ccmihnjx.o: in function `main ':

/ TMP/ccmihnjx.o(.Text 0xF): undefined Reference to `shuffle '

Collect2: ld returned 1 exit status

Compile success, because our syntax is correct. But the connection step failed because we didn't tell the compiler 'shuffle' function. So what is the connection? How do we tell the compiler to find this function?

?

connection

Connector LD, use the following command, accept the target file created by AS and convert it to executable

GCC -O Game Game.o shuffle.o

This will combine two target files and create executables

Game.

The connector locates the shuffle function from the shuffle.o target file and includes enters the executable. The real benefit of the target file is that if we want to use that function again, what we have to do is to include "dec k" files and connect the shuffle.o target file to a new executable. The code reuse like this happens. Although we did not write a Printf function called in front as a debug statement, the connector can use #include from us.

The statement contains its declaration in the file, and connects the target code stored in the C library (/LIB/LIBC.SO.6). This approach allows us to use the functions of other people who have worked correctly, only care about the issues we have to solve. This is why the header file generally contains only data and function declarations without a function body. Typically, you can create a target file or a library for the connector to connect to the executable. Our code may have a problem, because we did not put any function declaration in the header file. In order to ensure that everything goes well, what can we do?

?

Other two important options

-Wall options You can open all types of syntax warnings to help us determine that the code is correct and make portability as much as possible. When we use this option to compile our code, we will see the following warning:

Game.c: 9: Warning: Implicit Declaration of Function `shuffle '

This lets us know that there are still some jobs to do. We need to join a line of code in the header file to tell the compiler

Everything of the shuffle function makes it necessary to check. It sounds like a scil, but doing this can separate the definition of the function, so that we can use our functions anywhere, just contain new headers and connect it to our target file. Yes. Let's add this line to Deck.h.

Void shuffle (DECK_T * PDECK);

This will eliminate the warning information.

Another commonly used compiler option is an optimization option -O # (ie -o2). This is what level optimization you need to tell the compiler. The compiler has a set of skills to make your code run faster. For our apparatus, you may not pay attention to the difference, but for large programs, it can greatly improve the running speed. You will often touch it, so you should know what it means.

?

debugging

We all know that the code has been compiled and does not mean that it will work according to us. You can use the following command to verify that all numbers have been used.

Game | Sort - N | Less

And check if there is any omission. What should we do if there is a problem? How can we go deep into the underlying to find errors?

You can check your code using the debugger. Most releases provide a famous debugger: GDB. If those of the many command line options make you feel awkward, then you can use a good front-end tool with KDE.

Kdbg. There are also some other front-end tools, they are all similar. To start debug, you can choose File-> Executable and find yours

GAME program. When you press the F5 key or select Execution-> From the menu, you can see the output in another window. what happened? In that window, we can't see anything. Don't worry, KDBG has no problem. The problem is that we did not join any debugging information in the executable, so KDBG could not tell us what happened within. Compiler option

-g can add the necessary debug information to the target file. You must use this option to compile the destination file (extension .o), so the command is compiled:

gcc -g -c shuffle.c Game.c

gcc -g-game game.o shuffle.o

This puts the hook in executable, allowing GDB and KDBG to point out the operation. Debugging is a very important technology, it is worth speaking how to use how to use it. The debugger helps programmers is that it sets "breakpoints" in the source code. Now you can use the line of code to call the shuffle function to try to set the breakpoint. There will be a red small circle on the side of the line. Now when you press the F5 key, the program will stop executing there. Press F8 to jump into the shuffle function. Oh, we can see it now.

The code in shuffle.c! We can control the program step by step and see what happened. If you pause the cursor on a local variable, you will see the contents of the variable. Great. This is more than that

The printf statement is much better, is it?

?

summary

This paper generally introduces the method of compiling and debug C procedures. We discussed the steps of the compiler, and to make the compiler do these jobs should be passed on which options for GCC. We briefly describe the problem of connecting the shared function library, and finally introduces the debugger. I really need to pay a lot of efforts, but I hope this article will let you start correctly. You can find more information in GCC, AS, and LD Man and Info Page.

Write a code you can learn more. As an exercise, you can write a 21point game based on the card game of this article. At that time, you can learn how to use the debugger. It can be easier to use the KDBG using the GUI. If you only add a little bit every time, you can complete it soon. Remember, be sure to keep the program can always run!

To write a complete game, you need the following:

A card player's definition (ie, you can define DECK_T as Player_T). A function that gives a certain number of cards to the specified player. Remember to increase the number of "licensing" in cards, so that there are also those cards available. Also remember how many cards in the player. Some interactions with users and ask if the player has another card. A function that prints the card in player. Card is equal to value% 13 (number of 0 to 12), SUIT is equal to VALUE / 13 (the number of obtained 0 to 3). A function that determines the value in the player's hand. The Value of the ACE is zero and can be equal to 1 or 11. King's Value is 12 and can be equal to 10.

?

Site link

GCC GCC GNU Compiler Collection GDB GNU Debugger Kdbg Kde's GUI Debugger Award Winning Compiler Hack Ken Thompson's Great Compiler Hack

转载请注明原文地址:https://www.9cbs.com/read-126161.html

New Post(0)