Why Learning Assembly Language is Still a Good Idea

【AI智能体】Langchain 上下文记忆使用实战操作详解 阅读详情
Why Learning Assembly Language is Still a Good Idea
by Randall Hyde, author of Write Great Code (No Starch)
05/06/2004  

The world is full of case studies outlining software engineering disasters. Almost every programmer has had to work on a project involving "less than stellar" source code that was difficult to read and maintain. On rare occasion, some programmers get the opportunity to work on a well-designed system, an awe-inspiring piece of craftsmanship that usually produces the exclamation, "This is truly great code!"

Clearly, professional software engineers should strive to achieve this level of greatness is all their code. But the real question is, "What makes code great?" Simply "meeting specifications" is not how one writes great code. True, in today's software environment, some might actually believe that simply meeting the specifications sets an application apart, as many development projects fail to meet their basic design goals.

However, in other areas greatness is rarely defined by doing the expected and succeeding; greatness is defined by going above and beyond what is expected. Software engineers should expect no less from great software--it should go above and beyond the standard conventions for software development.

Efficiency Is the Key
Because greatness is a multifaceted attribute, a short article such as this one cannot begin to describe all the possible components of a great piece of software. Instead, this article will describe one component of writing great code that has been neglected in recent years as computer systems have increased in capacity and power: efficiency.

Anyone who has been around the computer industry for a decade or more is well aware of this phenomenon: machines are getting exponentially more powerful per unit cost, yet users do not perceive this improvement in the applications that they purchase. For example, while word processors are clearly faster today than they were 21 years ago, they aren't 16,384 times faster as Moore's Law [1] would suggest. Part of the problem, of course, is that some of the additional processing power has been employed to support new features (such as a bitmapped display), but a large part of the reason software users aren't seeing an increase in speed is because many of today's programmers don't take the time to write efficient software, or they simply don't know how to write fast software.

Outrageous software development schedules that don't give programmers enough time to develop efficient code is certainly a problem, but many of today's programmers have grown up with fast CPUs, whose speed has made up for poor coding habits and, as such, many of these programmers have never had to learn how to write fast code.

Unfortunately, when software performance is less than optimal, these programmers generally don't know how to correct the problems with their software. They'll often spout things like "The 90-10 rule," or "I'll just use a profiler to correct the performance problems," but the truth is they don't really know how to improve the performance of their underperforming applications. It's all well and good to say, "I'll just find a better algorithm!" However, finding and deploying that algorithm, if one actually exists, is another matter.

Most of the time you can achieve very good performance boosts by simply improving the implementation of an existing algorithm. A computer scientist may argue that a constant improvement in performance isn't as good as, say, going from an algorithm with O(n^2) performance to one with O(n^lg^n) performance, but the truth is that most of the time a constant factor of two or three times improvement, applied throughout a piece of software, can make the difference between a practical application and one that is simply too slow to comfortably use. And it is exactly this type of optimization with which most modern programmers have little experience.

Unfortunately, writing efficient software is a skill, one that must be practiced to learn and one that must be practiced to maintain. A programmer who never practices this skill will never be able to apply it the day they discover that their software is running too slow. Even if a programmer has mastered the skill of writing efficient software, the programmer must practice them on a regular basis. So, there are two reasons why some programmers don't write efficient (and great) software today: they never learned how to write efficient code in the first place, or they've allowed their programming skills to atrophy to the point that they no longer write efficient code as a matter of course.

Practice Your Skills
For the programmer who has simply allowed their skills to falter from lack of use, the solution is obvious--practice writing efficient code, even when the project doesn't absolutely require it. This doesn't mean, of course, that a practicing engineer should sacrifice project schedules, readable and maintainable code, or other important software attributes for the sake of efficiency.

What it does mean is that the software engineer should keep efficiency in mind while designing and implementing the software. The programmer should make a conscious decision to choose a less efficient implementation over a more efficient implementation based on economic or engineering concerns, rather than simply utilizing the first implementation that comes to mind. Just as often as not, this simple consideration of different (and possibly more efficient) implementations is all that is necessary to produce great code. After all, sometimes the more efficient implementation is no more difficult to create than an inefficient one. All an experienced engineer may need are multiple options from which to choose.

Unfortunately, unrealistic software development schedules have led many professional engineers to shortcut the careful consideration of software development and implementation. The end result is that many professional programmers have gotten out of the habit of writing great code. Fortunately, this process is easy to reverse by practicing good software development methodologies, such as considering multiple algorithms and their implementations, as often as possible.

Learn Assembly Language
What about the programmer who has never learned to write efficient code in the first place? How does one learn how to efficiently implement an application? Unfortunately, colleges and universities today largely take the attitude that if you choose a good algorithm, you don't have to worry about the implementation of that algorithm. Far too many students come out of their data structures and algorithms courses with the attitude that if you can only achieve a constant (that is, O(1)) performance improvement, you've really achieved nothing at all, and that attempts at improvement are a waste of time.

