An Introduction to Assembly Programming with RISC-V Prof. Edson Borin Institute of Computing Unicamp 1st edition An Introduction to Assembly Programming with RISC-V 2 Copyright c 2021 Edson Borin All rights reserved. This book or any portion thereof may notbe reproduced orusedinany mannerwhatsoever withouttheexpresswrittenpermission of the author except for the use of brief quotation in a book review. ISBN:978-65-00-15811-3 First edition 2021 Edson Borin Institute of Computing - University of Campinas Av. Albert Einstein, 1251 Cidade Universita´ria Zeferino Vaz Bara˜o Geraldo - Campinas - SP - Brasil www.ic.unicamp.br/~edson 13083-852 An updatedversionof this book and other material maybe available at: www.riscv-programming.org 3 Foreword This book focuses on teaching the art of programming in assembly language, using the RISC-V ISA as the guiding example. Towards this goal, the text spans, at an introductory level,the organizationof computing systems,describes the mechanics of how programs are created and introduces basic programming concepts including both user level and system programming. The ability to read and write code in low-level assembly languageis apowerful skill to be able tocreate highperformance programs, and to access features of the machine that are not easily accessible from high-level languages such as C, Java or Python, for example to control peripheraldevices. The book introduces the organization of computing systems, and the mechan- ics of creating programs and converting them to machine-readable format suitable for execution. It also teaches the components of a program, or how a programmer communicates her intent to the system via directives, data allocation primitivesand finally the ISA instructions, and their use. Basic programming concepts of control flow, loopsas wellas the runtimestackare introduced. Next the book describes the organization of code sequences into routines and subroutines, to composea program. The text also addresses issues related tosystem programming, including notions of peripheralcontroland interrupts. This text,and ancillary teachingmaterials, has beenused in introductory classes at the University of Campinas, Brazil (UNICAMP) and has undergone refinement and improvement for several editions. Mauricio Breternitz Principal Investigator & Invited AssociateProfessor ISTAR ISCTE Laboratory ISCTE Instituto Universitario de Lisboa Lisbon,Portugal 4 Notices: • Documentversion: May 9, 2022 • Please, reporttyposandotherissuesto Prof. EdsonBorin ([email protected]. br). 5 Contents Foreword 4 Glossary 11 Acronyms 14 I Introduction to computer systems and assembly language 1 1 Execution of programs: a 10,000 ft overview 2 1.1 Main components of computers . . . . . . . . . . . . . . . . . . . . . . 2 1.1.1 The main memory . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.1.2 The CPU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.2 Executing program instructions . . . . . . . . . . . . . . . . . . . . . . 4 1.3 The boot process . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 2 Data representation on modern computers 6 2.1 Numeral Systems and the Positional Notation . . . . . . . . . . . . . . 6 2.1.1 Converting numbersbetweenbases . . . . . . . . . . . . . . . . 8 2.2 Representing numberson computers . . . . . . . . . . . . . . . . . . . 11 2.2.1 Unsigned numbers . . . . . . . . . . . . . . . . . . . . . . . . . 11 2.2.2 Signed numbers. . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.2.3 Binary arithmetic and Overflow. . . . . . . . . . . . . . . . . . 14 2.2.4 Integer Overflow . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.3 Representing text . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16 2.4 Organizing data on the memory. . . . . . . . . . . . . . . . . . . . . . 18 2.4.1 Texts on the main memory . . . . . . . . . . . . . . . . . . . . 18 2.4.2 Numberson the main memory . . . . . . . . . . . . . . . . . . 19 2.4.3 Arrays on the main memory . . . . . . . . . . . . . . . . . . . . 19 2.4.4 Structs on the main memory . . . . . . . . . . . . . . . . . . . 21 2.5 Encodinginstructions . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 3 Assembly, object, and executable files 24 3.1 Generating native programs . . . . . . . . . . . . . . . . . . . . . . . . 24 3.1.1 Inspectingthe contents of object and executable files . . . . . . 26 3.2 Labels,symbols, references, and relocation . . . . . . . . . . . . . . . . 27 3.2.1 Labelsand symbols . . . . . . . . . . . . . . . . . . . . . . . . 27 3.2.2 References to labelsand relocation . . . . . . . . . . . . . . . . 28 3.2.3 Undefined references . . . . . . . . . . . . . . . . . . . . . . . . 30 3.2.4 Global vs localsymbols . . . . . . . . . . . . . . . . . . . . . . 31 3.2.5 The program entry point . . . . . . . . . . . . . . . . . . . . . 32 3.3 Program sections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.4 Executable vs object files . . . . . . . . . . . . . . . . . . . . . . . . . 36 6 4 Assembly language 37 4.1 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.2 Assembly instructions . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 4.3 Immediate values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4.4 Symbolnames . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40 4.5 Labels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 4.6 The locationcounterand the assemblingprocess . . . . . . . . . . . . 42 4.7 Assembly directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 4.7.1 Adding values to the program . . . . . . . . . . . . . . . . . . . 44 4.7.2 The .section directive . . . . . . . . . . . . . . . . . . . . . . 46 4.7.3 Allocatingvariables on the .bss section . . . . . . . . . . . . . 47 4.7.4 The .set and .equ directives . . . . . . . . . . . . . . . . . . . 48 4.7.5 The .globl directive. . . . . . . . . . . . . . . . . . . . . . . . 49 4.7.6 The .align directive. . . . . . . . . . . . . . . . . . . . . . . . 49 II User-level programming 51 5 Introduction 52 6 The RV32I ISA 53 6.1 Datatypesand memory organization . . . . . . . . . . . . . . . . . . . 54 6.2 RV32I registers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 6.3 Load/Store architecture . . . . . . . . . . . . . . . . . . . . . . . . . . 55 6.4 Pseudo-instructions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 6.5 Logic, shift, and arithmetic instructions . . . . . . . . . . . . . . . . . 56 6.5.1 Instructions syntax and operands . . . . . . . . . . . . . . . . . 57 6.5.2 Dealing with large immediate values . . . . . . . . . . . . . . . 57 6.5.3 Logic instructions . . . . . . . . . . . . . . . . . . . . . . . . . 58 6.5.4 Shift instructions . . . . . . . . . . . . . . . . . . . . . . . . . . 59 6.5.5 Arithmetic instructions . . . . . . . . . . . . . . . . . . . . . . 61 6.6 Data movement instructions . . . . . . . . . . . . . . . . . . . . . . . . 63 6.6.1 Load instructions . . . . . . . . . . . . . . . . . . . . . . . . . . 63 6.6.2 Store instructions . . . . . . . . . . . . . . . . . . . . . . . . . . 67 6.6.3 Data movement pseudo-instructions . . . . . . . . . . . . . . . 68 6.7 Control-flow instructions . . . . . . . . . . . . . . . . . . . . . . . . . . 69 6.7.1 Conditional control-flow instructions . . . . . . . . . . . . . . . 69 6.7.2 Direct vs indirect control-flow instructions . . . . . . . . . . . 71 6.7.3 Unconditional control-flow instructions. . . . . . . . . . . . . . 72 6.7.4 System Calls . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 6.8 Conditional set instructions . . . . . . . . . . . . . . . . . . . . . . . . 74 6.9 Detecting overflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 6.10 Arithmetic on multi-word variables . . . . . . . . . . . . . . . . . . . . 75 7 Controlling the execution flow 77 7.1 Conditional statements . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 7.1.1 if-then statements . . . . . . . . . . . . . . . . . . . . . . . . 77 7.1.2 Comparing signed vs unsigned variables . . . . . . . . . . . . . 77 7.1.3 if-then-else statements . . . . . . . . . . . . . . . . . . . . . 78 7.1.4 Handling non-trivial boolean expressions. . . . . . . . . . . . . 79 7.1.5 Nested if statements . . . . . . . . . . . . . . . . . . . . . . . . 80 7.2 Repetitionstatements . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.2.1 while loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.2.2 do-while loop . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 7.2.3 for loop . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82 7.2.4 Hoisting loop-invariantcode . . . . . . . . . . . . . . . . . . . . 83 7.3 Invoking and returning from routines . . . . . . . . . . . . . . . . . . . 83 7.3.1 Returning values from functions . . . . . . . . . . . . . . . . . 84 7.4 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 7 7.4.1 Searching for the maximum value on an array . . . . . . . . . . 85 8 Implementing routines 87 8.1 The program memory layout . . . . . . . . . . . . . . . . . . . . . . . 87 8.2 The program stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 8.2.1 Typesof stacks . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 8.3 The ABI and software composition . . . . . . . . . . . . . . . . . . . . 91 8.4 Passing parameters to and returning values from routines . . . . . . . 91 8.4.1 Passing parameters to routines . . . . . . . . . . . . . . . . . . 91 8.4.2 Returning values from routines . . . . . . . . . . . . . . . . . . 93 8.5 Value and reference parameters . . . . . . . . . . . . . . . . . . . . . . 93 8.6 Global vs localvariables . . . . . . . . . . . . . . . . . . . . . . . . . . 95 8.6.1 Allocatinglocalvariables on memory . . . . . . . . . . . . . . . 96 8.7 Register usage policies . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 8.7.1 Caller-saved vs Callee-saved registers . . . . . . . . . . . . . . . 99 8.7.2 Saving and restoring the return address . . . . . . . . . . . . . 100 8.8 Stack Frames and the Frame Pointer . . . . . . . . . . . . . . . . . . . 100 8.8.1 Stack Frames . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100 8.8.2 The Frame Pointer . . . . . . . . . . . . . . . . . . . . . . . . . 101 8.8.3 Keeping the stack pointer aligned. . . . . . . . . . . . . . . . . 102 8.9 Implementing RISC-V ilp32 compatible routines . . . . . . . . . . . . 102 8.10 Examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 103 8.10.1 Recursiveroutines . . . . . . . . . . . . . . . . . . . . . . . . . 103 8.10.2 The standard “C” library syscall routines . . . . . . . . . . . . 104 III System-level programming 106 9 Accessing peripherals 107 9.1 Peripherals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 9.2 Interacting with peripherals . . . . . . . . . . . . . . . . . . . . . . . . 108 9.2.1 Port-mappedI/O. . . . . . . . . . . . . . . . . . . . . . . . . . 109 9.2.2 Memory-mappedI/O . . . . . . . . . . . . . . . . . . . . . . . 110 9.3 I/O operationson RISC-V. . . . . . . . . . . . . . . . . . . . . . . . . 111 9.4 Busy waiting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 10 External Interrupts 114 10.1 Introduction. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 10.1.1 Polling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 10.2 External Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 10.2.1 Detecting external interrupts . . . . . . . . . . . . . . . . . . . 117 10.2.2 Invoking the properinterruptservice routine . . . . . . . . . . 118 10.3 Interruptson RV32I . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 10.3.1 Controland Status Registers . . . . . . . . . . . . . . . . . . . 120 10.3.2 Interruptrelated Controland Status Registers . . . . . . . . . 121 10.3.3 InterruptHandling Flow . . . . . . . . . . . . . . . . . . . . . . 122 10.3.4 Implementingan interruptservice routine . . . . . . . . . . . . 123 10.3.5 Setting up the Interrupt Handling Mechanism. . . . . . . . . . 124 11 Software Interrupts and Exceptions 127 11.1 Privilege Levels . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127 11.2 Protecting the system . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 11.3 Exceptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 11.4 Software Interrupts . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 11.5 Protecting RISC-V systems . . . . . . . . . . . . . . . . . . . . . . . . 130 11.5.1 Changing the privilege mode . . . . . . . . . . . . . . . . . . . 130 11.5.2 Configuring the exception and software interrupt mechanisms . 131 11.5.3 Handling illegal operations . . . . . . . . . . . . . . . . . . . . 131 11.5.4 Handling system calls . . . . . . . . . . . . . . . . . . . . . . . 132 8 A RV32IM ISA reference card 134 9 10