举例:x指向的内存地址,其字节内容从低到高依次分别为c1,c2,c3,c4(Delphi读取一个integer的时候,结果是c4c3c2c1,其排列规则是"高高低低"),那么结果是c4,c3,c2,c1(Delphi读取一个integer的时候,结果是c1c2c3c4)
用delphi写的程序,把x指针指向的4个字节次序颠倒过来:
function toulong(x: pchar): longword; begin result := (longword(x^) shl 24) or (longword((x + 1)^) shl 16) or (longword((x + 2)^) shl 8) or (longword((x + 3)^)); end;
以下是用delphi的嵌入式汇编写法:
function toulong(x: pchar): longword; asm mov esi,eax // 读取x指针的值(也就是某一个内存地址)到esi(esi是通用寄存器,一般可以随便使用)。即esi=x mov ax,[esi] // 从这个内存地址里读取两个字节的内容到ax里。即ax=c2c1(注意,intel倒着吃) xchg ah,al // 把ax里两个字节位置交换一下。即ax=c1c2 shl eax,16 // 交换完以后左移到eax的高2位字节。即eax=c1c200 mov ax,[esi+2] // 把esi往后移动2个字节读取内存数据到ax里,即ax=c4c3(注意,intel倒着吃) xchg ah,al // 把ax里两个字节位置交换一下。即ax=c3c4。加上之前计算好的eax高2位字节,结果即此时eax=c1c2c3c4,如果写回内存的话,内存里的值从低到高依次为c4c3c2c1,但Delphi倒着吃,又会读出一个integer的数据为c1c2c3c4) end;
说明:默认情况下,delphi使用“register”方式,若参数在3个已内,将分别使用eax、edx和ecx,超过3个参数部分将使用堆栈。返回参数的存放视长度而定,例如8位用al返回,16位用ax,32位用eax,64位用用两个32位寄存器edx:eax,其中eax是低位。
效率:本例asm大约比delphi或c快50%。
======================================================
做了个Delphi程序验证:
procedure TForm1.Button3Click(Sender: TObject); var i: integer; p: PInteger; x: PChar; begin i:=$04030201; // 注意,只有这样,才会内存的值从低到高依次是01020304 p:=@i; ShowMessage(IntToStr(Integer(p^))); x:=pchar(p); ShowMessage(IntToStr(toulong(x))); end;
Hex 01020304 = Dec 16909060
Hex 04030201 = Dec 67305985
注意,观察这个的汇编代码,很有意思。
======================================================
再用VC写一遍,汇编代码主体都不必,就是改变了关于参数传递约定那部分
#include "stdafx.h" int toulong(char* p) { int fff; __asm { mov eax, p // EAX不再是第一个参数的值了,所以要自己写 mov esi,eax mov ax,[esi] xchg ah,al shl eax,16 mov ax,[esi+2] xchg ah,al mov fff, eax // EAX不再是自动的返回值了,所以要自己写 } return fff; } int main(int argc, char* argv[]) { int i=0x04030201; printf("after: %d ! ", i); int* p=&i; int j=toulong((char*)p); printf("after: %d ! ", j); return 0; }
===========================================
不清楚对象在内存里的排列是怎么个倒序。以后再研究。