Advances in computer architecture have exacerbated this problem--for example, you might hear a programmer say, "If this program needs to be a little faster, just wait a year or so and CPUs will be twice as fast; there's no need to worry about it." And this attitude, probably more than any other, is why software performance doesn't keep pace with CPU performance.

With every new application, the programmer writes the software slower than it ought to run, on whatever current CPU they're using, believing that future CPU performance boosts will solve their problems. Of course, by the time the CPUs are fast enough to execute their software, the programmer has "enhanced" the software, and is now depending on yet another future version of the CPU. The cycle repeats almost endlessly, with CPU performance never really catching up with the demands of the software, until finally, the software's life comes to an end and the programmer begins the cycle anew with a different application.

The truth is, it is possible to write software that executes efficiently on contemporary processors. Programmers were doing great things with software back in the days when their applications were running on eight-bit 5MHz 8088 PCs; the same techniques they used to squeeze every last bit of performance out of those low-end CPUs provides the key to high-performance applications today. So, how did they achieve reasonable performance on such low-end processors? The answer is not a secret--they understood how the underlying hardware operated and they wrote their code accordingly. That same knowledge, of the underlying hardware, is the key to writing efficient software today.

Often, you'll hear old-time programmers make the comment that truly efficient software is written in assembly language. However, the reason such software is efficient isn't because the implementation language imparts some magical efficiency properties to that software -- it's perfectly possible to write inefficient software in assembly language. No, the real reason assembly language programs tend to be more efficient than programs written in other languages is because assembly language forces the programmer to consider how the underlying hardware operates with each machine instruction they write. And this is the key to learning how to write efficient code -- keeping one's eye on the low-level capabilities of the machine.

Those same old-time programmers who claim that truly efficient software is written in assembly language also offer another common piece of advice -- if you want to learn how to write great high-level language code, learn how to program in assembly language.

This is very good advice. After all, high-level compilers translate their high-level source statements into low-level machine code. So if you know assembly language for your particular machine, you'll be able to correlate high-level language constructs with the machine language sequences that a compiler generates. And with this understanding, you'll be able to choose better high-level language statements based on your understanding of how compilers translate those statements into machine code.

All too often, high-level language programmers pick certain high-level language sequences without any knowledge of the execution costs of those statements. Learning assembly language forces the programmer to learn the costs associated with various high-level constructs. So even if the programmer never actually writes applications in assembly language, the knowledge makes the programmer aware of the problems with certain inefficient sequences so they can avoid them in their high-level code.

Learning assembly language, like learning any new programming language, requires considerable effort. The problem is that assembly language itself is deceptively simple. You can learn the 20 or 30 machine instructions found in common assembly applications in just a few days. You can even learn how to put those machine instructions together to solve problems the same way you'd solve those same problems in a high-level language in just a few short weeks.

Unfortunately, this isn't the kind of knowledge that a high-level language programmer will find useful when attempting to write efficient high-level code. To reap the benefits of knowing assembly language, a programmer has to learn to think in assembly language. Then, such a programmer can write very efficient high-level language code while thinking in assembly and writing high-level language statements. Though code written in this manner is truly great, there is one slight problem with this approach -- it takes considerable effort to achieve this level. That's one of the reasons such code is great -- because so few practitioners are capable of producing it.






Assembly Isn't Dead
Assembly language, of course, developed a very bad reputation throughout the 1990s. Advances in compiler technology, improved CPU performance, and the "software crisis" all conspired to suggest that assembly language was a "dead" language that was no longer needed. As assembly language was a bit more difficult to learn than traditional high-level programming languages, students (and instructors!) gladly embraced this brave new high-level world, abandoning difficult-to-learn assembly in favor of higher and higher level languages.

The only problem with the demise of assembly language is that as its popularity waned, so did the percentage of programmers who understood the low-level ramifications of the code they were writing. Those programmers who were claiming that assembly language was dead already knew how to think in assembly language and how to apply that low-level thinking to their high-level code; in effect, enjoying the benefits of assembly language while writing high-level language code. However, as new programmers worked their way into the system, without the benefits of having written several applications in assembly, the efficiency of software applications began to decline.

Though it would be foolish to start claiming that programmers should begin writing commercial applications in assembly language, it is clear today that the demise of assembly language's popularity has had a big impact on the efficiency of modern software. To reverse this trend, one of two things must happen: programmers must once again begin studying assembly language, or they must somehow pick up this low-level programming knowledge some other way.

Learning assembly language still remains the best way to learn the basic organization of the underlying machine. Those programmers who take the effort to master assembly language become some of the very best high-level language programmers around. Their ability to choose appropriate high-level constructs to produce efficient code, their ability to read disassembled high-level language code and detect heinous bugs in a system, and their understanding of how the whole system operates elevates them to near legendary status among their peers. These are the programmers everyone goes to when they have questions how to implement something. These are the engineers who garner the respect of everyone around them. They are the ones other programmers want to emulate. These are the programmers who write great code.

If knowing assembly language helps make programmers great, a obvious question is "Why don't more programmers learn assembly language?" Part of the problem is prejudice: many college and university instructors that teach assembly programming begin their course with a statement like, "No one really needs to know this stuff, and you'll never use it, but it is required by this program so we've got to struggle through the next several weeks studying this material." After four years of this type of attitude from their instructors, it's no surprise that students really want nothing whatsoever at all to do with assembly language programming.

