i386.inc 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250
  1. {
  2. $Id$
  3. This file is part of the Free Pascal run time library.
  4. Copyright (c) 1999-2000 by the Free Pascal development team.
  5. Processor dependent implementation for the system unit for
  6. intel i386+
  7. See the file COPYING.FPC, included in this distribution,
  8. for details about the copyright.
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  12. **********************************************************************}
  13. {$asmmode ATT}
  14. {****************************************************************************
  15. Primitives
  16. ****************************************************************************}
  17. {$define FPC_SYSTEM_HAS_MOVE}
  18. procedure Move(const source;var dest;count:longint);assembler;
  19. asm
  20. movl dest,%edi
  21. movl source,%esi
  22. movl %edi,%eax
  23. movl count,%ebx
  24. { check for zero or negative count }
  25. cmpl $0,%ebx
  26. jle .LMoveEnd
  27. { Check for back or forward }
  28. sub %esi,%eax
  29. jz .LMoveEnd { Do nothing when source=dest }
  30. jc .LFMove { Do forward, dest<source }
  31. cmp %ebx,%eax
  32. jb .LBMove { Dest is in range of move, do backward }
  33. { Forward Copy }
  34. .LFMove:
  35. cld
  36. cmpl $15,%ebx
  37. jl .LFMove1
  38. movl %edi,%ecx { Align on 32bits }
  39. negl %ecx
  40. andl $3,%ecx
  41. subl %ecx,%ebx
  42. rep
  43. movsb
  44. movl %ebx,%ecx
  45. andl $3,%ebx
  46. shrl $2,%ecx
  47. rep
  48. movsl
  49. .LFMove1:
  50. movl %ebx,%ecx
  51. rep
  52. movsb
  53. jmp .LMoveEnd
  54. { Backward Copy }
  55. .LBMove:
  56. std
  57. addl %ebx,%esi
  58. addl %ebx,%edi
  59. movl %edi,%ecx
  60. decl %esi
  61. decl %edi
  62. cmpl $15,%ebx
  63. jl .LBMove1
  64. negl %ecx { Align on 32bits }
  65. andl $3,%ecx
  66. subl %ecx,%ebx
  67. rep
  68. movsb
  69. movl %ebx,%ecx
  70. andl $3,%ebx
  71. shrl $2,%ecx
  72. subl $3,%esi
  73. subl $3,%edi
  74. rep
  75. movsl
  76. addl $3,%esi
  77. addl $3,%edi
  78. .LBMove1:
  79. movl %ebx,%ecx
  80. rep
  81. movsb
  82. cld
  83. .LMoveEnd:
  84. end ['EAX','EBX','ECX','ESI','EDI'];
  85. {$define FPC_SYSTEM_HAS_FILLCHAR}
  86. Procedure FillChar(var x;count:longint;value:byte);
  87. { alias seems to be nowhere used? (JM)
  88. [public,alias: 'FPC_FILLCHAR']; }
  89. assembler;
  90. asm
  91. cld
  92. movl x,%edi
  93. movb value,%al
  94. movl count,%ecx
  95. { check for zero or negative count }
  96. cmpl $0,%ecx
  97. jle .LFillEnd
  98. cmpl $7,%ecx
  99. jl .LFill1
  100. movb %al,%ah
  101. movl %eax,%ebx
  102. shll $16,%eax
  103. movl %ecx,%edx
  104. movw %bx,%ax
  105. movl %edi,%ecx { Align on 32bits }
  106. negl %ecx
  107. andl $3,%ecx
  108. subl %ecx,%edx
  109. rep
  110. stosb
  111. movl %edx,%ecx
  112. andl $3,%edx
  113. shrl $2,%ecx
  114. rep
  115. stosl
  116. movl %edx,%ecx
  117. .LFill1:
  118. rep
  119. stosb
  120. .LFillEnd:
  121. end;
  122. {$define FPC_SYSTEM_HAS_FILLWORD}
  123. procedure fillword(var x;count : longint;value : word);assembler;
  124. asm
  125. movl x,%edi
  126. movl count,%ecx
  127. { check for zero or negative count }
  128. cmpl $0,%ecx
  129. jle .LFillWordEnd
  130. movzwl value,%eax
  131. movl %eax,%edx
  132. shll $16,%eax
  133. orl %edx,%eax
  134. movl %ecx,%edx
  135. shrl $1,%ecx
  136. cld
  137. rep
  138. stosl
  139. movl %edx,%ecx
  140. andl $1,%ecx
  141. rep
  142. stosw
  143. .LFillWordEnd:
  144. end ['EAX','ECX','EDX','EDI'];
  145. {$define FPC_SYSTEM_HAS_FILLDWORD}
  146. procedure filldword(var x;count : longint;value : dword);assembler;
  147. asm
  148. movl x,%edi
  149. movl count,%ecx
  150. { check for zero or negative count }
  151. cmpl $0,%ecx
  152. jle .LFillDWordEnd
  153. movl value,%eax
  154. cld
  155. rep
  156. stosl
  157. .LFillDWordEnd:
  158. end ['EAX','ECX','EDX','EDI'];
  159. {$define FPC_SYSTEM_HAS_INDEXBYTE}
  160. function IndexByte(Const buf;len:longint;b:byte):longint; assembler;
  161. asm
  162. xorl %eax,%eax
  163. movl Len,%ecx // Load len
  164. movl Buf,%edi // Load String
  165. testl %ecx,%ecx
  166. jz .Lready
  167. cld
  168. movl %ecx,%ebx // Copy for easy manipulation
  169. movb b,%al
  170. repne
  171. scasb
  172. jne .Lcharposnotfound
  173. incl %ecx
  174. subl %ecx,%ebx
  175. movl %ebx,%eax
  176. jmp .Lready
  177. .Lcharposnotfound:
  178. movl $-1,%eax
  179. .Lready:
  180. end ['EAX','EBX','ECX','EDI'];
  181. {$define FPC_SYSTEM_HAS_INDEXWORD}
  182. function Indexword(Const buf;len:longint;b:word):longint; assembler;
  183. asm
  184. xorl %eax,%eax
  185. movl Len,%ecx // Load len
  186. movl Buf,%edi // Load String
  187. testl %ecx,%ecx
  188. jz .Lready
  189. cld
  190. movl %ecx,%ebx // Copy for easy manipulation
  191. movw b,%ax
  192. repne
  193. scasw
  194. jne .Lcharposnotfound
  195. incl %ecx
  196. subl %ecx,%ebx
  197. movl %ebx,%eax
  198. jmp .Lready
  199. .Lcharposnotfound:
  200. movl $-1,%eax
  201. .Lready:
  202. end ['EAX','EBX','ECX','EDI'];
  203. {$define FPC_SYSTEM_HAS_INDEXDWORD}
  204. function IndexDWord(Const buf;len:longint;b:DWord):longint; assembler;
  205. asm
  206. xorl %eax,%eax
  207. movl Len,%ecx // Load len
  208. movl Buf,%edi // Load String
  209. testl %ecx,%ecx
  210. jz .Lready
  211. cld
  212. movl %ecx,%ebx // Copy for easy manipulation
  213. movl b,%eax
  214. repne
  215. scasl
  216. jne .Lcharposnotfound
  217. incl %ecx
  218. subl %ecx,%ebx
  219. movl %ebx,%eax
  220. jmp .Lready
  221. .Lcharposnotfound:
  222. movl $-1,%eax
  223. .Lready:
  224. end ['EAX','EBX','ECX','EDI'];
  225. {$define FPC_SYSTEM_HAS_COMPAREBYTE}
  226. function CompareByte(Const buf1,buf2;len:longint):longint; assembler;
  227. asm
  228. cld
  229. movl len,%eax
  230. movl buf2,%esi { Load params}
  231. movl buf1,%edi
  232. testl %eax,%eax {We address -1(%esi), so we have to deal with len=0}
  233. je .LCmpbyteExit
  234. cmpl $7,%eax {<7 not worth aligning and go through all trouble}
  235. jl .LCmpbyte2
  236. movl %edi,%ecx { Align on 32bits }
  237. negl %ecx { calc bytes to align (%edi and 3) xor 3= -%edi and 3}
  238. andl $3,%ecx
  239. subl %ecx,%eax { Subtract from number of bytes to go}
  240. orl %ecx,%ecx
  241. rep
  242. cmpsb {The actual 32-bit Aligning}
  243. jne .LCmpbyte3
  244. movl %eax,%ecx {bytes to do, divide by 4}
  245. andl $3,%eax {remainder}
  246. shrl $2,%ecx {The actual division}
  247. orl %ecx,%ecx {Sets zero flag if ecx=0 -> no cmp}
  248. rep
  249. cmpsl
  250. je .LCmpbyte2 { All equal? then to the left over bytes}
  251. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  252. subl %eax,%esi
  253. subl %eax,%edi
  254. .LCmpbyte2:
  255. movl %eax,%ecx {bytes still to (re)scan}
  256. orl %eax,%eax {prevent disaster in case %eax=0}
  257. rep
  258. cmpsb
  259. .LCmpbyte3:
  260. movzbl -1(%esi),%ecx
  261. movzbl -1(%edi),%eax // Compare failing (or equal) position
  262. subl %ecx,%eax
  263. .LCmpbyteExit:
  264. end ['ECX','EAX','ESI','EDI'];
  265. {$define FPC_SYSTEM_HAS_COMPAREWORD}
  266. function CompareWord(Const buf1,buf2;len:longint):longint; assembler;
  267. asm
  268. cld
  269. movl len,%eax
  270. movl buf2,%esi { Load params}
  271. movl buf1,%edi
  272. testl %eax,%eax {We address -2(%esi), so we have to deal with len=0}
  273. je .LCmpwordExit
  274. cmpl $5,%eax {<5 (3 bytes align + 4 bytes cmpsl = 4 words}
  275. jl .LCmpword2 { not worth aligning and go through all trouble}
  276. movl (%edi),%ebx // Compare alignment bytes.
  277. cmpl (%esi),%ebx
  278. jne .LCmpword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  279. shll $1,%eax {Convert word count to bytes}
  280. movl %edi,%edx { Align comparing is already done, so simply add}
  281. negl %edx { calc bytes to align -%edi and 3}
  282. andl $3,%edx
  283. addl %edx,%esi { Skip max 3 bytes alignment}
  284. addl %edx,%edi
  285. subl %edx,%eax { Subtract from number of bytes to go}
  286. movl %eax,%ecx { Make copy of bytes to go}
  287. andl $3,%eax { Calc remainder (mod 4) }
  288. andl $1,%edx { %edx is 1 if array not 2-aligned, 0 otherwise}
  289. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  290. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  291. rep { Compare entire DWords}
  292. cmpsl
  293. je .LCmpword2a { All equal? then to the left over bytes}
  294. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  295. subl %eax,%esi { Go back one DWord}
  296. subl %eax,%edi
  297. incl %eax {if not odd then this does nothing, else it makes
  298. sure that adding %edx increases from 2 to 3 words}
  299. .LCmpword2a:
  300. subl %edx,%esi { Subtract alignment}
  301. subl %edx,%edi
  302. addl %edx,%eax
  303. shrl $1,%eax
  304. .LCmpword2:
  305. movl %eax,%ecx {words still to (re)scan}
  306. orl %eax,%eax {prevent disaster in case %eax=0}
  307. rep
  308. cmpsw
  309. .LCmpword3:
  310. movzwl -2(%esi),%ecx
  311. movzwl -2(%edi),%eax // Compare failing (or equal) position
  312. subl %ecx,%eax // calculate end result.
  313. .LCmpwordExit:
  314. end ['EBX','EDX','ECX','EAX','ESI','EDI'];
  315. {$define FPC_SYSTEM_HAS_COMPAREDWORD}
  316. function CompareDWord(Const buf1,buf2;len:longint):longint; assembler;
  317. asm
  318. cld
  319. movl len,%eax
  320. movl buf2,%esi { Load params}
  321. movl buf1,%edi
  322. testl %eax,%eax {We address -2(%esi), so we have to deal with len=0}
  323. je .LCmpDwordExit
  324. cmpl $3,%eax {<3 (3 bytes align + 4 bytes cmpsl) = 2 DWords}
  325. jl .LCmpDword2 { not worth aligning and go through all trouble}
  326. movl (%edi),%ebx // Compare alignment bytes.
  327. cmpl (%esi),%ebx
  328. jne .LCmpDword2 // Aligning will go wrong already. Max 2 words will be scanned Branch NOW
  329. shll $2,%eax {Convert word count to bytes}
  330. movl %edi,%edx { Align comparing is already done, so simply add}
  331. negl %edx { calc bytes to align -%edi and 3}
  332. andl $3,%edx
  333. addl %edx,%esi { Skip max 3 bytes alignment}
  334. addl %edx,%edi
  335. subl %edx,%eax { Subtract from number of bytes to go}
  336. movl %eax,%ecx { Make copy of bytes to go}
  337. andl $3,%eax { Calc remainder (mod 4) }
  338. shrl $2,%ecx { divide bytes to go by 4, DWords to go}
  339. orl %ecx,%ecx { Sets zero flag if ecx=0 -> no cmp}
  340. rep { Compare entire DWords}
  341. cmpsl
  342. je .LCmpDword2a { All equal? then to the left over bytes}
  343. movl $4,%eax { Not equal. Rescan the last 4 bytes bytewise}
  344. subl %eax,%esi { Go back one DWord}
  345. subl %eax,%edi
  346. addl $3,%eax {if align<>0 this causes repcount to be 2}
  347. .LCmpDword2a:
  348. subl %edx,%esi { Subtract alignment}
  349. subl %edx,%edi
  350. addl %edx,%eax
  351. shrl $2,%eax
  352. .LCmpDword2:
  353. movl %eax,%ecx {words still to (re)scan}
  354. orl %eax,%eax {prevent disaster in case %eax=0}
  355. rep
  356. cmpsl
  357. .LCmpDword3:
  358. movzwl -4(%esi),%ecx
  359. movzwl -4(%edi),%eax // Compare failing (or equal) position
  360. subl %ecx,%eax // calculate end result.
  361. .LCmpDwordExit:
  362. end ['EBX','EDX','ECX','EAX','ESI','EDI'];
  363. {$define FPC_SYSTEM_HAS_INDEXCHAR0}
  364. function IndexChar0(Const buf;len:longint;b:Char):longint; assembler;
  365. asm
  366. // Can't use scasb, or will have to do it twice, think this
  367. // is faster for small "len"
  368. movl Buf,%esi // Load address
  369. movl len,%edx // load maximal searchdistance
  370. movzbl b,%ebx // Load searchpattern
  371. testl %edx,%edx
  372. je .LFound
  373. xorl %ecx,%ecx // zero index in Buf
  374. xorl %eax,%eax // To make DWord compares possible
  375. .LLoop:
  376. movb (%esi),%al // Load byte
  377. cmpb %al,%bl
  378. je .LFound // byte the same?
  379. incl %ecx
  380. incl %esi
  381. cmpl %edx,%ecx // Maximal distance reached?
  382. je .LNotFound
  383. testl %eax,%eax // Nullchar = end of search?
  384. jne .LLoop
  385. .LNotFound:
  386. movl $-1,%ecx // Not found return -1
  387. .LFound:
  388. movl %ecx,%eax
  389. end['EAX','EBX','ECX','EDX','ESI'];
  390. {****************************************************************************
  391. Object Helpers
  392. ****************************************************************************}
  393. {$ifndef HAS_GENERICCONSTRUCTOR}
  394. {$define FPC_SYSTEM_HAS_FPC_HELP_CONSTRUCTOR}
  395. procedure fpc_help_constructor; assembler; [public,alias:'FPC_HELP_CONSTRUCTOR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  396. asm
  397. { Entry without preamble, since we need the ESP of the constructor
  398. Stack (relative to %ebp):
  399. 12 Self
  400. 8 VMT-Address
  401. 4 main programm-Addr
  402. 0 %ebp
  403. edi contains the vmt position
  404. }
  405. { eax isn't touched anywhere, so it doesn't have to reloaded }
  406. movl 8(%ebp),%eax
  407. { initialise self ? }
  408. orl %esi,%esi
  409. jne .LHC_4
  410. { get memory, but save register first temporary variable }
  411. subl $4,%esp
  412. movl %esp,%esi
  413. { Save Register}
  414. pushal
  415. {$ifdef valuegetmem}
  416. { esi can be destroyed in fpc_getmem!!! (JM) }
  417. pushl %esi
  418. {$endif valuegetmem}
  419. { Memory size }
  420. pushl (%eax)
  421. {$ifdef valuegetmem}
  422. call fpc_getmem
  423. popl %esi
  424. movl %eax,(%esi)
  425. {$else valuegetmem}
  426. pushl %esi
  427. call AsmGetMem
  428. {$endif valuegetmem}
  429. movl $-1,8(%ebp)
  430. popal
  431. { Avoid 80386DX bug }
  432. nop
  433. { Memory position to %esi }
  434. movl (%esi),%esi
  435. addl $4,%esp
  436. { If no memory available : fail() }
  437. orl %esi,%esi
  438. jz .LHC_5
  439. { init self for the constructor }
  440. movl %esi,12(%ebp)
  441. { jmp not necessary anymore because next instruction is disabled (JM)
  442. jmp .LHC_6 }
  443. { Why was the VMT reset to zero here ????
  444. I need it fail to know if I should
  445. zero the VMT field in static objects PM }
  446. .LHC_4:
  447. { movl $0,8(%ebp) }
  448. .LHC_6:
  449. { is there a VMT address ? }
  450. orl %eax,%eax
  451. jnz .LHC_7
  452. { In case the constructor doesn't do anything, the Zero-Flag }
  453. { can't be put, because this calls Fail() }
  454. incl %eax
  455. ret
  456. .LHC_7:
  457. { set zero inside the object }
  458. pushal
  459. cld
  460. movl (%eax),%ecx
  461. movl %esi,%edi
  462. movl %ecx,%ebx
  463. xorl %eax,%eax
  464. shrl $2,%ecx
  465. andl $3,%ebx
  466. rep
  467. stosl
  468. movl %ebx,%ecx
  469. rep
  470. stosb
  471. popal
  472. { avoid the 80386DX bug }
  473. nop
  474. { set the VMT address for the new created object }
  475. { the offset is in %edi since the calling and has not been changed !! }
  476. movl %eax,(%esi,%edi,1)
  477. testl %eax,%eax
  478. .LHC_5:
  479. end;
  480. {$define FPC_SYSTEM_HAS_FPC_HELP_FAIL}
  481. procedure fpc_help_fail;assembler;[public,alias:'FPC_HELP_FAIL']; {$ifdef hascompilerproc} compilerproc; {$endif}
  482. { should be called with a object that needs to be
  483. freed if VMT field is at -1
  484. %edi contains VMT offset in object again }
  485. asm
  486. testl %esi,%esi
  487. je .LHF_1
  488. cmpl $-1,8(%ebp)
  489. je .LHF_2
  490. { reset vmt field to zero for static instances }
  491. cmpl $0,8(%ebp)
  492. je .LHF_3
  493. { main constructor, we can zero the VMT field now }
  494. movl $0,(%esi,%edi,1)
  495. .LHF_3:
  496. { we zero esi to indicate failure }
  497. xorl %esi,%esi
  498. jmp .LHF_1
  499. .LHF_2:
  500. { get vmt address in eax }
  501. movl (%esi,%edi,1),%eax
  502. movl %esi,12(%ebp)
  503. { push object position }
  504. {$ifdef valuefreemem}
  505. pushl %esi
  506. call fpc_freemem
  507. {$else valuefreemem}
  508. leal 12(%ebp),%eax
  509. pushl %eax
  510. call AsmFreeMem
  511. {$endif valuefreemem}
  512. { set both object places to zero }
  513. xorl %esi,%esi
  514. movl %esi,12(%ebp)
  515. .LHF_1:
  516. end;
  517. {$define FPC_SYSTEM_HAS_FPC_HELP_DESTRUCTOR}
  518. procedure fpc_help_destructor;assembler;[public,alias:'FPC_HELP_DESTRUCTOR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  519. asm
  520. { Stack (relative to %ebp):
  521. 12 Self
  522. 8 VMT-Address
  523. 4 Main program-Addr
  524. 0 %ebp
  525. edi contains the vmt position
  526. }
  527. pushal
  528. { Should the object be resolved ? }
  529. movl 8(%ebp),%eax
  530. orl %eax,%eax
  531. jz .LHD_3
  532. { Yes, get size from SELF! }
  533. movl 12(%ebp),%eax
  534. { get VMT-pointer (from Self) to %ebx }
  535. { the offset is in %edi since the calling and has not been changed !! }
  536. movl (%eax,%edi,1),%ebx
  537. { I think for precaution }
  538. { that we should clear the VMT here }
  539. movl $0,(%eax,%edi,1)
  540. {$ifdef valuefreemem}
  541. { Freemem }
  542. pushl %eax
  543. call fpc_freemem
  544. {$else valuefreemem}
  545. { temporary Variable }
  546. subl $4,%esp
  547. movl %esp,%edi
  548. { SELF }
  549. movl %eax,(%edi)
  550. pushl %edi
  551. call AsmFreeMem
  552. addl $4,%esp
  553. {$endif valuefreemem}
  554. .LHD_3:
  555. popal
  556. { avoid the 80386DX bug }
  557. nop
  558. end;
  559. {$define FPC_SYSTEM_HAS_FPC_NEW_CLASS}
  560. procedure fpc_new_class;assembler;[public,alias:'FPC_NEW_CLASS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  561. asm
  562. { to be sure in the future, we save also edit }
  563. pushl %edi
  564. { create class ? }
  565. movl 8(%ebp),%edi
  566. { if we test eax later without calling newinstance }
  567. { it must have a value <>0 }
  568. movl $1,%eax
  569. testl %edi,%edi
  570. jz .LNEW_CLASS1
  571. { save registers !! }
  572. pushl %ebx
  573. pushl %ecx
  574. pushl %edx
  575. { esi contains the vmt }
  576. pushl %esi
  577. { call newinstance (class method!) }
  578. call *52{vmtNewInstance}(%esi)
  579. popl %edx
  580. popl %ecx
  581. popl %ebx
  582. { newinstance returns a pointer to the new created }
  583. { instance in eax }
  584. { load esi and insert self }
  585. movl %eax,%esi
  586. .LNEW_CLASS1:
  587. movl %esi,8(%ebp)
  588. testl %eax,%eax
  589. popl %edi
  590. end;
  591. { Internal alias that can be reference from asm code }
  592. procedure int_dispose_class;external name 'FPC_DISPOSE_CLASS';
  593. {$define FPC_SYSTEM_HAS_FPC_DISPOSE_CLASS}
  594. procedure fpc_dispose_class;assembler;[public,alias:'FPC_DISPOSE_CLASS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  595. asm
  596. { to be sure in the future, we save also edit }
  597. pushl %edi
  598. { destroy class ? }
  599. movl 12(%ebp),%edi
  600. testl %edi,%edi
  601. jz .LDISPOSE_CLASS1
  602. { no inherited call }
  603. movl (%esi),%edi
  604. { save registers !! }
  605. pushl %eax
  606. pushl %ebx
  607. pushl %ecx
  608. pushl %edx
  609. { push self }
  610. pushl %esi
  611. { call freeinstance }
  612. call *56{vmtFreeInstance}(%edi)
  613. popl %edx
  614. popl %ecx
  615. popl %ebx
  616. popl %eax
  617. .LDISPOSE_CLASS1:
  618. popl %edi
  619. end;
  620. {$define FPC_SYSTEM_HAS_FPC_HELP_FAIL_CLASS}
  621. procedure fpc_help_fail_class;assembler;[public,alias:'FPC_HELP_FAIL_CLASS']; {$ifdef hascompilerproc} compilerproc; {$endif}
  622. { a non zero class must allways be disposed
  623. VMT is allways at pos 0 }
  624. asm
  625. testl %esi,%esi
  626. je .LHFC_1
  627. { can't use the compilerproc version as that will generate a
  628. reference instead of a symbol }
  629. call int_dispose_class
  630. { set both object places to zero }
  631. xorl %esi,%esi
  632. movl %esi,8(%ebp)
  633. .LHFC_1:
  634. end;
  635. {$define FPC_SYSTEM_HAS_FPC_CHECK_OBJECT}
  636. { we want the stack for debugging !! PM }
  637. procedure fpc_check_object(obj : pointer);[public,alias:'FPC_CHECK_OBJECT']; {$ifdef hascompilerproc} compilerproc; {$endif}
  638. begin
  639. asm
  640. pushl %edi
  641. movl obj,%edi
  642. pushl %eax
  643. { Here we must check if the VMT pointer is nil before }
  644. { accessing it... }
  645. testl %edi,%edi
  646. jz .Lco_re
  647. movl (%edi),%eax
  648. addl 4(%edi),%eax
  649. jz .Lco_ok
  650. .Lco_re:
  651. pushl $210
  652. call HandleError
  653. .Lco_ok:
  654. popl %eax
  655. popl %edi
  656. { the adress is pushed : it needs to be removed from stack !! PM }
  657. end;{ of asm }
  658. end;
  659. {$define FPC_SYSTEM_HAS_FPC_CHECK_OBJECT_EXT}
  660. procedure fpc_check_object_ext;assembler;[public,alias:'FPC_CHECK_OBJECT_EXT']; {$ifdef hascompilerproc} compilerproc; {$endif}
  661. { checks for a correct vmt pointer }
  662. { deeper check to see if the current object is }
  663. { really related to the true }
  664. asm
  665. pushl %ebp
  666. movl %esp,%ebp
  667. pushl %edi
  668. movl 8(%ebp),%edi
  669. pushl %ebx
  670. movl 12(%ebp),%ebx
  671. pushl %eax
  672. { Here we must check if the VMT pointer is nil before }
  673. { accessing it... }
  674. .Lcoext_obj:
  675. testl %edi,%edi
  676. jz .Lcoext_re
  677. movl (%edi),%eax
  678. addl 4(%edi),%eax
  679. jnz .Lcoext_re
  680. cmpl %edi,%ebx
  681. je .Lcoext_ok
  682. .Lcoext_vmt:
  683. movl 8(%edi),%eax
  684. cmpl %ebx,%eax
  685. je .Lcoext_ok
  686. movl %eax,%edi
  687. jmp .Lcoext_obj
  688. .Lcoext_re:
  689. pushl $219
  690. call HandleError
  691. .Lcoext_ok:
  692. popl %eax
  693. popl %ebx
  694. popl %edi
  695. { the adress and vmt were pushed : it needs to be removed from stack !! PM }
  696. popl %ebp
  697. ret $8
  698. end;
  699. {$endif HAS_GENERICCONSTRUCTOR}
  700. {****************************************************************************
  701. String
  702. ****************************************************************************}
  703. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_ASSIGN}
  704. function fpc_shortstr_to_shortstr(len:longint; const sstr: shortstring): shortstring; [public,alias: 'FPC_SHORTSTR_TO_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  705. begin
  706. asm
  707. cld
  708. movl __RESULT,%edi
  709. movl sstr,%esi
  710. xorl %eax,%eax
  711. movl len,%ecx
  712. lodsb
  713. cmpl %ecx,%eax
  714. jbe .LStrCopy1
  715. movl %ecx,%eax
  716. .LStrCopy1:
  717. stosb
  718. cmpl $7,%eax
  719. jl .LStrCopy2
  720. movl %edi,%ecx { Align on 32bits }
  721. negl %ecx
  722. andl $3,%ecx
  723. subl %ecx,%eax
  724. rep
  725. movsb
  726. movl %eax,%ecx
  727. andl $3,%eax
  728. shrl $2,%ecx
  729. rep
  730. movsl
  731. .LStrCopy2:
  732. movl %eax,%ecx
  733. rep
  734. movsb
  735. end ['ESI','EDI','EAX','ECX'];
  736. end;
  737. {$ifdef interncopy}
  738. procedure fpc_shortstr_assign(len:longint;sstr,dstr:pointer);[public,alias:'FPC_SHORTSTR_ASSIGN'];
  739. {$else}
  740. procedure fpc_shortstr_copy(len:longint;sstr,dstr:pointer);[public,alias:'FPC_SHORTSTR_COPY'];
  741. {$endif}
  742. begin
  743. asm
  744. pushl %eax
  745. pushl %ecx
  746. cld
  747. movl dstr,%edi
  748. movl sstr,%esi
  749. xorl %eax,%eax
  750. movl len,%ecx
  751. lodsb
  752. cmpl %ecx,%eax
  753. jbe .LStrCopy1
  754. movl %ecx,%eax
  755. .LStrCopy1:
  756. stosb
  757. cmpl $7,%eax
  758. jl .LStrCopy2
  759. movl %edi,%ecx { Align on 32bits }
  760. negl %ecx
  761. andl $3,%ecx
  762. subl %ecx,%eax
  763. rep
  764. movsb
  765. movl %eax,%ecx
  766. andl $3,%eax
  767. shrl $2,%ecx
  768. rep
  769. movsl
  770. .LStrCopy2:
  771. movl %eax,%ecx
  772. rep
  773. movsb
  774. popl %ecx
  775. popl %eax
  776. end ['ESI','EDI'];
  777. end;
  778. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_CONCAT}
  779. {$ifdef hascompilerproc}
  780. { define a dummy fpc_shortstr_concat for i386. Only the next one }
  781. { is really used by the compiler, but the compilerproc forward }
  782. { definition must still be fulfilled (JM) }
  783. function fpc_shortstr_concat(const s1,s2: shortstring): shortstring; compilerproc;
  784. begin
  785. { avoid warning }
  786. fpc_shortstr_concat := '';
  787. runerror(216);
  788. end;
  789. {$endif hascompilerproc}
  790. procedure fpc_shortstr_concat_intern(const s1, s2:shortstring);
  791. [public,alias:'FPC_SHORTSTR_CONCAT'];
  792. begin
  793. asm
  794. movl s2,%edi
  795. movl s1,%esi
  796. movl %edi,%ebx
  797. movzbl (%edi),%ecx
  798. xor %eax,%eax
  799. lea 1(%edi,%ecx),%edi
  800. negl %ecx
  801. addl $0x0ff,%ecx
  802. lodsb
  803. cmpl %ecx,%eax
  804. jbe .LStrConcat1
  805. movl %ecx,%eax
  806. .LStrConcat1:
  807. addb %al,(%ebx)
  808. cmpl $7,%eax
  809. jl .LStrConcat2
  810. movl %edi,%ecx { Align on 32bits }
  811. negl %ecx
  812. andl $3,%ecx
  813. subl %ecx,%eax
  814. rep
  815. movsb
  816. movl %eax,%ecx
  817. andl $3,%eax
  818. shrl $2,%ecx
  819. rep
  820. movsl
  821. .LStrConcat2:
  822. movl %eax,%ecx
  823. rep
  824. movsb
  825. end ['EBX','ECX','EAX','ESI','EDI'];
  826. end;
  827. {$define FPC_SYSTEM_HAS_FPC_SHORTSTR_COMPARE}
  828. function fpc_shortstr_compare(const dstr,sstr:shortstring): longint; [public,alias:'FPC_SHORTSTR_COMPARE']; {$ifdef hascompilerproc} compilerproc; {$endif}
  829. begin
  830. asm
  831. cld
  832. xorl %ebx,%ebx
  833. xorl %eax,%eax
  834. movl sstr,%esi
  835. movl dstr,%edi
  836. movb (%esi),%al
  837. movb (%edi),%bl
  838. movl %eax,%edx
  839. incl %esi
  840. incl %edi
  841. cmpl %ebx,%eax
  842. jbe .LStrCmp1
  843. movl %ebx,%eax
  844. .LStrCmp1:
  845. cmpl $7,%eax
  846. jl .LStrCmp2
  847. movl %edi,%ecx { Align on 32bits }
  848. negl %ecx
  849. andl $3,%ecx
  850. subl %ecx,%eax
  851. orl %ecx,%ecx
  852. rep
  853. cmpsb
  854. jne .LStrCmp3
  855. movl %eax,%ecx
  856. andl $3,%eax
  857. shrl $2,%ecx
  858. orl %ecx,%ecx
  859. rep
  860. cmpsl
  861. je .LStrCmp2
  862. movl $4,%eax
  863. sub %eax,%esi
  864. sub %eax,%edi
  865. .LStrCmp2:
  866. movl %eax,%ecx
  867. orl %eax,%eax
  868. rep
  869. cmpsb
  870. jne .LStrCmp3
  871. cmp %ebx,%edx
  872. .LStrCmp3:
  873. end ['EDX','ECX','EBX','EAX','ESI','EDI'];
  874. end;
  875. {$define FPC_SYSTEM_HAS_FPC_PCHAR_TO_SHORTSTR}
  876. function fpc_pchar_to_shortstr(p:pchar):shortstring;[public,alias:'FPC_PCHAR_TO_SHORTSTR']; {$ifdef hascompilerproc} compilerproc; {$endif}
  877. {$include strpas.inc}
  878. {$define FPC_SYSTEM_HAS_FPC_PCHAR_LENGTH}
  879. function fpc_pchar_length(p:pchar):longint;assembler;[public,alias:'FPC_PCHAR_LENGTH']; {$ifdef hascompilerproc} compilerproc; {$endif}
  880. {$include strlen.inc}
  881. {$define FPC_SYSTEM_HAS_GET_FRAME}
  882. function get_frame:pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  883. asm
  884. movl %ebp,%eax
  885. end ['EAX'];
  886. {$define FPC_SYSTEM_HAS_GET_CALLER_ADDR}
  887. function get_caller_addr(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  888. asm
  889. movl framebp,%eax
  890. orl %eax,%eax
  891. jz .Lg_a_null
  892. movl 4(%eax),%eax
  893. .Lg_a_null:
  894. end ['EAX'];
  895. {$define FPC_SYSTEM_HAS_GET_CALLER_FRAME}
  896. function get_caller_frame(framebp:pointer):pointer;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  897. asm
  898. movl framebp,%eax
  899. orl %eax,%eax
  900. jz .Lgnf_null
  901. movl (%eax),%eax
  902. .Lgnf_null:
  903. end ['EAX'];
  904. {****************************************************************************
  905. Math
  906. ****************************************************************************}
  907. {$define FPC_SYSTEM_HAS_ABS_LONGINT}
  908. function abs(l:longint):longint; assembler;{$ifdef SYSTEMINLINE}inline;{$endif}[internconst:in_const_abs];
  909. asm
  910. movl l,%eax
  911. cltd
  912. xorl %edx,%eax
  913. subl %edx,%eax
  914. end ['EAX','EDX'];
  915. {$define FPC_SYSTEM_HAS_ODD_LONGINT}
  916. function odd(l:longint):boolean;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}[internconst:in_const_odd];
  917. asm
  918. movl l,%eax
  919. andl $1,%eax
  920. setnz %al
  921. end ['EAX'];
  922. {$define FPC_SYSTEM_HAS_SQR_LONGINT}
  923. function sqr(l:longint):longint;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}[internconst:in_const_sqr];
  924. asm
  925. mov l,%eax
  926. imull %eax,%eax
  927. end ['EAX'];
  928. {$define FPC_SYSTEM_HAS_SPTR}
  929. Function Sptr : Longint;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  930. asm
  931. movl %esp,%eax
  932. end;
  933. {****************************************************************************
  934. Str()
  935. ****************************************************************************}
  936. {$define FPC_SYSTEM_HAS_INT_STR_LONGINT}
  937. procedure int_str(l : longint;var s : string);
  938. var
  939. buffer : array[0..11] of byte;
  940. begin
  941. { Workaround: }
  942. if l=$80000000 then
  943. begin
  944. s:='-2147483648';
  945. exit;
  946. end;
  947. asm
  948. movl l,%eax // load Integer
  949. movl s,%edi // Load String address
  950. xorl %ecx,%ecx // String length=0
  951. xorl %ebx,%ebx // Buffer length=0
  952. movl $0x0a,%esi // load 10 as dividing constant.
  953. orl %eax,%eax // Sign ?
  954. jns .LM2
  955. neg %eax
  956. movb $0x2d,1(%edi) // put '-' in String
  957. incl %ecx
  958. .LM2:
  959. cltd
  960. idivl %esi
  961. addb $0x30,%dl // convert Rest to ASCII.
  962. movb %dl,-12(%ebp,%ebx)
  963. incl %ebx
  964. cmpl $0,%eax
  965. jnz .LM2
  966. { copy String }
  967. .LM3:
  968. movb -13(%ebp,%ebx),%al // -13 because EBX is decreased only later
  969. movb %al,1(%edi,%ecx)
  970. incl %ecx
  971. decl %ebx
  972. jnz .LM3
  973. movb %cl,(%edi) // Copy String length
  974. end;
  975. end;
  976. {$define FPC_SYSTEM_HAS_INT_STR_LONGWORD}
  977. procedure int_str(c : longword;var s : string);
  978. var
  979. buffer : array[0..14] of byte;
  980. begin
  981. asm
  982. movl c,%eax // load CARDINAL
  983. movl s,%edi // Load String address
  984. xorl %ecx,%ecx // String length=0
  985. xorl %ebx,%ebx // Buffer length=0
  986. movl $0x0a,%esi // load 10 as dividing constant.
  987. .LM4:
  988. xorl %edx,%edx
  989. divl %esi
  990. addb $0x30,%dl // convert Rest to ASCII.
  991. movb %dl,-12(%ebp,%ebx)
  992. incl %ebx
  993. cmpl $0,%eax
  994. jnz .LM4
  995. { now copy the string }
  996. .LM5:
  997. movb -13(%ebp,%ebx),%al // -13 because EBX is decreased only later
  998. movb %al,1(%edi,%ecx)
  999. incl %ecx
  1000. decl %ebx
  1001. jnz .LM5
  1002. movb %cl,(%edi) // Copy String length
  1003. end;
  1004. end;
  1005. {****************************************************************************
  1006. Bounds Check
  1007. ****************************************************************************}
  1008. {$ifndef NOBOUNDCHECK}
  1009. procedure int_boundcheck;assembler;[public,alias: 'FPC_BOUNDCHECK'];
  1010. var dummy_to_force_stackframe_generation_for_trace: Longint;
  1011. {
  1012. called with:
  1013. %ecx - value
  1014. %edi - pointer to the ranges
  1015. }
  1016. asm
  1017. cmpl (%edi),%ecx
  1018. jl .Lbc_err
  1019. cmpl 4(%edi),%ecx
  1020. jle .Lbc_ok
  1021. .Lbc_err:
  1022. pushl %ebp
  1023. pushl $201
  1024. call HandleErrorFrame
  1025. .Lbc_ok:
  1026. end;
  1027. {$endif NOBOUNDCHECK}
  1028. { do a thread save inc/dec }
  1029. {$define FPC_SYSTEM_HAS_DECLOCKED}
  1030. function declocked(var l : longint) : boolean;assembler;
  1031. asm
  1032. movl l,%edi
  1033. { this check should be done because a lock takes a lot }
  1034. { of time! }
  1035. cmpb $0,IsMultithread
  1036. jz .Ldeclockednolock
  1037. lock
  1038. decl (%edi)
  1039. jmp .Ldeclockedend
  1040. .Ldeclockednolock:
  1041. decl (%edi);
  1042. .Ldeclockedend:
  1043. setzb %al
  1044. end ['EDI','EAX'];
  1045. {$define FPC_SYSTEM_HAS_INCLOCKED}
  1046. procedure inclocked(var l : longint);assembler;
  1047. asm
  1048. movl l,%edi
  1049. { this check should be done because a lock takes a lot }
  1050. { of time! }
  1051. cmpb $0,IsMultithread
  1052. jz .Linclockednolock
  1053. lock
  1054. incl (%edi)
  1055. jmp .Linclockedend
  1056. .Linclockednolock:
  1057. incl (%edi)
  1058. .Linclockedend:
  1059. end ['EDI'];
  1060. {****************************************************************************
  1061. FPU
  1062. ****************************************************************************}
  1063. const
  1064. fpucw : word = $1332;
  1065. { Internal constants for use in system unit }
  1066. FPU_Invalid = 1;
  1067. FPU_Denormal = 2;
  1068. FPU_DivisionByZero = 4;
  1069. FPU_Overflow = 8;
  1070. FPU_Underflow = $10;
  1071. FPU_StackUnderflow = $20;
  1072. FPU_StackOverflow = $40;
  1073. FPU_ExceptionMask = $ff;
  1074. {$define FPC_SYSTEM_HAS_SYSRESETFPU}
  1075. Procedure SysResetFPU;assembler;{$ifdef SYSTEMINLINE}inline;{$endif}
  1076. asm
  1077. fninit
  1078. fldcw fpucw
  1079. end;
  1080. {
  1081. $Log$
  1082. Revision 1.41 2003-03-26 00:19:10 peter
  1083. * ifdef HAS_GENERICCONSTRUCTOR
  1084. Revision 1.40 2003/03/17 14:30:11 peter
  1085. * changed address parameter/return values to pointer instead
  1086. of longint
  1087. Revision 1.39 2003/02/18 17:56:06 jonas
  1088. - removed buggy i386-specific FPC_CHARARRAY_TO_SHORTSTR
  1089. * fixed generic FPC_CHARARRAY_TO_SHORTSTR (web bug 2382)
  1090. * fixed some potential range errors in indexchar/word/dword
  1091. Revision 1.38 2003/01/06 23:03:13 mazen
  1092. + defining FPC_SYSTEM_HAS_DECLOCKED and FPC_SYSTEM_HAS_INCLOCKED to avoid
  1093. compilation error on generic.inc
  1094. Revision 1.37 2003/01/03 17:14:54 peter
  1095. * fix possible overflow when array len > 255 when converting to
  1096. shortstring
  1097. Revision 1.36 2002/12/15 22:32:25 peter
  1098. * fixed return value when len=0 for indexchar,indexword
  1099. Revision 1.35 2002/10/20 11:50:57 carl
  1100. * avoid crashes with negative len counts on fills/moves
  1101. Revision 1.34 2002/10/15 19:24:47 carl
  1102. * Replace 220 -> 219
  1103. Revision 1.33 2002/10/14 19:39:16 peter
  1104. * threads unit added for thread support
  1105. Revision 1.32 2002/10/05 14:20:16 peter
  1106. * fpc_pchar_length compilerproc and strlen alias
  1107. Revision 1.31 2002/10/02 18:21:51 peter
  1108. * Copy() changed to internal function calling compilerprocs
  1109. * FPC_SHORTSTR_COPY renamed to FPC_SHORTSTR_ASSIGN because of the
  1110. new copy functions
  1111. Revision 1.30 2002/09/07 21:33:35 carl
  1112. - removed unused defines
  1113. Revision 1.29 2002/09/07 16:01:19 peter
  1114. * old logs removed and tabs fixed
  1115. Revision 1.28 2002/09/03 15:43:36 peter
  1116. * add alias for fpc_dispose_class so it can be called from
  1117. fpc_help_fail_class
  1118. Revision 1.27 2002/08/19 19:34:02 peter
  1119. * SYSTEMINLINE define that will add inline directives for small
  1120. functions and wrappers. This will be defined automaticly when
  1121. the compiler defines the HASINLINE directive
  1122. Revision 1.26 2002/07/26 15:45:33 florian
  1123. * changed multi threading define: it's MT instead of MTRTL
  1124. Revision 1.25 2002/07/06 20:31:59 carl
  1125. + added TEST_GENERIC to test generic version
  1126. Revision 1.24 2002/06/16 08:21:26 carl
  1127. + TEST_GENERIC to test generic versions of code
  1128. Revision 1.23 2002/06/09 12:54:37 jonas
  1129. * fixed memory corruption bug in fpc_help_constructor
  1130. Revision 1.22 2002/04/21 18:56:59 peter
  1131. * fpc_freemem and fpc_getmem compilerproc
  1132. Revision 1.21 2002/04/01 14:23:17 carl
  1133. - no need for runerror 203, already fixed!
  1134. Revision 1.20 2002/03/30 14:52:04 carl
  1135. * cause runtime error 203 on failed class creation
  1136. }