logo资料库

高级C/C++编译技术(英文原版).pdf

第1页 / 共326页
第2页 / 共326页
第3页 / 共326页
第4页 / 共326页
第5页 / 共326页
第6页 / 共326页
第7页 / 共326页
第8页 / 共326页
资料共326页,剩余部分请下载后查看
Advanced C and C++ Compiling
Contents at a Glance
Contents
About the Author
About the Technical Reviewers
Acknowledgment
Introduction
Chapter 1: Multitasking OS Basics
Useful Abstractions
Memory Hierarchy and Caching Strategy
Virtual Memory
Virtual Addressing
Process Memory Division Scheme
The Roles of Binaries, Compiler, Linker, and Loader
Summary
Chapter 2: Simple Program Lifetime Stages
Initial Assumptions
Code Writing
Concept illustration: Demo Project
Compiling
Introductory Definitions
Related Definitions
The Stages of Compiling
Preprocessing
Demo Project Preprocessing Example
Linguistic Analysis
Assembling
Demo Project Assembling Example
AT&T Assembly Format Example
Intel Assembly Format Example
Optimization
Code Emission
Demo Project Compiling Example
Object File Properties
Compilation Process Limitations
What Makes Section Combining so Complicated?
Linking
Linking Stages
Relocation
Resolving References
Demo Project Linking Example
Linker’s Viewpoint
Executable File Properties
Variety of Section Types
A Variety of Symbol Types
Chapter 3: Program Execution Stages
Importance of the Shell
Kernel Role
Loader Role
Loader-Specific View of a Binary File (Sections vs. Segments)
Program Loading Stage
Executing Program Entry Point
The Loader Finds the Entry Point
The Role of _start() Function
The Role of __libc_start_main() Function
Stack and Calling Conventions
Functions Calling Conventions
Chapter 4: The Impact of Reusing Concept
Static Libraries
Dynamic Libraries
Dynamic vs. Shared Libraries
Dynamic Linking in More Detail
Part 1: Building the Dynamic Library
Part 2: Playing by Trust While Building the Client Executable (Looking for the Symbols Only)
Part 3: Runtime Loading and Symbol Resolution
Peculiarities of Dynamic Linking on Windows
Special Binary File Types Related to Dynamic Linking in Windows
Dynamically Linked Library (.dll)
Import Library File (.lib)
Export File (.exp)
Unique Nature of Dynamic Library
Property 1: Dynamic Library Creation Requires the Complete Build Procedure
Property 2: The Dynamic Library Can Link In Other Libraries
Application Binary Interface (ABI)
Static vs. Dynamic Libraries Comparison Points
Differences in Import Selectiveness Criteria
Import Selectiveness Criteria for Static Libraries
Import Selectiveness Criteria for Dynamic Libraries
Whole Archive Import Scenario
Deployment Dilemma Scenarios
Choice 1: Linking with a Static Library
Choice 2: Linking with a Dynamic Library
Final Verdict
Useful Comparison Analogies
The Conclusion: The Impact of Binary Reuse Concept
Chapter 5: Working with Static Libraries
Creating Static Library
Creating Linux Static Library
Creating a Windows Static Library
Using the Static Library
Recommended Use Case Scenarios
Static Libraries Tips and Tricks
Potential for Losing the Symbol Visibility and Uniqueness
Counterindicated Use Case Scenarios
Specific Rules of Linking Static Libraries
Converting Static to Dynamic Library
Static Libraries Issues on 64-bit Linux
Resolving the Problem In Real Life Scenarios
Chapter 6: Designing Dynamic Libraries: Basics
Creating the Dynamic Library
Creating the Dynamic Library in Linux
About the -fPIC Compiler Flag
Question 1: What does - fPIC stand for?
Question 2: Is the use of the -fPIC compiler flag strictly required to build the dynamic library?
Question 3: Is the use of the -fPIC compiler flag strictly confined to the domain of dynamic libraries? Can it be used when...
Creating the Dynamic Library in Windows
Designing Dynamic Libraries
Designing the Binary Interface
C++ Issues
Issue #1: C++ Imposes More Complex Symbol Name Requirements
Issue #2: Static Initialization Order Fiasco
Problem Description
Avoiding the Problem
Issue #3: Templates
Designing the Application Binary Interface
Guideline #1: Implement the Dynamic Library ABI as a Set of C-style Functions
Guideline #2: Provide the Header File Carrying the Complete ABI Declaration
Guideline #3: Use Widely-Supported Standard C Keyword s
Guideline #4: Use a Class Factory Mechanism (C++) or Module (C)
Guideline #5: Export Only the Really Important Symbols
Guideline #6: Use Namespaces to Avoid Symbol Naming Collision
Controlling Dynamic Library Symbols’ Visibility
Exporting the Linux Dynamic Library Symbols
The Symbol Export Control at Build Time
The Other Methods
The Symbol Export Control Demo Example
The Default Symbols Visibility Case
The Controlled Symbols Visibility Case
Using the strip Utility
Exporting the Windows Dynamic Library Symbols
Using the __declspec(dllexport) Keyword
Using the Module-definition File (.def)
Linking Completion Requirements
--no-undefined Linker Flag
Dynamic Linking Modes
Statically Aware (Load-Time) Dynamic Linking
Runtime Dynamic Linking
Dynamic Linking Modes Comparison
Chapter 7: Locating the Libraries
Typical Library Use Case Scenarios
Development Use Case Scenario
End User Runtime Use Case Scenario
Build Time Library Location Rules
Linux Build Time Library Location Rules
Linux Static Library Naming Conventions
Linux Dynamic Library Naming Conventions
Dynamic Library Filename vs. Library Name
Dynamic Library Version Information
Dynamic Library Soname
Linker’s vs. Human’s Perception of Library Name
Linux Build Time Library Location Rules Details
Beginners’ Mistakes: What Can Possibly Go Wrong and How to Avoid It
Windows Build Time Library Location Rules
Project Linker Settings
#pragma Comment
Implicit Referencing of the Library Project
Runtime Dynamic Library Location Rules
Linux Runtime Dynamic Library Location Rules
Preloaded Libraries
rpath
LD_LIBRARY_PATH Environment Variable
runpath
ldconfig Cache
The Default Library Paths (/lib and /usr/lib)
Priority Scheme Summary
Windows Runtime Dynamic Library Location Rules
Linux Demo of Build Time and Runtime Conventions
Chapter 8: Designing Dynamic Libraries: Advanced Topics
Why Resolved Memory Addresses Are a Must
General Problem of Resolving References
Which Symbols Are Likely to Suffer from Address Translation?
Problems Caused by Address Translation
Scenario 1: Client Binary Needs to Know the Address of Dynamic Library Symbols
Scenario 2: Loaded Library No Longer Knows the Addresses of Its Own Symbols
Linker-Loader Coordination
Overall Strategy
Linker Recognizes Its Own Limitations
Linker Precisely Estimates the Damage, and Prepares Directives for Fixing It
The Loader Precisely Follows the Linker Directives
Tactics
Linker Directives Overview
Linker-Loader Coordination Implementation Techniques
Load Time Relocation (LTR)
Position Independent Code (PIC)
Lazy Binding
Rules and Limitations of the Recursive Chain of Dynamic Linking
Strong Implementation Preferences
Chapter 9: Handling Duplicate Symbols When Linking In Dynamic Libraries
Duplicate Symbols Definition
Typical Duplicate Symbols Scenarios
Duplicate C Symbols
Duplicate C++ Symbols
Duplicate Symbols Default Handling
Duplicate Local Symbols Are Allowed
Duplicate Symbols Handling When Linking in Dynamic Libraries
General Strategies of Eliminating Duplicate Symbols Problems
Duplicate Symbols and Dynamic Linking Modes
Linker’s Criteria in the Approximate Algorithm of Resolving Dynamic Libraries’ Duplicate Symbols
Location, Location, Location: Code Priority Zoning Rules
First Level Priority Symbols: Client Binary Symbols
Second Level Priority Symbols: Dynamic Library Visible Symbols
Third Level Priority (Unprioritized, Noncompeting) Symbols
Analyses of Specific Duplicate Names Cases
Case 1: Client Binary Symbol Collides with Dynamic Library ABI Function
Windows-Specific Twist
Case 2: ABI Symbols of Different Dynamic Libraries Collide
No Impact of Different Function Calls Order
Impact of Different Linking Order
Case 3: Dynamic Library ABI Symbol Collides with Another Dynamic Library Local Symbol
Case 4: Dynamic Library Non-exported Symbol Collides with Another Dynamic Library Non-exported Symbol
Interesting Scenario: Singleton in Static Library
Solving the Problem
Final Remark: Linking Does Not Provide Any Kind of Namespace Inheritance
Chapter 10: Dynamic Libraries Versioning
Gradation of Versions and their Impact on Backwards Compatibility
Major Version Code Changes
Minor Version Code Changes
Patch Version
Linux Dynamic Library Versioning Schemes
Linux Soname-based Versioning Scheme
Linux Library Filename Carries the Version Information
The Usual Dynamic Library Upgrade Practices
Preamble: The Flexibility of Softlinks
Preamble: Library Soname vs. Library Filename
Combining Softlink and Soname in the Library Upgrade Scheme
Extra Softlink Needed as Convenience for Development Scenarios
Analysis of Soname-based Versioning Scheme
The Softlink’s Role
Version Safeguarding Role of Soname
Technicalities of the Soname Implementation
Soname Embedded into the Dynamic Library File
Soname Propagated into the Client Binary File
The Support from the Other Utility Programs (ldconfig)
Linux Symbol Versioning Scheme
The Advantage of Symbol Versioning Mechanism
Symbol Versioning Mechanisms Analysis Model
Phase 1: Initial Version
Phase 2: Minor Version Changes
Phase 3: Major Version Changes
The Basic Implementation Ingredients
Linker Version Script
.symver Assembler Directive
How Does This Scheme Work?
Sample Project Analysis: Phase 1 (Initial Version)
ELF Format Support
Propagation of Version Symbol Information to the Client Binaries
Sample Project Analysis: Phase 2 (Minor Version Changes)
Sample Project Analysis: Phase 3 (Major Version Changes)
The Case of Changed ABI Function Behavior
The Case of Changed ABI Function Prototype
Version Script Syntax Overview
Version Node
Version Node Naming Rules
Symbols Export Control
Wildcard Support
Linkage Specifier Support
Namespace Support
Unnamed Node
Version Script Side Feature: Symbol Visibility Control
Windows Dynamic Libraries Versioning
DLL Version Information
Specifying DLL Version Information
Querying and Retrieving DLL Version Information
VERSIONINFO Structure
Linking Requirements
Elegant Way: Calling the DLL’s DllGetVersion Function
Brutal Alternative: Examining File Version Directly
Chapter 11: Dynamic Libraries: Miscellaneous Topics
Plug-in Concept
Rules of Exporting
Popular Plug-in Architectures
Tips and Tricks
Practical Implications of Working with Dynamic Libraries
Compartmentalized, Faster Development
Runtime Quick Substitution Ability
Miscellaneous Tips
Converting Dynamic Library to Executable
Conflicting Runtime Memory Handling of Windows Libraries
Linker Weak Symbols Explained
Chapter 12: Linux Toolbox
Quick Insight Tools
file Utility Program
size Utility Program
Detailed Analysis Tools
ldd
Safer ldd Alternatives
nm
objdump
Parsing ELF Header
Listing and Examining Sections
Listing All Symbols
Listing Dynamic Symbols Only
Examining Dynamic Section
Examining Relocation Section
Examining Data Section
Listing and Examining Segments
Disassembling the Code
objdump nm equivalents
readelf
Parsing ELF Header
Listing and Examining Sections
Listing All Symbols
Listing Dynamic Symbols Only
Examining the Dynamic Section
Examining the Relocation Section
Examining the Data Section
Listing and Examining Segments
Detecting the Debug Build
Deployment Phase Tools
chrpath
patchelf
strip
ldconfig
Runtime Analysis Tools
strace
addr2line
gdb (GNU Debugger)
Static Library Tools
ar
Creating the Static Library
Listing the Static Library Object Files
Deleting an Object File from the Static Library
Adding the New Object File to the Static Library
Restoring the Order of Object Files
Chapter 13: Linux How To’s
Debugging the Linking
Determining the Binary File Type
Determining the Binary File Entry Point
Determining the Executable Entry Point
Determining the Dynamic Library Entry Point
List Symbols
List and Examine Sections
Listing the Available Sections
Examining Specific Sections
Examining the Dynamic Section
Determining Whether Dynamic Library is PIC or LTR
Examining the Relocation Section
Examining the Data Section
List and Examine Segments
Disassembling the Code
Disassembling the Binary File
Disassembling the Running Process
Identifying the Debug Build
Listing Load-time Dependencies
Listing the Libraries Known to the Loader
Listing Dynamically Linked Libraries
strace Utility
LD_DEBUG Environment Variable
/proc//maps File
lsof Utility
Programmatic Way
Creating and Maintaining the Static Library
Chapter 14: Windows Toolbox
Library Manager (lib.exe)
lib.exe as a Static Library Tool
lib.exe as a Default Archiver Tool
lib.exe as a Command Line Utility
Creating a Static Library
Listing the Static Library Contents
Removing Individual Object Files from the Static Library
Inserting the Object File into the Static Library
Extracting the Individual Object File from the Static Library
lib.exe in the Realm of Dynamic Libraries (Import Library Tool)
dumpbin Utility
Identifying the Binary File Type
Listing the DLL Exported Symbols
Listing and Examining the Sections
Disassembling the Code
Identifying the Debug Build
Object Files
DLLs and Executables
Listing the Load Time Dependencies
Dependency Walker
Index
For your convenience Apress has placed some of the front matter material after the index. Please use the Bookmarks and Contents at a Glance links to access them.
Contents at a Glance About the Author ���������������������������������������������������������������������������������������������������������������� xv About the Technical Reviewers ���������������������������������������������������������������������������������������� xvii Acknowledgments ������������������������������������������������������������������������������������������������������������� xix Introduction ����������������������������������������������������������������������������������������������������������������������� xxi ■ Chapter 1: Multitasking OS Basics �����������������������������������������������������������������������������������1 ■ Chapter 2: Simple Program Lifetime Stages ���������������������������������������������������������������������9 ■ Chapter 3: Program Execution Stages �����������������������������������������������������������������������������43 ■ Chapter 4: The Impact of Reusing Concept ���������������������������������������������������������������������53 ■ Chapter 5: Working with Static Libraries ������������������������������������������������������������������������75 ■ Chapter 6: Designing Dynamic Libraries: Basics �������������������������������������������������������������81 ■ Chapter 7: Locating the Libraries ����������������������������������������������������������������������������������115 ■ Chapter 8: Designing Dynamic Libraries: Advanced Topics ������������������������������������������137 ■ Chapter 9: Handling Duplicate Symbols When Linking In Dynamic Libraries ���������������155 ■ Chapter 10: Dynamic Libraries Versioning ��������������������������������������������������������������������187 ■ Chapter 11: Dynamic Libraries: Miscellaneous Topics ��������������������������������������������������233 ■ Chapter 12: Linux Toolbox ���������������������������������������������������������������������������������������������243 ■ Chapter 13: Linux How To’s �������������������������������������������������������������������������������������������277 ■ Chapter 14: Windows Toolbox ���������������������������������������������������������������������������������������291 Index ���������������������������������������������������������������������������������������������������������������������������������309 v
Introduction It took me quite some time to become aware of an amazing analogy that exists between the culinary art and the art of computer programming. Probably the most obvious comparison that comes to mind is that both the culinary specialist and the programmer have similar ultimate goals: to feed. For a chef, it is the human being, for which plenty of raw ingredients are used to provide edible nutrients as well as gastronomic pleasure, whereas for the programmer it is the microprocessor, for which a number of different procedures are used to provide the code that not only needs to produce some meaningful actions, but also needs to be delivered in the optimum form. As much as this introductory comparison point may seem a bit far-fetched or even childish, the subsequent comparison points are something that I find far more applicable and far more convincing. The recipes and instructions for preparing dishes of all kinds are abundant and ubiquitous. Almost every popular magazine has a culinary section dedicated to all kinds of foods, and all kind of food preparation scenarios, ranging from quick-and-easy/last-minute recipes all the way to really elaborate ones, from ones focusing on nutrition tables of ingredients to ones focusing on the delicate interplay between extraordinary, hard-to-find ingredients. However, at the next level of expertise in the culinary art, the availability of resources drops exponentially. The recipes and instructions for running the food business (volume production, running the restaurant, or catering business), planning the quantities and rhythm of delivery for food preparation process, techniques and strategies for optimizing the efficiency of food delivery, techniques for choosing the right ingredients, minimizing the decay of stored ingredients—this kind of information is substantially more hard to find. Rightfully so, as these kinds of topics delineate the difference between amateur cooking and the professional food business. The situation with programming is quite similar. The information about a vast variety of programming languages is readily available, through thousands of books, magazines, articles, web forums, and blogs, ranging from the absolute beginner level all the way to the “prepare for the Google programming interview” tips. These kinds of topics, however, cover only about half of the skills required by the software professional. Soon after the immediate gratification of seeing the program we created actually executing (and doing it right) comes the next level of important questions: how to architect the code to allow for easy further modifications, how to extract reusable parts of the functionality for future use, how to allow smooth adjustment for different environments (starting from different human languages and alphabets, all the way to running on different operating systems). As compared to the other topics of programming, these kinds of topics are rarely discussed, and to this day belong to the form of “black art” reserved for a few rare specimens of computer science professionals (mostly software architects and build engineers) as well as to the domain of university-level classes related to the compiler/linker design. One particular factor—the ascent of Linux and the proliferation of its programming practices into a multitude of design environments—has brought a huge impetus for a programmer to pay attention to these topics. Unlike the colleagues writing software for “well-cushioned” platforms (Windows and Mac, in which the platform, IDEs, and SDKs relieve the programmer of thinking about certain programming aspects), a Linux programmer’s daily routine is to combine together the code coming from variety of sources, coding practices, and in forms which require immediate understanding of inner workings of compiler, linker, the mechanism of program loading, and hence the details of designing and using the various flavors of libraries. xxi
■ IntroduCtIon The purpose of this book is to discuss a variety of valuable pieces of information gathered from a scarce and scattered knowledge base and validate it through a number of carefully tailored simple experiments. It might be important to point out that the author does not come from a computer science background. His education on the topic came as a result of being immersed as electrical engineer in the technology frontier of the Silicon Valley multimedia industry in the time of the digital revolution, from the late 90s to the present day. Hopefully, this collection of topics will be found useful by a wider audience. Audience (Who Needs This Book and Why) The side effect of myself being a (very busy, I must say proudly) software design hands-on consultant is that I regularly come in contact with an extraordinary variety of professional profiles, maturity, and accomplishment levels. The solid statistic sample of the programmer population (of Silicon Valley, mostly) that I meet by switching office environments several times during a work week has helped me get a fairly good insight into the profiles of who may benefit from reading this book. So, here they are. The first group is made of the C/C++ programmers coming from a variety of engineering backgrounds (EE, mechanical, robotics and system control, aerospace, physics, chemistry, etc.) who deal with programming on a daily basis. A lack of formal and more focused computer science education as well as a lack of non-theoretical literature on the topic makes this book a precious resource for this particular group. The second group is comprised of junior level programmers with a computer science background. This book may help concretize the body of their existing knowledge gained in core courses and focus it to the operational level. Keeping the quick summaries of Chapters 12–14 somewhere handy may be worthwhile even for the more senior profiles of this particular group. The third group is made of folks whose interest is in the domain of OS integration and customization. Understanding the world of binaries and the details of their inner working may help “clean the air” tremendously. About the Book Originally, I did not have any plans to write this particular book. Not even a book in the domain of computer science. (Signal processing? Art of programming? Maybe . . . but a computer science book? Naaah . . .) The sole reason why this book emerged is the fact that through the course of my professional career I had to deal with certain issues, which at that time I thought someone else should take care of. Once upon a time, I made the choice of following the professional path of a high-tech assassin of sort, the guy who is called by the citizens of the calm and decent high tech communities to relieve them from the terror of nasty oncoming multimedia-related design issues wreaking havoc together with a gang of horrible bugs. Such a career choice left pretty much no space for exclusivity in personal preferences typically found by the kids who would eat the chicken but not the peas. The ominous “or else” is kind of always there. Even though FFTs, wavelets, Z-transform, FIR and IIR filters, octaves, semitones, interpolations and decimations are naturally my preferred choice of tasks (together with a decent amount of C/C++ programming), I had to deal with issues that would not have been my personal preference. Someone had to do it. Surprisingly, when looking for the direct answers to very simple and pointed questions, all I could find was a scattered variety of web articles, mostly about the high-level details. I was patiently collecting the “pieces of the puzzle” together, and managed to not only complete the design tasks at hand but also to learn along the way. One fine day, the time came for me to consolidate my design notes (something that I regularly do for the variety of topics I deal with). This time, however, when the effort was completed, it all looked . . . well . . . like a book. This book. Anyways . . . Given the current state of the job market, I am deeply convinced that (since about the middle of the first decade of 21st century) knowing the C/C++ language intricacies perfectly—and even algorithms, data structures, and design patterns—is simply not enough. xxii
■ IntroduCtIon In the era of open source, the life reality of the professional programmer becomes less and less about “knowing how to write the program” and instead substantially more about “knowing how to integrate existing bodies of code.” This assumes not only being able to read someone else’s code (written in variety of coding styles and practices), but also knowing the best way to integrate the code with the existing packages that are mostly available in binary form (libraries) accompanied by the export header files. Hopefully, this book will both educate (those who may need it) as well as provide the quick reference for the most of the tasks related to the analysis of the C/C++ binaries. Why am I illustrating the concepts mostly in Linux? It’s nothing personal. In fact, those who know me know how much (back in the days when it was my preferred design platform) I used to like and respect the Windows design environment—the fact that it was well documented, well supported, and the extent to which the certified components worked according to the specification. A number of professional level applications I’ve designed (GraphEdit for Windows Mobile for Palm, Inc., designed from scratch and crammed with extra features being probably the most complex one, followed by a number of media format/DSP analysis applications) has led me toward the thorough understanding and ultimately respect for the Windows technology at the time. In the meantime, the Linux era has come, and that’s a fact of life. Linux is everywhere, and there is little chance that a programmer will be able to ignore and avoid it. The Linux software design environment has proven itself to be open, transparent, simple and straight to-the-point. The control over individual programming stages, the availability of well-written documentation, and even more “live tongues” on the Web makes working with the GNU toolchain a pleasure. The fact that the Linux C/C++ programming experience is directly applicable to low-level programming on MacOS contributed to the final decision of choosing the Linux/GNU as the primary design environment covered by this book. But, wait! Linux and GNU are not exactly the same thing!!! Yes, I know. Linux is a kernel, whereas GNU covers whole lot of things above it. Despite the fact that the GNU compiler may be used on the other operating systems (e.g. MinGW on Windows), for the most part the GNU and Linux go hand-in-hand together. To simplify the whole story and come closer to how the average programmer perceives the programming scene, and especially in contrast with the Windows side, I’ll collectively refer to GNU + Linux as simply “Linux.” The Book Overview Chapters 2–5 are mostly preparing the terrain for making the point later on. The folks with the formal computer science background probably do not need to read these chapters with focused attention (fortunately, these chapters are not that long). In fact, any decent computer science textbook may provide the same framework in far more detail. My personal favorite is Bryant and O’Hallaron’s Computer Systems – A Programmer’s Perspective book, which I highly recommend as a source of nicely arranged information related to the broader subject. Chapters 6–12 provide the essential insight into the topic. I invested a lot of effort into being concise and trying to combine words and images of familiar real-life objects to explain the most vital concepts whose understanding is a must. For those without a formal computer science background, reading and understanding these chapters is highly recommended. In fact, these chapters represent the gist of the whole story. Chapters 13–15 are kind of a practical cheat sheet, a form of neat quick reminders. The platform-specific set of tools for the binary files analyses are discussed, followed by the cross-referencing “How Tos” part which contains quick recipes of how to accomplish certain isolated tasks. Appendix A contains the technical details of the concepts mentioned in Chapter 8. Appendix A is available online only at www.apress.com. For detailed information about how to locate it, go to www.apress.com/source-code/. After understanding the concepts from Chapter 8, it may be very useful to try to follow the hands-on explanations of how and why certain things really work. I hope that a little exercise may serve as practical training for the avid reader. xxiii
Chapter 1 Multitasking OS Basics The ultimate goal of all the art related to building executables is to establish as much control as possible over the process of program execution. In order to truly understand the purpose and meaning of certain parts of the executable structure, it is of the utmost importance to gain the full understanding of what happens during the execution of a program, as the interplay between the operating system kernel and the information embedded inside the executable play the most significant roles. This is particularly true in the initial phases of execution, when it is too early for runtime impacts (such as user settings, various runtime events, etc.) which normally happen. The mandatory first step in this direction is to understand the surroundings in which the programs operate. The purpose of this chapter is to provide in broad sketches the most potent details of a modern multitasking operating system’s functionality. Modern multitasking operating systems are in many aspects very close to each other in terms of how the most important functionality is implemented. As a result, a conscious effort will be made to illustrate the concepts in platform-independent ways first. Additionally, attention will be paid to the intricacies of platform-specific solutions (ubiquitous Linux and ELF format vs. Windows) and these will be analyzed in great detail. Useful Abstractions Changes in the domain of computing technology tend to happen at very fast pace. The integrated circuits technology delivers components that are not only rich in variety (optical, magnetic, semiconductor) but are also getting continually upgraded in terms of capabilities. According to the Moore’s Law, the number of transistors on integrated circuits doubles approximately every two years. Processing power, which is tightly associated with the number of available transistors, tends to follow a similar trend. As was found out very early on, the only way of substantially adapting to the pace of change is to define overall goals and architecture of computer systems in an abstract/generalized way, at the level above the particulars of the ever-changing implementations. The crucial part of this effort is to formulate the abstraction in such a way that any new actual implementations fit in with the essential definition, leaving aside the actual implementation details as relatively unimportant. The overall computer architecture can be represented as a structured set of abstractions, as shown in Figure 1-1. 1
Chapter 1 ■ Multitasking Os BasiCs Virtual Machine Process Virtual Memory Instruction Set Operating System CPU Main Memory Byte Stream I/O Devices Figure 1-1. Computer Architecture Abstractions The abstraction at the lowest level copes with the vast variety of I/O devices (mouse, keyboard, joystick, trackball, light pen, scanner, bar code readers, printer, plotter, digital camera, web camera) by representing them with their quintessential property of byte stream. Indeed, regardless of the differences between various devices’ purposes, implementations, and capabilities, it is the byte streams these devices produce or receive (or both) that are the detail of utmost importance from the standpoint of computer system design. The next level abstraction, the concept of virtual memory, which represents the wide variety of memory resources typically found in the system, is the subject of extraordinary importance for the major topic of this book. The way this particular abstraction actually represents the variety of physical memory devices not only impacts the design of the actual hardware and software but also lays a groundwork that the design of compiler, linker, and loader relies upon. The instruction set that abstracts the physical CPU is the abstraction of the next level. Understanding the instruction set features and the promise of the processing power it carries is definitely the topic of interest for the master programmer. From the standpoint of our major topic, this level of abstraction is not of primary importance and will not be discussed in great detail. The intricacies of the operating system represent the final level of abstraction. Certain aspects of the operating system design (most notably, multitasking) have a decisive impact on the software architecture in general. The scenarios in which the multiple parties try to access the shared resource require thoughtful implementation in which unnecessary code duplication would be avoided—the factor that directly led to the design of shared libraries. Let’s make a short detour in our journey of analyzing the intricacies of the overall computer system and instead pay special attention to the important issues related to memory usage. Memory Hierarchy and Caching Strategy There are several interesting facts of life related to the memory in computer systems: • • • The need for memory seems to be insatiable. There is always a need for far more than is currently available. Every quantum leap in providing larger amounts (of faster memory) is immediately met with the long-awaiting demand from the technologies that have been conceptually ready for quite some time, and whose realization was delayed until the day when physical memory became available in sufficient quantities. The technology seems to be far more efficient in overcoming the performance barriers of processors than memory. This phenomenon is typically referred to as “the processor-memory gap.” The memory’s access speed is inversely proportional to the storage capacity. The access times of the largest capacity storage devices are typically several orders of magnitude larger than that of the smallest capacity memory devices. 2
分享到:
收藏