Still, once it becomes obvious to a coder that the truly great programmers are the ones who've mastered assembly language programming, you might ask why more programmers don't pick up this valuable knowledge. The only problem is that, traditionally, most programmers have found it difficult to master assembly language. Assembly is radically different than most high-level languages, so learning assembly language is almost as much work as learning programming from scratch.

To someone attempting to learn assembly, it often seems as though none of their past programming experience is of any help. All too often, an engineer learning assembly becomes frustrated with the fact that they know how to achieve a goal in a high-level language but they cannot figure out how to achieve the same thing in assembly. For many programmers, switching from "thinking in a high-level language" to "thinking in an assembly language" becomes an insurmountable problem.


As an instructor teaching assembly language for over a decade at the University of California, I was quite aware of the problems students have making the transition from the high- level programming paradigm to the low-level programming paradigm.

In the early 1990s, Microsoft provided a solution with the introduction of the Microsoft Macro Assembler (MASM) v6.0 -- the inclusion of high-level control structures in an assembly language translator. While these new statements are definitely not true assembly language, they do provide a nice transition path from traditional, imperative, high-level programming languages to assembly. A programmer can continue to use statements like IF, WHILE, and FOR while learning other aspects of assembly language programs. This lets the programmer learn assembly language programming in graduated steps rather than having to make the plunge all at once.

Master Low-Level Statements
Of course, a programmer cannot truly call themselves an assembly language programmer until they've mastered the equivalent low-level statements. Nevertheless, these high-level control structures provide an excellent bridge between high-level languages and assembly language, allowing the student to leverage their existing high-level programming knowledge to learn assembly language. Alas, there are few, if any, appropriate textbooks that teach assembly language programming using this high-level to low-level approach using the high-level control structures that MASM provides.

Another problem with the high-level to low-level transition is that most high-level languages provide large libraries of routines to handle mundane tasks such as input/output, numeric conversions, and string operations. A big problem that beginning assembly programmers face is that they typically need the ability to input and output numeric quantities or do numeric-to-string conversions (and vice versa) in order to write and test very simple programs. Unfortunately, most assembly language development systems leave it up to the programmer to provide this functionality for their applications. This presents a Catch-22 situation: it is difficult to learn assembly language without these functions, but you can't really write such functions until you learn assembly language.

These roadblocks effectively prevent all but the most determined programmers from mastering assembly language. As such, throughout the 1990s and early 2000s the use of assembly language continued to wane. Seeing the decline in software efficiency and quality that seemed to track the decline of the use of assembly language, I set out on a crusade in the mid-1990s to encourage programmers to learn assembly language programming.

The first milestone I achieved was the release in the mid-1990s of the electronic edition of The Art of Assembly Language. This book, along with the use of the accompanying UCR Standard Library for 80x86 Language Programmers, reduced the effort needed to learn assembly language programming. Tens of thousands of programmers have learned assembly language programming using this textbook and the complementary set of library routines.

The only problem with the electronic edition of The Art of Assembly Language and the UCR Standard Library for 80x86 Assembly Language Programmers is that they were almost obsolete as soon as they appeared on the Internet because they taught the reader how to create 16-bit DOS applications (their release almost corresponded with the release of Windows 95, which was one of the last nails in the 16-bit programming coffin).

Still on the crusade, I started to work on a brand-new, high-level assembler (HLA, the High-Level Assembler), a new version of The Art of Assembly Language, and a new, 32-bit, HLA-based set of library routines. This effort culminated with the release of the published edition of The Art of Assembly (AoA) in 2003. To date, thousands and thousands of programmers have enthusiastically embraced this new way of learning assembly language using AoA, HLA, and the HLA Standard Library.

Though The Art of Assembly Language and HLA are increasing the ranks of assembly language programmers every day, the solution they provide is for the next generation of programmers.

What about current programmers who've missed the opportunity to learn assembly language while in school and master the concepts of machine organization before the realities of project schedules rob them of the time needed to develop the necessary expertise to write great code? The question is, "Can machine organization be effectively taught to professional programmers without simultaneously teaching assembly language?"

While it is fairly clear that learning assembly language is the best advice I can give anyone who is interested in writing great, efficient code, I am also convinced that someone can study the subject of machine organization sans assembly and still learn how to write better code. Perhaps their code won't be quite as good as the programmer who has mastered assembly language, but it will be better than the software they've written devoid of this knowledge.

Most importantly, while it is difficult to sell the idea of learning assembly language to the current generation of programmers (two decades of anti-assembly propaganda have assured this), most programmers realize that if they just "learned a little more about how the underlying hardware works" they would be able to write better code. So what is needed is a set of materials that teach data representation, memory organization, elements of computer architecture, how input/output operates, and the correspondence between high-level programming language statements.

