Hola,
estoy probando a pasar un proyecto de Firemonkey a Linux. Evidentemente en Linux funcionaría en modo consola, con lo que he llenado de ifdefs los packages gráficos.
Ya en windows me costó encontrar solución a un problema (solución un poco elegante quiero decir), y es que el proyecto tira de muchas dll's generadas en C, con las que se intercambian mensajes y por tanto hay callbacks (debido a que esas dll's se comunican con un bus de comunicaciones). Bueno hasta ahí no parece que hayan problemas, salvo que los callbacks requieren ser llamados por procedimientos regulares, es decir no se puede pasar por parámetro un método de una clase (si un método estático de una clase, pero estaríamos más o menos en las mismas). El asunto viene que por cada dll puede haber varias instancias de clases, así pues debido a esa restricción el callback a un método regular sería para todas las clases el mismo procedure, lo cual es un problema, enmaraña la solución. Lo ideal, que cada clase tenga su callback particular claro.
Tras buscar encontré que en las librerías de la utilidad madexception había una función que le pasas el método de una instancia de una clase y te devuelve la dirección de la misma, es decir la convierte en un procedimiento regular (pensaba ingenuo de mi que sería algo tan simple como algo parecido a lo siguiente: @InstanciaDeClase.MetodoX). Funciona bien.
Pero claro, al pasar a Linux, llego a ese punto y ooohh no compila, pues accede a la función VirtualAlloc que es del winapi (aparte de los ansistrings), y ya ahí atasco, y eso sin mirar al resto de la función en si, pues es bastante compleja (para mi al menos). La pongo a continuación:
function MethodToProcedure(Self: TObject; methodAddr: Pointer; maxParamCount: Integer): Pointer; var stackSpace: Integer; s1, s2 : AnsiString; pos : Integer; i1 : Integer; begin if maxParamCount < 4 then maxParamCount := 4; if odd(maxParamCount) then stackSpace := (maxParamCount + 2) * 8 // parameters + self + localVar else stackSpace := (maxParamCount + 3) * 8; // parameters + self + localVar + alignment s1 := #$48 + #$81 + #$ec + #0#0#0#0 + // sub rsp, $118 #$48 + #$89 + #$84 + #$24 + #0#0#0#0 + // mov [rsp+$110], rax #$48 + #$8b + #$84 + #$24 + #0#0#0#0 + // mov rax, [rsp+$120] // read 1st original stack parameter #$48 + #$89 + #$44 + #$24 + #$08 + // mov [rsp+8], rax // store as 2nd new stack parameter #$48 + #$8b + #$84 + #$24 + #0#0#0#0 + // mov rax, [rsp+$128] // read 2nd original stack parameter #$48 + #$89 + #$44 + #$24 + #$10 + // mov [rsp+$10], rax // store as 3rd new stack parameter #$48 + #$8b + #$84 + #$24 + #0#0#0#0 + // mov rax, [rsp+$130] // read 3rd original stack parameter #$48 + #$89 + #$44 + #$24 + #$18 + // mov [rsp+$18], rax // store as 4th new stack parameter #$4c + #$89 + #$4c + #$24 + #$20 + // mov [rsp+$20], r9 // store 4th original register parameter as 5th new stack parameter #$4d + #$89 + #$c1 + // mov r9, r8 // cycle the register parameters (rcx -> rdx -> r8 -> r9) #$49 + #$89 + #$d0 + // mov r8, rdx #$48 + #$89 + #$ca + // mov rdx, rcx #$66 + #$0f + #$6f + #$da + // movdqa xmm3, xmm2 // cycle the register parameters (xmm0 -> xmm1 -> xmm2 -> xmm3) #$66 + #$0f + #$6f + #$d1 + // movdqa xmm2, xmm1 #$66 + #$0f + #$6f + #$c8; // movdqa xmm1, xmm0 Integer(Pointer(@s1[4])^) := stackSpace; Integer(Pointer(@s1[12])^) := stackSpace - $8; Integer(Pointer(@s1[20])^) := stackSpace + $8; Integer(Pointer(@s1[33])^) := stackSpace + $10; Integer(Pointer(@s1[46])^) := stackSpace + $18; pos := Length(s1) + 1; SetLength(s1, Length(s1) + (maxParamCount - 4) * 16); s2 := #$48 + #$8b + #$84 + #$24 + #0#0#0#0 + // mov rax, [rsp+$140] #$48 + #$89 + #$84 + #$24 + #0#0#0#0; // mov [rsp+$28], rax for i1 := 1 to maxParamCount - 4 do begin Integer(Pointer(@s2[5])^) := $20 + i1 * 8 + stackSpace; Integer(Pointer(@s2[13])^) := $20 + i1 * 8; Move(s2[1], s1[pos], Length(s2)); inc(pos, Length(s2)); end; s2 := #$48 + #$8b + #$84 + #$24 + #0#0#0#0 + // mov rax, [rsp+$110] #$48 + #$b9 + #0#0#0#0#0#0#0#0 + // mov rcx, methodAddr #$48 + #$89 + #$8c + #$24 + #0#0#0#0 + // mov [rsp+$110], rcx #$48 + #$b9 + #0#0#0#0#0#0#0#0 + // mov rcx, self #$48 + #$89 + #$0c + #$24 + // mov [rsp], rcx // store "self" as 1st new stack parameter #$ff + #$94 + #$24 + #0#0#0#0 + // call [rsp+$110] #$48 + #$81 + #$c4 + #0#0#0#0 + // add rsp, $118 #$c3; // ret Integer(Pointer(@s2[5])^) := stackSpace - $8; Pointer(Pointer(@s2[11])^) := methodAddr; Integer(Pointer(@s2[23])^) := stackSpace - $8; Pointer(Pointer(@s2[29])^) := Self; Integer(Pointer(@s2[44])^) := stackSpace - $8; Integer(Pointer(@s2[51])^) := stackSpace; s1 := s1 + s2; Result := VirtualAlloc(nil, Length(s1), MEM_COMMIT, PAGE_EXECUTE_READWRITE); Move(s1[1], Result^, Length(s1)); end;
Por finalizar, las preguntas:
1-La primera es si alguien tiene quizás algo parecido a esta función ya implementado para Linux
2-La segunda, si alguien tiene idea de como atacar a esa función, vamos de entender qué hace esta función, y si alguien tiene idea de como se puede tocar para que vaya para Linux. Pudiera ser que sea todo cuasi igual, pero la función VirtualAlloc no sabría por qué reemplazarla.
Saludos
Editado por egostar, 13 noviembre 2017 - 05:43 .
Agregar etiqueta de CODIGO para una mejor comprensión del tema.