2012-04-02 20 views
8

Tôi đang làm việc với một số chức năng trampoline để sử dụng với mức gọi cao hơn trong C/Objective-C, một chút xoắn trên đường Apple does it.Xóa đối số khỏi ngăn xếp trong i386, lắp ráp ARM

Nếu bạn quen thuộc với cách Objective-C IMP hoạt động, về cơ bản nó là một con trỏ hàm trong đó hai đối số đầu tiên là người nhận thư và tên của bộ chọn thư, chẳng hạn như void(*)(id obj, SEL sel, ...). Các phiên bản gần đây của thời gian chạy cho phép triển khai phương pháp được tổng hợp tại thời gian chạy bằng cách sử dụng các khối C, như void(^)(id obj, ...). Những khối này không có bộ chọn; thời gian chạy tạo ra một tấm bạt lò xo ghi đè lên bộ chọn với người nhận, người nhận với con trỏ khối, và sau đó di chuyển trên thực hiện nó.

Tôi muốn làm điều gì đó mơ hồ tương tự như không có hoặc là trong hai đối số đầu tiên, để đối số cho khối này giống hệt như đối số của phương thức truyền thống gửi. mục đích, ví dụ: void(*)(Block *, ...). Điều này đòi hỏi chỉ sao chép trong con trỏ khối, và tôi cho rằng loại bỏ một đối số.

__a1a2_tramphead_argonly: 
    popl %eax 
    andl $0xFFFFFFF8, %eax 
    subl $0x1000, %eax 
    movl 4(%esp), %ecx // self -> ecx 
    movl %ecx, 8(%esp) // ecx -> _cmd 
    movl (%eax), %ecx // blockPtr -> ecx 
    movl %ecx, 4(%esp) // ecx -> self 
    jmp *12(%ecx) // tail to block->invoke 

Đây là lắp ráp Tôi có trên ARM:

__a1a2_tramphead_argonly: 
    // calculate the trampoline's index (512 entries, 8 bytes each) 
#ifdef _ARM_ARCH_7 
    // PC bias is only 4, no need to correct with 8-byte trampolines 
    ubfx r1, r1, #3, #9 
#else 
    sub r1, r1, #8    // correct PC bias 
    lsl r1, r1, #20 
    lsr r1, r1, #23 