That is, teach them all the things that they'd have to learn when learning assembly language, with the single exception of mastering the assembly language programming paradigm. Recently, I've begun to focus on this group, working on books like Write Great Code, Volume One: Understanding the Machine, a book on machine organization that doesn't specifically teach assembly language programming. While someone studying machine organization might not write code as great as someone who takes the time to master assembly language, my hope is that those who would never consider learning assembly language might be willing to pick up a book like Write Great Code and learn to write better code, if not totally great code.

Conclusion
To write great code requires one to write efficient code. Writing efficient code requires good algorithm choices and a good implementation of those algorithms. The best implementations are going to be written by those who've mastered assembly language or fully understand the low-level implementation of the high-level language statements they're choosing. This doesn't mean that we'll return to the days when major commercial applications were written entirely in assembly language. However, to reverse the trend of software running slower and slower even though CPUs are running faster and faster is going to require programmers to begin considering the low-level implications of the code that they write.

So, even if you never intend to write a single line of assembly language code again, learning assembly language, and learning to think in assembly language, is one of the best things you can do to learn how to write better assembly code.

[1] Moore's Law states that semiconductor technology doubles in capacity or performance at a given price point about every 18 months. 
 
AT&T Assembly Language 详细的揭示了linux下的AT&T汇编指令使用方法,给出了各种汇编指令,指令用法,以及相应的例程。其中包括一些如何使用汇编链接C语言库,汇编调用系统调用,汇编执行浮点运算,C语言内嵌汇编等。 Chapter 1: What Is Assembly Language? 1 Processor Instructions 1 Instruction code handling 2 Instruction code format 3 High-Level Languages 6 Types of high-level languages 7 High-level language features 9 Assembly Language 10 Opcode mnemonics 11 Defining data 12 Directives 14 Summary 15 Chapter 2: The IA-32 Platform 17 Core Parts of an IA-32 Processor 17 Control unit 19 Execution unit 24 Registers 25 Flags 29 Advanced IA-32 Features 32 The x87 floating-point unit 32 Multimedia extensions (MMX) 33 Streaming SIMD extensions (SSE) 33 Hyperthreading 34 The IA-32 Processor Family 34 Intel processors 35 Non-Intel processors 36 Summary 37 Chapter 3: The Tools of the Trade 39 The Development Tools 39 The Assembler 40 The Linker 42 The Debugger 43 The Compiler 44 The object code disassembler 44 The Profiler 44 The GNU Assembler 45 Installing the assembler 45 Using the assembler 47 A word about opcode syntax 49 The GNU Linker 50 The GNU Compiler 53 Downloading and installing gcc 53 Using gcc 54 The GNU Debugger Program 56 Downloading and installing gdb 56 Using gdb 57 The KDE Debugger 60 Downloading and installing kdbg 60 Using kdbg 60 The GNU Objdump Program 62 Using objdump 63 An objdump example 64 The GNU Profiler Program 65 Using the profiler 65 A profile example 68 A Complete Assembly Development System 69 The basics of Linux 69 Downloading and running MEPIS 70 Your new development system 71 Summary 72 Chapter 4: A Sample Assembly Language Program 73 The Parts of a Program 73 Defining sections 74 Defining the starting point 74 Creating a Simple Program 75 The CPUID instruction 76 The sample program 77 Building the executable 80 Running the executable 80 Assembling using a compiler 80 Debugging the Program 81 Using gdb 81 Using C Library Functions in Assembly 86 Using printf 87 Linking with C library functions 88 Summary 90 Chapter 5: Moving Data 91 Defining Data Elements 91 The data section 91 Defining static symbols 94 The bss section 95 Moving Data Elements 97 The MOV instruction formats 97 Moving immediate data to registers and memory 98 Moving data between registers 99 Moving data between memory and registers 99 Conditional Move Instructions 106 The CMOV instructions 107 Using CMOV instructions 109 Exchanging Data 110 The data exchange instructions 111 Using the data exchange instruction 116 The Stack 119 How the stack works 119 PUSHing and POPing data 120 PUSHing and POPing all the registers 123 Manually using the ESP and EBP registers 123 Optimizing Memory Access 123 Summary 124 Chapter 6: Controlling Execution Flow 127 The Instruction Pointer 127 Unconditional Branches 129 Jumps 129 Calls 132 Interrupts 135 Conditional Branches 136 Conditional jump instructions 136 The compare instruction 138 Examples of using the flag bits 140 Loops 144 The loop instructions 144 A loop example 145 Preventing LOOP catastrophes 145 Duplicating High-Level Conditional Branches 146 if statements 147 for loops 150 Optimizing Branch Instructions 153 Branch prediction 153 Optimizing tips 155 Summary 158 Chapter 7: Using Numbers 161 Numeric Data Types 161 Integers 162 Standard integer sizes 162 Unsigned integers 164 Signed integers 166 Using signed integers 168 Extending integers 169 Defining integers in GAS 172 SIMD Integers 173 MMX integers 173 Moving MMX integers 174 SSE integers 176 Moving SSE integers 177 Binary Coded Decimal 178 What is BCD? 178 FPU BCD values 179 Moving BCD values 180 Floating-Point Numbers 182 What are floating-point numbers? 182 Standard floating-point data types 184 IA-32 floating-point values 186 Defining floating-point values in GAS 187 Moving floating-point values 187 Using preset floating-point values 189 SSE floating-point data types 190 Moving SSE floating-point values 191 Conversions 196 Conversion instructions 196 A conversion example 198 Summary 199 Chapter 8: Basic Math Functions 201 Integer Arithmetic 201 Addition 201 Subtraction 210 Incrementing and decrementing 215 Multiplication 216 Division 221 Shift Instructions 223 Multiply by shifting 224 Dividing by shifting 225 Rotating bits 226 Decimal Arithmetic 227 Unpacked BCD arithmetic 227 Packed BCD arithmetic 229 Logical Operations 231 Boolean logic 231 Bit testing 232 Summary 233 Chapter 9: Advanced Math Functions 235 The FPU Environment 235 The FPU register stack 236 The FPU status, control, and tag registers 237 Using the FPU stack 242 Basic Floating-Point Math 245 Advanced Floating-Point Math 249 Floating-point functions 249 Partial remainders 252 Trigonometric functions 254 Logarithmic functions 257 Floating-Point Conditional Branches 259 The FCOM instruction family 260 The FCOMI instruction family 262 The FCMOV instruction family 263 Saving and Restoring the FPU State 265 Saving and restoring the FPU environment 265 Saving and restoring the FPU state 266 Waiting versus Nonwaiting Instructions 269 Optimizing Floating-Point Calculations 270 Summary 270 Chapter 10: Working with Strings 273 Moving Strings 273 The MOVS instruction 274 The REP prefix 278 Other REP instructions 283 Storing and Loading Strings 283 The LODS instruction 283 The STOS instruction 284 Building your own string functions 285 Comparing Strings 286 The CMPS instruction 286 Using REP with CMPS 288 String inequality 289 Scanning Strings 291 The SCAS instruction 292 Scanning for multiple characters 293 Finding a string length 295 Summary 296 Chapter 11: Using Functions 297 Defining Functions 297 Assembly Functions 299 Writing functions 299 Accessing functions 302 Function placement 304 Using registers 304 Using global data 304 Passing Data Values in C Style 306 Revisiting the stack 306 Passing function parameters on the stack 306 Function prologue and epilogue 308 Defining local function data 309 Cleaning out the stack 312 An example 312 Watching the stack in action 314 Using Separate Function Files 317 Creating a separate function file 317 Creating the executable file 318 Debugging separate function files 319 Using Command-Line Parameters 320 The anatomy of a program 320 Analyzing the stack 321 Viewing command-line parameters 323 Viewing environment variables 325 An example using command-line parameters 326 Summary 328 Chapter 12: Using Linux System Calls 329 The Linux Kernel 329 Parts of the kernel 330 Linux kernel version 336 System Calls 337 Finding system calls 337 Finding system call definitions 338 Common system calls 339 Using System Calls 341 The system call format 341 Advanced System Call Return Values 346 The sysinfo system call 346 Using the return structure 347 Viewing the results 348 Tracing System Calls 349 The strace program 349 Advanced strace parameters 350 Watching program system calls 351 Attaching to a running program 353 System Calls versus C Libraries 355 The C libraries 356 Tracing C functions 357 Comparing system calls and C libraries 358 Summary 359 Chapter 13: Using Inline Assembly 361 What Is Inline Assembly? 361 Basic Inline Assembly Code 365 The asm format 365 Using global C variables 367 Using the volatile modifier 369 Using an alternate keyword 369 Extended ASM 370 Extended ASM format 370 Specifying input and output values 370 Using registers 372 Using placeholders 373 Referencing placeholders 376 Alternative placeholders 377 Changed registers list 377 Using memory locations 379 Using floating-point values 380 Handling jumps 382 Using Inline Assembly Code 384 What are macros? 384 C macro functions 384 Creating inline assembly macro functions 386 Summary 387 Chapter 14: Calling Assembly Libraries 389 Creating Assembly Functions 389 Compiling the C and Assembly Programs 391 Compiling assembly source code files 392 Using assembly object code files 392 The executable file 393 Using Assembly Functions in C Programs 395 Using integer return values 396 Using string return values 397 Using floating-point return values 400 Using multiple input values 401 Using mixed data type input values 403 Using Assembly Functions in C++ Programs 407 Creating Static Libraries 408 What is a static library? 408 The ar command 409 Creating a static library file 410 Compiling with static libraries 412 Using Shared Libraries 412 What are shared libraries? 412 Creating a shared library 414 Compiling with a shared library 414 Running programs that use shared libraries 415 Debugging Assembly Functions 417 Debugging C programs 417 Debugging assembly functions 418 Summary 420 Chapter 15: Optimizing Routines 421 Optimized Compiler Code 421 Compiler optimization level 1 422 Compiler optimization level 2 423 Compiler optimization level 3 425 Creating Optimized Code 425 Generating the assembly language code 425 Viewing optimized code 429 Recompiling the optimized code 429 Optimization Tricks 430 Optimizing calculations 430 Optimizing variables 433 Optimizing loops 437 Optimizing conditional branches 442 Common subexpression elimination 447 Summary 450 Chapter 16: Using Files 453 The File-Handling Sequence 453 Opening and Closing Files 454 Access types 455 UNIX permissions 456 Open file code 458 Open error return codes 459 Closing files 460 Writing to Files 460 A simple write example 460 Changing file access modes 462 Handling file errors 462 Reading Files 463 A simple read example 464 A more complicated read example 465 Reading, Processing, and Writing Data 467 Memory-Mapped Files 470 What are memory-mapped files? 470 The mmap system call 471 mmap assembly language format 473 An mmap example 475 Summary 479 Chapter 17: Using Advanced IA-32 Features 481 A Brief Review of SIMD 481 MMX 482 SSE 483 SSE2 483 Detecting Supported SIMD Operations 483 Detecting support 484 SIMD feature program 485 Using MMX Instructions 487 Loading and retrieving packed integer values 487 Performing MMX operations 488 Using SSE Instructions 497 Moving data 498 Processing data 499 Using SSE2 Instructions 504 Moving data 505 Processing data 505 SSE3 Instructions 508 Summary 508 Index 511 立即下载

