2012-05-04 36 views
6

Tôi gặp vấn đề với đường vòng. Đường vòng, như bạn đã biết, chỉ có thể di chuyển giữa 5 byte không gian (ví dụ: cuộc gọi 'jmp' và địa chỉ 4 byte). Bởi vì điều này là không thể có chức năng 'móc' trong một lớp (một phương pháp), bạn không thể cung cấp con trỏ 'này' vì đơn giản là không đủ không gian (here's vấn đề được giải thích kỹ lưỡng hơn). Vì vậy, tôi đã động não cả ngày cho một giải pháp, và bây giờ tôi muốn suy nghĩ của bạn về chủ đề này vì vậy tôi không bắt đầu một dự án 3-5 ngày mà không biết nếu nó sẽ có thể hay không.C++ và HOÀN TOÀN chức năng động

Tôi đã có 3 mục tiêu ban đầu, tôi muốn các hàm 'móc' là các phương thức lớp, tôi muốn toàn bộ phương pháp tiếp cận hướng đối tượng (không có hàm tĩnh hoặc đối tượng chung) và phần tồi tệ nhất hoàn toàn năng động. Đây là giải pháp (theo lý thuyết) của tôi; với một assembly có thể sửa đổi các hàm trong thời gian chạy (ví dụ hoàn hảo là bất kỳ phương thức tẩy rửa nào). Vì vậy, kể từ khi tôi có thể sửa đổi các chức năng tự động, tôi không nên cũng có thể tạo chúng một cách năng động? Ví dụ; Tôi phân bổ bộ nhớ cho, hãy nói ~ 30 byte (thông qua malloc/mới). Nó sẽ không thể chỉ thay thế tất cả các byte với số nhị phân tương ứng với các nhà khai thác lắp ráp khác nhau (như 0xE9 là 'jmp') và sau đó gọi địa chỉ trực tiếp (vì nó sẽ chứa một chức năng)? Chú ý: Tôi biết trước về giá trị trả về, và tất cả các đối số cho tất cả các hàm mà tôi muốn đi vòng, và vì tôi đang sử dụng GCC, quy ước thiscall thực tế giống với _cdecl.

Vì vậy, đây là suy nghĩ của tôi/sẽ sớm được triển khai; Tôi tạo ra một lớp 'Chức năng'. Hàm khởi tạo này lấy một số đối số variadic (trừ đối số đầu tiên, trong đó mô tả giá trị trả về của hàm đích).

Mỗi đối số là một mô tả về các đối số móc sẽ nhận được (kích thước và cho dù đó là con trỏ hay không). Vì vậy, hãy nói rằng tôi muốn tạo ra một lớp chức năng cho một int * RandomClass::IntCheckNum(short arg1);. Sau đó, tôi sẽ phải làm như thế này: Function func(Type(4, true), Type(4, true), Type(2, false));. Trường hợp 'Loại' được định nghĩa là Type(uint size, bool pointer). Sau đó, thông qua lắp ráp tôi có thể tự động tạo ra các chức năng (lưu ý: điều này tất cả sẽ được sử dụng quy ước gọi _cdecl) kể từ khi tôi có thể tính toán số lượng các đối số và tổng kích thước.

EDIT: Với ví dụ này, Type(4, true) là giá trị trả về (int *), các scond Type(4, true) là RandomClass 'này' con trỏ và Type(2, false) mô tả các đối số đầu tiên (arg1 ngắn).

Với việc triển khai này, tôi có thể dễ dàng có các phương thức lớp như gọi lại, nhưng nó đòi hỏi một số lượng lớn mã lắp ráp (mà tôi thậm chí không có kinh nghiệm đặc biệt). Cuối cùng, điều không động duy nhất sẽ là các phương thức trong lớp gọi lại của tôi (cũng sẽ yêu cầu các cuộc gọi lại trước và sau).

Vì vậy, tôi muốn biết; điều này có thể không? Tôi cần bao nhiêu công việc và tôi có thể vượt qua đầu mình ở đây không?

EDIT: Tôi xin lỗi nếu tôi trình bày mọi thứ hơi mờ, nhưng nếu có điều gì đó bạn muốn giải thích kỹ lưỡng hơn, hãy hỏi!

EDIT2: Tôi cũng muốn biết, nếu tôi có thể tìm giá trị hex cho tất cả các toán tử lắp ráp ở đâu đó? Một danh sách sẽ giúp một tấn! Và/hoặc nếu có thể bằng cách nào đó 'tiết kiệm' asm (""); mã tại một địa chỉ bộ nhớ (mà tôi rất nghi ngờ).

+0

Tại sao nên sử dụng đường vòng? Bạn không thể sử dụng một giải pháp C++ thuần túy như 'std :: function' hay tôi thiếu một cái gì đó? –

+0

Không giống như tôi có thể giúp bạn chỉ để làm rõ mọi thứ. Bạn muốn hàm có thể ghi lại trong lớp? (Tôi có nghĩa là bạn có thể thay đổi chúng khi đang chạy) Nếu đó là vì vậy tôi nghĩ rằng (khi hoàn thành) có thể mở ra cơ hội khổng lồ cho lập trình AI trong C++. +1 – akaltar

+0

@akaltar Điều này được gọi là [lập trình di truyền] (http://en.wikipedia.org/wiki/Genetic_programming) và không thực sự cần chức năng ghi lại. –

Trả lời

4

Những gì bạn mô tả thường được gọi là "thunking" và được triển khai khá phổ biến. Về mặt lịch sử, mục đích phổ biến nhất là ánh xạ giữa mã 16 bit và 32 bit (bằng cách tự động tạo một hàm 32 bit mới gọi một hàm 16 bit hiện có hoặc ngược lại). Tôi tin rằng một số trình biên dịch C++ tạo ra các hàm tương tự để điều chỉnh con trỏ lớp cơ sở cho con trỏ con trỏ trong nhiều thừa kế, cũng vậy.

Nó chắc chắn có vẻ như một giải pháp khả thi cho vấn đề của bạn và tôi không lường trước được bất kỳ vấn đề lớn nào. Chỉ cần chắc chắn rằng bạn cấp phát bộ nhớ với bất kỳ cờ nào cần thiết trong hệ điều hành của bạn để đảm bảo bộ nhớ có thể thực thi được (hầu hết các hệ điều hành hiện đại cung cấp bộ nhớ không thể thực thi theo mặc định).

Bạn có thể tìm thấy liên kết này hữu ích, đặc biệt là nếu làm việc trong Win32: http://www.codeproject.com/Articles/16785/Thunking-in-Win32-Simplifying-Callbacks-to-Non-sta

Về việc tìm kiếm các giá trị hex của hoạt động lắp ráp, các tài liệu tham khảo tốt nhất mà tôi biết là phụ lục kèm theo hướng dẫn của các nhà lắp ráp NASM (và tôi không chỉ nói vậy vì tôi đã giúp viết nó). Có sẵn bản sao tại đây: http://www.posix.nl/linuxassembly/nasmdochtml/nasmdoca.html

+0

Liên kết tuyệt vời! Nó thực sự thú vị đọc về quá trình thunking (quá xấu nó đã được Win32 mặc dù). Bây giờ xin lỗi nếu tôi câm lặng, nhưng như đã đề cập trước đó, tôi không đặc biệt có kinh nghiệm về lắp ráp (tôi chỉ biết một chút AT & T cú pháp) vì vậy tôi phải hỏi về bộ lắp ráp NASM mà bạn tham chiếu đến. Tôi có 2 câu hỏi; tất cả các toán tử ASM chỉ sử dụng 1 byte? Và thứ hai, vì có một số giá trị khác nhau được chỉ định cho từng toán tử, tôi muốn quan tâm đến điều gì? Tôi đoán nó phụ thuộc vào kích thước của các biến của tôi, nhưng để 'đẩy' có 13 giá trị khác nhau, làm cách nào để biết tôi muốn cái nào? –

+1

Đây là các biến thể khác nhau cho các loại lệnh đẩy khác nhau (loại đăng ký, giá trị trực tiếp, tham chiếu bộ nhớ gián tiếp). Phần đầu của hướng dẫn có mô tả về tất cả các chế độ khác nhau, vì vậy hãy sử dụng nó để tìm ra cái nào bạn muốn, sau đó chỉ cần nhìn xuống danh sách để tìm định dạng lệnh bạn cần. Giả sử bạn muốn đẩy EBX: đó là reg32, vì vậy bạn muốn biến thể thứ hai, là "o32 50 + r". o32 là tiền tố kích cỡ toán hạng, được bỏ qua nếu bạn đang chạy trong mã 32 bit; 50 + r là 50 hex cộng với mã cho thanh ghi (3, chúng được liệt kê ở trên cùng), vì vậy 53h là mã của bạn. – Jules

+1

Trong câu trả lời cho câu hỏi đầu tiên của bạn, không có hướng dẫn nào dài hơn một byte và một số hướng dẫn khác nhau tùy theo ngữ cảnh (xem ví dụ PUSH ở trên: tiền tố 'o32' không tạo bất kỳ mã nào trong 32 bit tuy nhiên, nếu bạn đang tạo mã 16 bit, nó sẽ là một byte 66h bổ sung xuất hiện khi bắt đầu lệnh). Tuy nhiên tất cả các hướng dẫn phổ biến nhất là một byte. – Jules

Các vấn đề liên quan