#endif 

    // load block pointer from trampoline's data 
    adr r12, __a1a2_tramphead_argonly // text page 
    sub r12, r12, #4096   // data page precedes text page 
    ldr r12, [r12, r1, LSL #3] // load block pointer from data + index*8 

    // shuffle parameters 
    mov r1, r0     // _cmd = self 
    mov r0, r12     // self = block pointer 

    // tail call block->invoke 
    ldr pc, [r12, #12] 

đang tương tự tồn tại cho x86_64; mã ở trên là như vậy đến nay trực tiếp từ Apple. Đối với kiến ​​thức cá nhân, tôi tự hỏi bắt đầu từ đâu với một cuộc tranh luận, để đối số đầu tiên (cái được sử dụng để là người nhận) là khối chữ, thứ hai là đối số thực đầu tiên, v.v.

Tôi cực kỳ ngớ ngẩn với ASM, vì vậy mọi trợ giúp đều được đánh giá cao. Tất cả mọi thứ tôi đã cố gắng đã thổi lên theo những cách ngày càng thú vị. Cảm ơn trước.

+1

Hãy cẩn thận, nhiều bản phân phối Linux hiện đang trong quá trình di chuyển đến ABI nổi cứng của ARM. Điều đó sẽ hoàn toàn phá vỡ mọi thứ cho bạn, một lần nữa. – ams

+0

Thật thú vị, tôi sẽ ghi nhớ điều đó trong tương lai. Điều này chủ yếu nhắm vào Darwin, tuy nhiên. Cảm ơn bạn! Chỉnh sửa: Điều đó có nghĩa là ARMV6 và ARMV7, ít nhất là trong thời gian này. – zwaldowski

Trả lời

2

iOS ABI kết hợp hiệu quả AAPCS và chỉ xác định sự khác biệt, vì vậy bạn sẽ muốn bắt đầu với http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ihi0042d/index.html trước tiên. Sau đó đọc Hướng dẫn gọi chức năng iOS ABI của Apple (tôi nghĩ bạn cần một thành viên Trung tâm Dev của iOS trả phí để truy cập).

Tóm tắt các quy tắc, để gọi một ObjC IMP:

  • tự đi trong R0
  • _cmd đi trong R1
  • đầu tiên int hoặc con trỏ lập luận đi trong R2
  • thứ hai int hoặc con trỏ luận đi vào R3
  • tất cả các đối số khác đi vào ngăn xếp

Vì vậy, nếu bạn chỉ nhìn vào tranh cãi với lên đến 2 params, không ai trong số họ nổi điểm/int64_t/struct, để loại bỏ các đối số tự và _cmd chỉ là vấn đề của shuffling R0-R4:

mov r0, r2 
mov r1, r3 

Hoặc, để viết một chức năng mà phải mất hai params và crams tự và _cmd ở trước khi chuyển tiếp đến một IMP, nó chỉ này:

mov r3, r1 
mov r2, r0 
ldr r1, [address of _cmd] 
ldr r0, [address of self] 

trong trường hợp khối tấm bạt lò xo của Apple, những gì họ đang làm là chuyển một cuộc gọi tới [foo performBlockOnSelf: block] thành, có hiệu quả, [block foo].Như bạn nói, con trỏ khối kết thúc bằng r0 (vị trí tự thường) và tham số đích foo kết thúc bằng r1 (vị trí _cmd thông thường). Nếu các khối thực sự là IMP, tất nhiên, điều này sẽ là vô nghĩa, bởi vì foo không phải là SEL, nhưng chúng không, vì vậy nó không phải là một vấn đề. Từ tuyên bố của bạn "Tôi muốn làm một cái gì đó mơ hồ tương tự liên quan đến việc không có một trong hai đối số đầu tiên, để các đối số cho khối này là chính xác giống như các đối số của phương thức truyền thống gửi," Tôi không hoàn toàn rõ ràng mà trong hai điều bạn đang cố gắng để làm:

  1. Xác định một "đại biểu" đối tượng (về C#), về cơ bản một khối với mục tiêu của nó nướng trong lúc xây dựng. Trong trường hợp này, bạn sẽ muốn tìm kiếm cả r0 (con trỏ khối) và r1 (mục tiêu) từ một số bảng đại biểu, thay vì chỉ là con trỏ khối. Nhưng bạn sẽ không có bất kỳ trình biên dịch trợ giúp thiết lập bảng đó - có nghĩa là bạn có thể thiết lập nó và truy cập nó trong C thuần túy và nó sẽ chỉ là thuận tiện và xây dựng một trampoline lắp ráp tùy chỉnh. (Bạn thậm chí có thể làm điều đó thông qua từ điển ObjC, với một số mất hiệu suất có thể không quan trọng trong thực tế.)

  2. Biến thông báo thành một khối, bao gồm việc lưu trữ mọi thứ để khi mã trampoline của Apple cố gắng gọi khối nó kết thúc bằng phương thức truyền thống gửi tham số thay vì tham số khối. Nếu đây là mục tiêu của bạn, đơn giản hơn và an toàn hơn nhiều khi chỉ sử dụng trình bao bọc khối quanh thư thay vì cố chuyển đổi thư thành các khối và tôi nghi ngờ sẽ có chi phí hiệu quả hoặc linh hoạt quan trọng.

+0

Lời xin lỗi của tôi đã mất quá nhiều thời gian để trả lời, tôi đã viết lại và đánh dấu câu trả lời này là câu trả lời thích hợp vì đó chính là điều tôi muốn trong tháng Tư. Sau khi tham khảo ý kiến ​​với một số người đã làm những việc tương tự, chúng tôi đã đi với - và triển khai - một giải pháp sử dụng libffi. Loại bỏ đối số thứ hai (_cmd) là hoàn toàn bắt buộc. Giữa việc tải trước các đối số (ít nhất là trên ARM), nó sẽ khó thực hiện mà không giới hạn người dùng khung của chúng tôi đến bốn đối số hoặc các phương thức không phải là stret. Giải pháp cuối cùng của chúng tôi nhanh hơn và chức năng hơn người tiền nhiệm của nó, vì vậy tôi rất vui. Cảm ơn! – zwaldowski