相关推荐

Mastering Assembly Programming 无水印pdf

Mastering Assembly Programming 英文无水印pdf pdf所有页面使用FoxitReader和PDF-XChangeViewer测试都可以打开 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

汇编语言(Assembly Language)笔记

An introduction toAssembly Language: It’s a low-levelprogramming language for a computer orother programmable device. In contrast,it can compiling faster than most high-levelprogramming languages

kerecs的博客 2237

【论文精读】Latent Diffusion

Latent Diffusion

weixin_44934783的博客 4479

Intel X86 assembly language reference

Jump Meaning Signedness (S or U) ------------------------------------------------------------ ja | Jump if above | U jae | Jump if above or Equal | U jb | Jump if below | U jbe | Jump if below

fanbird2008的专栏 1143

Saturn PCB Toolkit V8.02 实战:5分钟完成10A电源路径的走线与过孔通流验证

本文详细介绍了如何使用Saturn PCB Toolkit V8.02快速验证10A电源路径的走线与过孔通流能力。通过实战案例和参数配置指南,帮助工程师解决大电流PCB设计中的温升失控、过孔瓶颈等核心挑战,提升设计效率和可靠性。

weixin_34194829的博客 452

银河麒麟V10系统下,手把手解决Ollama安装报错‘GLIBCXX_3.4.25 not found’

