4. ** in 1971-73 Dennis M. Ritchie turned
the B language into the C language,
keeping most of the language B syntax
while adding data-types and many
other changes
5. *
the most famous example program from the book is its "hello,
world" program, which just prints out the text "hello, world" to
the terminal, as an illustration of a minimal working C
program. Numerous texts since then have followed that
convention for introducing a programming language.
*in 1978 the publication of ”The C Programming
Language” by Kernighan & Ritchie caused a revolution
in the computing world.
8. *
*gcc hello.c
=>your code has been compiled into a separate
executable file which by default is named
as a.out
*To execute program first, enter: ./first
9. *
*The compilation is performed in four sequential phases
by the compilation system (a collection of four
programs preprocessor,compiler, assembler, and
linker).
* we could use the commands as (assembler), ld (link
loader), and gdb (GNU debugger) from GCC(GNU
Compiler Collection) .
*C code=> assembly code=>object file=>executable
13. *To get the assembly code from our C code we
use the « Gcc –s » command :
1
2
3
# gcc -S hello.c -o hello.s
# cat hello.s
15. *
1
2
3
# gcc -c hello.s -o hello.o
# file hello.o
hello.o: ELF 32-bit ,,,,,,,,,,,,
1
2
8 # readelf -a hello.o
We can see that the hello.o is the object file that is actually an ELF 32-bit
executable, which is not linked yet. If we want to run the executable, it will
fail as noted below:
We can read the contents of the object file with the readelf program
as follows
16. *
*# chmod +x hello.o
*# ./hello.o
*bash: ./hello.o: cannot execute binary file =>
we need to link it
18. *
*Generic ELF File Layout : A simple Executable
ARM ELF file has the conceptual layout shown
in the diagram on the right.
19. *
we want to build object code for the ARM processor at the heart of the
Raspberry Pi, we need a cross-compiler and its associated tools, which
is usually called a "toolchain". Here we are using "crosstool-ng" to build
such tool chain.
arm - non e - eabi - gcc
20. *To understand the C compilation let’s look at
the ARM assembly language
21. *
In this lab, you will learn to write ARM assembly language
programs and test them on a Raspberry Pi, featuring the BCM2835
microprocessor
Rpi < 2 only support armv6 instructions
While RPI 2 support armv7 instructions
22. *all ARM instructions are 32 bits long. Here is a
typical one:
*10101011100101010010100111101011
*Fortunately, we don't have to write ARM
programs using such codes. Instead we use
assembly language
25. *
Registres particuliers
r13 alias sp : stack pointer pointeur sur pile de
donnees
● r14 alias lr : lr stands for link register and it
is the address of the instruction following the
instruction that called us(return)
● r15 alias pc : program counter contains the
address of the next instruction going to be
executed
When the ARM processor
executes an instruction,
two things may happen at
the end of its execution. If
the instruction does not
modify pc (and most
instructions do not), pc is
just incremented by 4 (like
if we did add pc, pc, #4).
Why 4? Because in
ARM, instructions are 32
bit wide, so there are 4
bytes between every
instruction. If the
instruction modifies pc
then the new value for pc
is used
Once the processor has fully executed an instruction then it
uses the value in the pc as the address for the next instruction
to execute,This process of changing the value of pc is called
branching. In ARM this done using branch instructions.
26. cpsr (for Current Program Status
Register) keeps some values that can be read and updated
when executing an instruction
cmp r1, r2 /* updates cpsr doing "r1 ‐ r2", but r1 and r2
are not modified */
EQ (equal) When Z is enabled (Z is 1)
NEQ (not equal). When Z is disabled. (Z is 0)
[r1, +#12] => an offset of 12
(4 bytes * 3 items
skipped).
33. MOV r5,#7
*● C'est une operation Move =>Opcode
*->11100011101
*● Puis indicateur ''pas de mise a jour
*des codes conditions'' (pas de S en suffixe)
*->111000111010
*● MOV : pas de 1er operande (Rn a 0)
*->1110001110100000
*● Registre destination R5 (Rd code pour 5)
*->11100011101000000101
*Format immediat : constante 8 bits et rotation
*constante = 0b00000111(binaire)=7décimal
*● Pas besoin de deplacer la constante 8 bits
*pour obtenir la valeur immediate (rotation 0)
*->111000111010000001010000
*● Constante 8 bits
*->11100011101000000101000000000111
35. .data
msg:
.ascii "Hello, Piday!n"
len = . ‐ msg
.text
.globl _start
_start:
/* syscall write(int fd, const void *buf, size_t count) needs 3 argument*/
mov %r0, $1 /* fd ‐> stdout standard output*/
ldr %r1, =msg /* buf ‐> msg */
ldr %r2, =len /* count ‐> len(msg) */
mov %r7, $4 /* write is syscall #4 */
swi $0 /* invoke syscall */
/* syscall exit(int status) */
mov %r0, $0 /* status ‐> 0 */
mov %r7, $1 /* exit is syscall #1 */
swi $0 /* invoke syscall */
The C function s, including the ISO C
standard ones, are widely used by
programs, and are regarded as if they
were not only an implementation of
something in the C language, but also
de fact o part of the operating system
interface.=> glibc
Making call using C lib
it is rather unusual to perform system calls directly.
It is almost always preferable to call the C library
instead.
*
36. *To terminate a program
*MOV R7, #1
*SVC 0 6 of 23
*The number 1 placed in Register 7 tells the operating system
to terminate this program. The instruction “SVC 0” is the
system call, that transfers the program execution to the
operating system. If you place a different number in R7, the
operating system will perform a difference service.
on ARM, the system call identifier is put in register R7, arguments are passed in
R0R6 (respecting “EABI arrangement” where appropriate,i.e. 64bit arguments),
and the kernel is called with the ‘SWI 0’ instruction.
37. Now, coming to Raspberry Pi, which is a Broadcom SOC,BCM 2835,based on ARM
Processor. Every System Call is Index in the System Call Table. The Index is an
Integer value which is passed to the Register R7, in case Platform. The
registers, R0, R1 and R2 are used to pass the arguments of the System Call. The
instruction, SWI, now being used as SVC, which is a Supervisor Call, used to
jump to the Privileged Mode, to invoke the Kernel. The embedded with SVC
#num, is used to refer to the Handler.
svc #0
Hence, as an example, say, we want to invoke a System Call to print "Hello
Worldn". The System Call Index 'Write' is #4. Thus, the code will be something
like,
38. *
In Linux ARM we can perform a system call by using the
instruction swi. This instruction means software
interruption and its sole purpose is to make a system
call to the operating system.
Linux we will always use swi #0 to perform a system call.
No system call in Linux receives
more than 7 arguments and the arguments
are passed in registers r0 to r6. If the
system call returns some value it will be
returned in register r0.
39. Hello world, the system call way
As a simple illustration of calling the operating system we
will write the archetypical “Hello world” program using
system calls. In this case we will call the function write.
Write receives three parameters: a file descriptor where we
will write some data, a pointer to the data that will be
written and the size of such data. Of these three, the most
obscure may be now the file descriptor. Without entering
into much details, it is just a number that identifies a file
assigned to the process. Processes usually start with three
preassigned files: the standard input, with the number 0,
the standard output, with the number 1, and the standard
error, with the number 2. We will write our messages to the
standard output, so we will use the file descriptor 1.
42. Write assembly in .s file
As ‐o hello.o hello.S (output object file from
assembly file)
Ld ‐s ‐o hello hello.o (output exeutable file) gcc ‐o hello hello.o
*Linker: Finally, the linker ﴾ld/ld.exe﴿ links the object code with the
library code to produce an executable file « hello/hello.exe".
*> ld ‐o hello.exe hello.o ...libraries...
43. *
"ldd" Utility ‐ List Dynamic‐Link Libraries
The utility "ldd" examines an executable and displays a list of the
shared libraries that it needs. For example,
> ldd hello.exe
ntdll.dll => /cygdrive/c/Windows/SYSTEM32/ntdll.dll (0x77bd0000)
kernel32.dll => /cygdrive/c/Windows/system32/kernel32.dll
(0x77600000)
KERNELBASE.dll => /cygdrive/c/Windows/system32/KERNELBASE.dll
(0x75fa0000)
44. Gdb Debugger
>> gdb hello
>> gdb start
>> gdb disassemble
*Debugging :
* as gstabs o filename.o filename.s =>get assambly
* If you want to use gdb, you need to invoke the
assembler with some additional options.
* When gdb starts, we need to set a breakpoint.
* The execution of the program will stop there and
we can step forwards one instruction at a time
from
* that point. Here, I am setting the breakpoint
* at the _start label.
* (gdb) break *_start
* (gdb) run
* (gdb) info rgisters
* GDB has the ability of disassembling the machine
code back to assembly instructions. The command
is “disassemble”.
Gdb layout asm
Gdb si (stepinto)
* To start the program, use command “run”*
45. *
*Install Code::Blocks IDE
*To install Code::Blocks IDE, use the following
command at the command prompt and all the
required software will be installed.
*$ sudo apt-get install codeblocks
46. *The assembly code generated from the C code
is different from the basic Assembly code.s
A compiler has to produce working machine code for
the infinite number of programs that can be
written in the language it compiles. It is impossible
to ensure that all possible highlevel Instructions are
translated in the optimum way;
Call assembly into C
48. *
How a Raspberr y-Pi processor boots. The BCM2385 includes a GPU
and this GPU includes a
bootloader . The bootloader is capabable of reading the contents of
a FAT32 partition on an SD card and booting fr om
the kernel .img file contained on it. This kernel.img file is an ARM
executable, and is generally the linux kernel . All we need to do is
generate our executable and replace the kernel .img file on the SD
card with our file to execute it.
The first thing we will need to setup is the GPIO controller.
There are no drivers we can rely on as there is no OS
running, all the bootloader has done is boot the processor
into a working state, ready to start loading the OS.
49. *Now that you have extracted the template, create a new file
in the 'source' directory called 'main.s'. This file will contain
the code for this operating system. To be explicit, the folder
structure should look like:
*build/ (empty)
* source/
main.s
*kernel.ld
*LICENSE
*Makefile
Open 'main.s' in a text editor so that we
can begin typing assembly code. The
Raspberry Pi uses a variety of assembly
code called ARMv6, so that is what we'll
need to write in.
Copy in these first commands.
.section .init
.globl _start
_start:
*
50. *This will turn on
the LED and blink
To install your operating system, first of all get a Raspberry PI SD
card which has an operating system installed already. If you browse
the files in the SD card, you should see one called kernel.img.
Rename this file to something else, such as kernel_linux.img. Then,
copy the file kernel.img that make generated onto the SD Card.
You've just replaced the existing operating system with your own. To
switch back, simply delete your kernel.img file, and rename the
other one back to kernel.img. I find it is always helpful to keep a
backup of you original Raspberry Pi operating system, in case you
need it again.
51. BareMetal OS, a 64-bit operating system written entirely in
assembly.
APOTHEMEOS A Small Assembly Opensource Os.
52. *
*Cambridge tutorials by lighting the OK LED
on the Raspberry-Pi board.
*Any request : Bellaj1@gmail.com
Compiled languages
Interpreted languages
P-code languages
hybrid language that uses both compilation and interpretation
Important p-code languages include Python, Perl, and Java.
These two functions are implemented in the C library, so they are more or less supported in any environment supporting the C language.
La compiltion =?
GNU Compiler Collection ﴾GCC﴿: a compiler suit that supports many languages, such as C/C++, Objective‐C and
Java.
What is compilation?
BCM2836=> pi2
BCM2835=> olds pis
Docu du 35 est disponible !=36
Br = branch =like jump
list of all the instruction boxes in the courses in order.
ldr reg,=val puts the number val into the register named reg.
mov reg,#val puts the number val into the register named reg.
lsl reg,#val shifts the binary representation of the number in reg by val places to the left.
str reg,[dest,#val] stores the number in reg at the address given by dest + val.
name: labels the next line name.
b label causes the next line to be executed to be label.
sub reg,#val subtracts the number val from the value in reg.
cmp reg,#val compares the value in reg with the number val.
Suffix ne causes the command to be executed only if the last comparison determined that the numbers were not equal.
.globl lbl makes the label lbl accessible from other files.
mov reg1,reg2 copies the value in reg2 into reg1.
Suffix ls causes the command to be executed only if the last comparison determined that the first number was less than or the same as the second. Unsigned.
Suffix hi causes the command to be executed only if the last comparison determined that the first number was higher than the second. Unsigned.
push {reg1,reg2,...} copies the registers in the list reg1,reg2,... onto the top of the stack. Only general purpose registers and lr can be pushed.
bl lbl sets lr to the address of the next instruction and then branches to the label lbl.
add reg,#val adds the number val to the contents of the register reg.
Argument shift reg,lsl #val shifts the binary representation of the number in reg left by val before using it in the operation before.
lsl reg,amt shifts the binary representation of the number in reg left by the number in amt.
str reg,[dst] is the same as str reg,[dst,#0].
pop {reg1,reg2,...} copies the values from the top of the stack into the register list reg1,reg2,.... Only general purpose registers and pc can be popped.
alias .req reg sets alias to mean the register reg.
.unreq alias removes the alias alias.
lsr dst,src,#val shifts the binary representation of the number in src right by val, but stores the result in dst.
and reg,#val computes the Boolean and function of the number in reg with val.
teq reg,#val checks if the number in reg is equal to val.
ldrd regLow,regHigh,[src,#val] loads 8 bytes from the address given by the number in src plus val into regLow and regHigh.
.align num ensures the address of the next line is a multiple of 2num.
.int val outputs the number val.
tst reg,#val computes and reg,#val and compares the result with 0.
strh reg,[dest] stores the low half word number in reg at the address given by dest.
ARM instruction has 32 bits in which to encode the instruction type, condition,
operands etc. In group one instructions there are twelve bits available to encode immediate operands.
Twelve bits of binary can represent numbers in the range 0..4095, or 2048..+ 2047 if we treat them as
signed.
calling the system call through the C library was not harder than calling a normal function. Let’s try the same directly performing a Linux system call. First we have to identify the number of the system call and put it in r7. The call write has the number 4 (you can see the numbers in the file /usr/include/arm‐linux‐gnueabihf/asm/unistd.h). The parameters are usually the same as in the C function, so we will use registers r0, r1 and r2 likewise.
You could register your own sys call
/************* CODE SECTION *************/
.text @ the following is executable assembly
@ Ensure code section is 4-byte aligned:
.balign 4
@ main is the entry point and must be global
.global main
B main @ begin at main
/************* MAIN SECTION *************/
main:
MOV r4, #13 @ load nth fibonacci number here
MOV r0, #0
MOV r1, #1 @ Load first two fibonacci numbers
loop:
B loop
done:
BX lr @ exit cleanly
.end @ end of code
/////////////////////
As you can see it is not that different to a function call but instead of branching to a specific
address of code using bl we use swi #0. Truth be told, it is rather unusual to perform
system calls directly. It is almost always preferable to call the C library instead.
Hidden slid
Use time to compare the difference between native Assambly code execution and the execution of the assembly code generated from C code.
Un os en assembly projet,
Almost all Unix code except a small amount of direct hardware-interface support in the kernel itself is nowadays written in a high-level language.