打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
BASM for beginners, lesson 1
BASM for beginners, lesson 1

This series of lessons is dedicated to teach beginners BASM.

Instead of doing a book with chapters about instructions, Calling conventions & code optimization etc., we will be discussing the issues as examples bring them into focus.

The first little example gets us started. It is a simple function in Pascal with multiplies an integer with the constant 2.

function MulInt2(I : Integer) : Integer;

begin
 Result := I * 2;
end;

Let us steal the BASM from the CPU view. I compiled with optimizations turned on.

function MulInt2_BASM(I : Integer) : Integer;

begin
 Result := I * 2;
  {
  add eax,eax
 ret
 }
end;

From this we see that I is transferred to the function in eax and that the result is transferred back to the caller in eax too. This is the conventions for the register calling convention which is the default in Delphi. The actual code is very simple. The times 2 multiplication is obtained by adding I to itself, I+I = 2I. The ret instruction returns execution to the line after the one which called the function.

Let us code the function as a pure asm function.

function MulInt2_BASM2(I : Integer) : Integer;

asm
 //Result := I * 2;
  add eax,eax
 //ret
end;

Observe that the ret function is supplied by the inline assembler.

Let us take a look at the calling code.

This is the Pascal code

procedure TForm1.Button1Click(Sender: TObject);

var

 I, J : Integer;

begin
 I := StrToInt(IEdit.Text);
  J := MulInt2_BASM2(I);
  JEdit.Text := IntToStr(J);
end;

The important line is

J := MulInt2_BASM2(I);

from the cpu view

call  StrToInt

call MulInt2_BASM2

mov esi,eax

After the call to StrToInt from the line before the one which calls our function, I is in eax. (StrToInt is also following the register calling convention). MulInt2_BASM2 is called and returns the result in eax which is copied to esi in the next line.

Optimization issues: Multiplication by 2 can be done in two more ways. Using the mul instruction or shifting left by one. In the IA32 Intel Architecture Software Developer’s Manual Volume 2 – Instruction Set Reference page 536  mul is described. It multiplies the value in  eax by the value held in another register and the result is returned in the register pair edx:eax. A register pair is needed because a multiplication of two 32 bit numbers results in a 64 bit result, just like 9*9=81 - two one digit numbers (can) result in a two digit result.

Because edx gets into use the issue of which registers must be preserved by a function and which can be used freely is raised. This is explained in the Delphi help.

"An asm statement must preserve the EDI, ESI, ESP, EBP, and EBX registers, but can freely modify the EAX, ECX, and EDX registers."

We can conclude that it is no problem that edx is modified by the  mul instruction and our function can also be implemented like this.

function MulInt2_BASM3(I : Integer) : Integer;

asm
 //Result := I * 2;
  mov ecx, 2
  mul ecx
end;

ecx is used also but this is also ok. As long as the result is less than the range of integer it is returned correctly in eax. If I is bigger than half the range of integer, overflow will occur and the result is incorrect.

Implementation with shift

function MulInt2_BASM4(I : Integer) : Integer;

asm
 //Result := I * 2;
  shl eax,1
end;

Timing can reveal which implementation is fastest. We can also consult Intel and AMD documents with latency and throughput tables. On P4 add & mov are 0.5 clock cycles latency and throughput, mul is 14-18 cycles latency and 5 cycles throughput. Shl is 4 clock cycles latency and 1 cycle throughput. The version chosen by Delphi is the most efficient on P4 and this will probably also be the case on Athlon and P3.

Issues not covered: mul versus imul and range checking, other calling conventions, benchmarking, clock count on other processors, clock count for call + ret, location of return address for ret etc. Later lessons will introduce these subjects.
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
Inline Assembler in Delphi (VI) Calling external procedures
GNU Assembler Examples
Declaring Procedure Parameters with the PROC Directive Calling Procedures with the INVOKE Directive
Debug Tutorial Part 2: The Stack
【转】【转】Shell 编程中的函数返回值
论函数调用约定
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服