本文详细介绍了在银河麒麟V10系统下解决Ollama安装报错‘GLIBCXX_3.4.25 not found’的实战指南。通过隔离编译新版libstdc++、环境变量引导和服务化封装等安全方案,确保在不破坏系统稳定性的前提下顺利运行Ollama,适用于国产操作系统与AI工具的兼容性需求。

weixin_42556197的博客 484

编译器 | 从工业实现到极简设计 —— 编译器的多元形态与实践

……

u013669912的博客 894

医疗信创国产化替代目前面临哪些难题?如何利用国产虚拟化技术促进医院信创建设

业务系统众多,存在大量信创改造模糊地带,既有老系统,也有新系统,故障点多,管理难度高,IT人力资源不足,其对硬件的支撑能力也提出了越来越高的要求,由此造成硬件成本、管理成本以及能耗成本都非常高。

云宏winhong的博客 2662

微软技术日报 11-09:.NET 8 与 9 明日同时停止支持,注册表编辑器出了 WinUI 3 版

今天这四条消息的共同点是收口。.NET 8 和 9 的支持期到点,注册表编辑器的新界面只放在仓库里给人看,GitHub 把一类危险触发器按住默认,微软在安全报告里把防线从地址黑名单挪到行为。收口并不等于关门。.NET 10 还在支持期里,被按住的触发器可以用策略按文件放回来,实验室里的样例随时可能变成产品。区别在于这些动作要有人签字,不再是默认开着。如果今天只做一件事,去看一眼构建机上的 .NET 版本。明天之后,8 和 9 的漏洞补丁不会再来了。

海盗Sharp的博客 390

基于 Node.js + MongoDB 技术栈的小众开源短链接程序 —— Lynx

开源的短链接程序有很多,像 YOURLS、Shlink 等大多采用 PHP + MySQL 技术栈。但我之前的服务器配置一般,再加上自己写的小玩具使用的是 Node.js + MongoDB,这些环境已经装在服务器上了,因此更倾向于寻找一款同样基于这套技术栈的短链接程序。搜索了很久才找到这么一款基于的短链接程序——Lynx。这个开源项目非常小众,Star 数只有两百多。

zc_mk的博客 828

基于强化学习方法的PID参数整定

前言 PID控制器在工业界应用非常广泛,但是PID的参数调节一般需要人工根据经验法来试。对于有经验的工程师来说,一般试几次就可以获得满足调节的参数。然而对于新手工程师却很难确定一套比较好的参数。 这里我们采用强化学习的方法来调节PID参数。 这个例子展示了如何使用双延迟深度确定性策略梯度(TD3:twin-delayed deep deterministic policy gradient)强化学习算法来调整PI控制器。整定控制器的性能与使用Control System Tuner app整定的控制器的性能

