ptrtohandle.s 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. | This routine returns the HANDLE of the block containing the address
  2. | where the given pointer points to, or H_NULL if there's no such block.
  3. |
  4. | This routine is NOT a duplicate of HeapPtrToHandle: unlike HeapPtrToHandle,
  5. | PtrToHandle can meaningfully handle pointers that do not point to the
  6. | beginning of the block.
  7. | Kernels have provided PtrToHandle for years as "Ptr2Hd".
  8. |
  9. | Copyright (C) Lionel Debroux 2003 (contribution to TIGCC)
  10. | Copyright (C) Lionel Debroux 2009 (rename, modifications & integration to GCC4TI).
  11. |
  12. | Equivalent C code:
  13. /*
  14. HANDLE PtrToHandle(void *ptr asm("d0"))
  15. {
  16. HANDLE h = H_NULL;
  17. void *ptr2;
  18. while (h < 2000)
  19. {
  20. h++;
  21. ptr2 = HeapDeref(h);
  22. if (ptr >= ptr2 && (unsigned char *)ptr < (unsigned char *)ptr2 + HeapSize(h)) return h;
  23. }
  24. return H_NULL;
  25. }
  26. */
  27. .text
  28. .even
  29. .globl PtrToHandle
  30. PtrToHandle:
  31. movem.l %d3-%d4/%a2-%a4,-(%sp)
  32. | Save the pointer into non-call-clobbered a2.
  33. movea.l %a0,%a2
  34. | Put the addresses of HeapDeref and HeapSize in the registers.
  35. movea.l 0xC8.w,%a4
  36. movea.l 0x96*4(%a4),%a3 | HeapDeref.
  37. movea.l 0x9E*4(%a4),%a4 | HeapSize.
  38. | We'll check handles 1-1999 in ascending order, because:
  39. | * HeapSize(H_NULL) crashes the calculator;
  40. | * since handles are allocated in ascending order, pointers pointing to an
  41. | allocated memory area will be found more quickly.
  42. | Checking the handles in ascending order yields a larger routine, though.
  43. clr.w -(%sp)
  44. move.w #2000,%d3
  45. .L__PtrToHandle_loop:
  46. | In theory, we should re-create the argument each time HeapDeref is called and each time HeapSize is called.
  47. | This is because callees, among which AMS functions, _can_ destroy their stack arguments...
  48. | Neither HeapDeref nor HeapSize has ever done so, be it on AMS (discontinued) or PedroM (which behaves the
  49. | same way as AMS does, for compatibility and implementation sanity reasons).
  50. addq.w #1,(%sp)
  51. cmp.w (%sp),%d3
  52. beq.s .L__PtrToHandle_not_found
  53. | We've not run out of the heap table yet.
  54. jsr (%a3) | HeapDeref.
  55. | If this handle is not allocated, skip it, so as not to emulate the bug of HeapPtrToHandle(NULL) returning
  56. | the index of the first free entry in the heap table (instead of H_NULL, which would make more sense, as NULL
  57. | doesn't belong to any block). This matches the behaviour of kernel::Ptr2Hd.
  58. move.l %a0,%d4
  59. beq.s .L__PtrToHandle_loop
  60. | If a2 < the lowest address of the current handle, the current handle is not the one we're looking for.
  61. cmpa.l %d4,%a2
  62. blt.s .L__PtrToHandle_loop
  63. | a2 >= the lowest address of the current handle.
  64. jsr (%a4) | HeapSize.
  65. add.l %d0,%d4
  66. | If a2 >= the lowest address and < the highest address, the current handle is the one we're looking for.
  67. cmp.l %a2,%d4
  68. blt.s .L__PtrToHandle_loop
  69. | Found the handle.
  70. move.w (%sp)+,%d0
  71. .L__PtrToHandle_end:
  72. movem.l (%sp)+,%d3-%d4/%a2-%a4
  73. rts
  74. | The whole heap table was traversed, but no handle was found. Return H_NULL.
  75. .L__PtrToHandle_not_found:
  76. moveq #0,%d0
  77. addq.l #2,%sp
  78. bra.s .L__PtrToHandle_end