inline assembly section 1: recitation 7. in the early days of computing, most programs were written...

21
Inline Assembly Section 1: Recitation 7

Post on 19-Dec-2015

214 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Inline Assembly

Section 1: Recitation 7

Page 2: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

• In the early days of computing, most programs were written in assembly code.– Unmanageable because

• No type checking, eg., confusing pointer as an integer.• Machine dependent.

• But sometimes assembly is necessary.

– Implementing an operating system.• Special registers storing process state information• Special instructions or memory locations for I/O.

– For application programmers, there are some machine features, such as the values of the condition codes, that cannot be accessed directly in C.

Page 3: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

• Integrate code consisting mainly of C with a small amount written in assembly language.

E.g., file p1.c contains C code and file p2.s contains assembly code. The command:

$ gcc -o p p1.c p2.s

will cause file p1.c to be compiled, file p2.s to be assembled, and the resulting object code to be linked to form an executable program p.

– Using Inline Assembly.

Page 4: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Inline Assembly (asm directive)

• Allows user to insert assembly code directly into the code sequence generated by the compiler.

• Special features are provided eg. – specify instruction operands– indicate registers which are being overwritten.

• The resulting code is machine-dependent,

• The asm directive is specific to GCC. Therefore, incompatible with other compilers.

Page 5: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Basic form

• asm( code-string );• code-string is an assembly code sequence

given as a quoted string.• The compiler inserts this string verbatim into the

assembly code being generated, ie., the compiler-supplied and the user supplied assembly will be combined.

• The compiler doesn’t check the string for errors, and so the first indication of a problem might be an error report from the assembler.

Page 6: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

An example:

• Consider functions with the following prototypes:int ok_smul(int x, int y, int *dest);

int ok_umul(unsigned x, unsigned y, unsigned *dest);

• Compute the product of arguments x and y and store the result in the memory location specified by argument dest. As return values, they return 0 when the multiplication overflows and 1 when it does not.

• Separate functions for signed and unsigned multiplication, since they overflow under different circumstances.

Page 7: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Mul 1:• The strategy here is to exploit the fact that

register %eax is used to store the return value.• Assuming the compiler uses this register for

variable result, the first line will set the register to 0. The inline assembly will insert code that sets the low-order byte of this register appropriately, and the register will be used as the return value.

Page 8: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

• Instead of setting register %eax to 0 at the beginning of the function, the generated code does so at the very end, and so the function always returns 0.

• The fundamental problem is that the compiler has no way to know what the programmer’s intentions are, and how the assembly statement should interact with the rest of the generated code.

Page 9: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Mul 2:

• A less than ideal code, but working code:

Page 10: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

• Same strategy as before, but this time the code reads a global variable dummy to initialize result to 0.

• Compilers are more conservative about generating code involving global variables, and therefore less likely to rearrange the ordering of the computations.

• Even the above code depends on quirks of the compiler to get proper behavior. In fact, it only works when compiled with optimization enabled. Otherwise it stores result on the stack and retrieves its value just before returning.

Page 11: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Extended form of asm

• The extended version of the asm allows to specify– which program values are to be used as operands– which registers are overwritten by the assembly code.

• With this information the compiler can generate code that will correctly set up the required source values, execute the assembly instructions, and make use of the computed results.

• It will also have information it requires about register usage so that important program values are not overwritten by the assembly code instructions.

Page 12: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Extended form syntax• The general syntax of an extended assembly

sequence is as follows:asm ( code-string

: output operands /* optional */

: input operands /* optional */

: list of clobbered registers /* optional */ );

– code-string – the assembly code sequence.– output-operands– results generated by the assembly

code.– input-operands – source values for the assembly

code.– clobbered registers – inform gcc that the user will

use and modify these registers (in addition to i/o regs)

Page 13: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Extended form syntax

• It consists of a sequence of assembly code instructions separated by the semicolon (‘;’) character.

• Input and output operands are denoted by references %0, %1, and so on, up to possibly %9.

• Operands are numbered, according to their ordering first in the output list and then in the input list.

• Register names such as “%eax” must be written with an extra ‘%’ symbol, e.g., “%%eax.”

Page 14: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

num X 5asm ("leal (%1,%1,4), %0"

: "=r" (five_times_x)

: "r" (x) );

gcc will choose any input, output register

asm ("leal (%0,%0,4), %0"

: "=r" (five_times_x)

: "0" (x) );

User specifies input and output operands in the same register, any register

asm ("leal (%%ecx,%%ecx,4), %%ecx"

: "=c" (x)

: "c" (x) ); User specifies input and output operands in %ecx

Page 15: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Register operand constraint (r)

Memory operand constraint (m)

asm ("leal (%%ecx,%%ecx,4), %0" : "=m" (loc)

: "c" (x) ); The value 5x is stored in the memory location loc.

Page 16: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Mul 3:

Page 17: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

• First instruction: Store test result in the single-byte register %bl.• Second instruction: Zero-extend and copy value to whatever

register the compiler chooses to hold result, indicated by operand %0.

• Output list: Pairs of values– First element is operand type, ie., ‘r’ indicates an integer

register and ‘=’ indicates that the assembly code assigns a value to this operand.

– Second element is operand enclosed in parentheses. It can be any assignable value.

• Input list has the same general format.• Overwrite list gives the names of the registers that are

overwritten.• The code shown above works regardless of the

compilation flags.

Page 18: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Mul 4 (unsigned):

• We can’t use the same code since gcc use imull (signed multiply) instruction for both signed and unsigned multiplication.

• This generates the correct value for either product, but it sets the carry flag according to the rules for signed multiplication.

• Therefore, we must include an assembly code that performs unsigned multiplication using the mull instruction.

Page 19: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Unsigned Mul:

Page 20: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

Prob 3.39

• Given prototype:void full_umul(unsigned x, unsigned y, unsigned dest[]);

This function should compute the full 64-bit product of its arguments and store the results in the destination array, with dest[0] having low-order 4 bytes and dest[1] having high order 4 bytes.

Page 21: Inline Assembly Section 1: Recitation 7. In the early days of computing, most programs were written in assembly code. –Unmanageable because No type checking,

void full_umul(unsigned x, unsigned y, unsigned dest[])

{ asm(“movl %2,%%eax; mull %3; movl %%eax,%0; movl %%edx,%1”

: "=r" (dest[0]), "=r" (dest[1])

: "r" (x), "r" (y)

: "%eax", "%edx" ); }