weixin_42188287的博客 2万+

AI驱动数据处理的安全边界:行业现状、风险权衡与本地化实践路径

本文基于第三方数据,分析AI用于数据处理的安全议题。大模型应用加速普及,但伴随数据出境、影子AI、幻觉与成本失控等风险。行业共识指向“脚本复用”路径:将分析逻辑本地化固化,实现数据可控、结果可复现、成本可降。产品如数以轻舟提供本地处理、多模型接入与一次付费永久使用方案。建议企业从数据落点、可控性、可复现性与合规性四维度评估选型,推动AI在安全边界内释放价值。

数据矿工-数据化运营博客 329

基于深度学习的大豆病害检测识别系统:YOLOv10 + UI界面 + 数据集

YOLOv10是一种高效的目标检测算法,能够在保持高精度的同时,提供较快的检测速度。YOLOv10使用了改进的卷积神经网络架构,并在多个计算机视觉任务中表现出色。在本项目中,我们将使用YOLOv10进行大豆病害的检测和分类。本系统利用YOLOv10算法,实现了大豆病害的实时检测和分类。通过结合深度学习和图像处理技术,可以帮助农业领域的专业人员更加高效地识别和诊断大豆病害,提高农作物的生产力与质量。

YOLO 700

微软技术日报 11-08:Foundry 与 Entra 各挂一个 10.0 分漏洞,Foundry 接 fal 五款视频模型

这一周的动作可以分成两类。一类在收。Copilot 从电视上退场,搜索里的 AI 改成可选,云端漏洞只发通知不收补丁。共同点是承认铺得太开,代价比预期高。另一类在放。Foundry 一次摆上五个视频模型,容器版应用网关一个入口挂 64 个 MCP 服务器。共同点是把能力做成可组合的积木,让使用者按需挑。两个方向背后是同一个判断。把能力塞到每一个界面上,短期看覆盖率高,长期要解释为什么删不掉。新的做法是先给一个能关的开关,再谈覆盖。对每天写代码的人来说,今天有两样现成的东西可以试。

海盗Sharp的博客 419

基于Simulink的单级式光伏并网系统MPPT控制仿真

本文基于Simulink平台,详细介绍了单级式光伏并网系统的MPPT控制仿真实现。主要内容包括:1)阐述MPPT作为光伏系统"智能大脑"的核心作用;2)解析单级式系统架构及扰动观察法(P&O)算法原理;3)以10kW户用系统为例,分步骤演示建模过程,包括光伏阵列搭建、P&O控制器实现(含MATLAB代码)、并网控制设计等;4)通过仿真验证系统在光照突变下的动态响应性能,MPPT效率达98.3%。文章还提出了变步长P&O等优化方向,为光伏系统仿真与控制提供实用指导。

xiaoheshang_123的博客 112

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

微软技术周报 11-02~11-09:VS Code 混装 Claude 与 Codex、EF Core 11 静默改行为、.NET 11 倒计时

11 月 6 日,Power Platform 通过消息中心通知管理员,Copilot Studio、Power Automate 和 Power Apps 里所有跑在 Anthropic Claude、xAI Grok 以及旧版 GPT 上的 prompt,12 月 2 日自动迁移到 GPT-6 系列,档位价格不变,模型选择收窄到一条产品线。效果是这样的:让 Claude 评审一个 Copilot chat 写出的方案,或者把同样的任务交给 Codex,两边并排跑在同一个会话里。更要紧的是下周的时间线。

海盗Sharp的博客 989

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

MAI-Cyber-1 深度解析:微软首个网络安全专用模型

微软没有去做"更大的安全大模型",而是用一颗 137B 总参、仅 5B 激活的稀疏 MoE 专用模型,配上 90/10 的"小模型铺量、大模型兜底"路由,在 CyberGym 基准上拿到 95.95% 的同时把成本砍掉一半——这标志着 AI 安全从"通用模型加提示词"进入了"专用模型加系统工程"的时代。

Simple_Pure的博客 327

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

微软输入法标点乱跳解决方案

微软拼音输入法常因“中文输入时使用英文标点”开关被意外开启,导致标点自动切换为英文且快捷键失效。本文提供一键批处理脚本,通过修改注册表(HKCU\Software\Microsoft\InputMethod\Settings\CHS)强制锁定中文标点,覆盖多个相关键值,确保设置持久生效。相比手动操作,该方案可抵御更新、同步等导致的配置重置,提升稳定性。执行后需重启输入法或系统以使更改生效,建议提前备份注册表。

谙弆悕博士的技术博客! 370

微软2026年11月补丁星期二解析:1094个 CVE、Outlook 零日 CVE-2026-124194 与修复优先级

微软11月补丁星期二修复1094个 CVE,唯一在野利用的 Outlook 零日 CVE-2026-124194 只评为“中等”,修复随 Office 更新下发、不在 Windows 累积更新里。本文整理漏洞分布、严重级漏洞分类处置与三档修复优先级。

SplashtopLoki的博客 217

微软 BioEmu2 实测:AI 设计的抗体,能否通过动态模拟提前筛选?

微软 BioEmu2 实测:AI 设计的抗体,能否通过动态模拟提前筛选?**2026 年 10 月 26 日,展示了一个 AI 抗体候选的 10 纳秒传播动画。**但这个案例留下的最大问题,仍是实验室门前那道选择题:一批看起来合理的设计,究竟该把哪几个送去测试?Ford 正在参与 Adaptyv 与 Anthropic 的蛋白设计竞赛,也在开发抗体语言模型。**但他在原文中坦言,生成候选容易,挑出值得测试的候选依然困难。**本文解读他的公开实测,并对照微软文档核查证据边界,未独立运行模型。

weixin_71777199的博客 216

【第 008 讲】在终端中运行 Python 程序:交互模式与脚本模式 | 绝对路径与相对路径 | 以模块方式运行 | 常见报错的识别与排查

本文系统讲解在终端中运行 Python 程序的方式:从交互模式与脚本模式讲起,梳理绝对路径与相对路径的运行写法及 cd、dir 等命令的用法;进而讲解以模块方式运行的特点与字节码缓存的产生;最后通过路径、拼写、标点三类典型报错,帮助读者掌握读懂报错、定位并修复错误的排查思路。

大模型全栈工程师 · Thanks_ks 785

企业微信 × AI 对接第六步:模板卡片交互闭环——按钮回调、ResponseCode 状态机、卡片更新(附跑通代码)

AI 生成的审批建议,让主管在卡片上直接点"同意/驳回",比跳系统快一个数量级——这是企业微信模板卡片消息的交互闭环:发送时带 task_id 和按钮 key,用户点击后企微回调 EventKey/TaskId/ResponseCode,你拿 ResponseCode(72 小时有效、只能用一次)调 update_template_card 把卡片原地改成"已处理"。这篇把五种卡片类型、回调字段、更新接口一次讲透,附一个带完整防御(重复核销/超时/未知 key 拒绝)的状态机代码,本地实测跑通四种场景。

weixin_45264536的博客 373

情感交互机器人融资,四川具身科技的「爱湫」登场

当前人形机器人的主流战场是工业、仓储、巡检这些「干活」的场景,而「爱湫」把重心放在了「陪伴」上——通过面部投影和情绪识别,让机器人和人之间多一层情感层面的交互。情感交互机器人的市场,其实一直存在,只是过去被「能干活」的主流叙事盖住了。它主推的产品「爱湫」,是一款主打情感交互的人形机器人,搭载 3D 投影面部技术,情感交互机器人的逻辑,是面向养老陪伴、文旅服务、展厅导览这类「不要求重体力、但要求互动感」的场景。真正的考验不在发布会,而在它能不能在真实的养老和陪伴场景里,被用户用起来、留下来。

jushenAGI的博客 294

微软 365 全球掉线复盘,Purview 数据治理退役,C++ 动态调试转正

把今天这几条放在一起,会看到一个共同的题目,系统的自动判断出错时,人还能不能兜住。故障那条是自动判断误判。健康检查本来的职责是把坏机器摘出去,这次它把还能用的机器也摘了,剩下的机器承接双倍压力,再被摘掉,容量一路缩减。微软的补救方向很说明问题,一边验证一套替代的健康检查方式,一边准备自动检测并重启无响应服务器的机制,等于在原来的判断链路上加第二道保险。脚本那条是校验从宽容变严格。旧文件在宽松的校验下一直能用,规则一收紧,一批历史遗留的编码问题同时浮出水面,而表象是「签名没了」。

海盗Sharp的博客 301

微软技术日报 2026-11-07:Copilot 本机跑 27B 模型、Front Door 默认后量子 TLS、Beta 转 26H2

四条消息挤在同一天,方向各不相同:Foundry Local 把 27B 的编码模型压进了 24GB 显存并接进 GitHub Copilot;Azure Front Door 把入站 TLS 1.3 的混合后量子密钥交换设成了默认;Windows Insider 一次放出五个构建,Beta 通道正式转到 26H2;Power Platform 通知管理员,12 月 2 日提示模型换血,Claude 与 Grok 一起退出。四条放在一起看,有两条在改默认值,两条在改节奏。

海盗Sharp的博客 515

微软Copilot生态深度解析:从办公助手到超级应用的整合趋势与实战技巧

在人工智能技术飞速发展的今天,微软Copilot已成为连接用户与AI生产力的核心桥梁。虽然“copilot-analysis”这一特定仓库可能指向具体的分析脚本或文档,但从更宏观的视角来看,它代表了当前对微软Copilot生态系统的深度探索。Copilot不仅仅是一个聊天机器人,它已经深度嵌入到Excel、Word、GitHub等核心生产力工具中,甚至正在向“超级应用”演进。

wulechun的博客 166
上一篇: 用VC写Assembly代码(7)--在Visual C++中使用内联汇编
下一篇: 用VC写Assembly代码(5) --函数调用(三)
普通网友
博客等级 码龄22年 1万+粉丝 3156原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值