Tenés varias maneras, pero se agrupan en dos : Binarias y Scripteadas.
En las binarias establecés qué funciones tiene que tener el binario (librería) y delineás toda una
ABI a respetar ... después tu programa carga dicha librería y utiliza las funciones que espera que esa librería tenga.
En las scripteadas, embebés un mini compilador o runtime de algún lenguaje (como squirrel, lua, C#, etc) dentro de tu programa, y le "registrás" qué funciones de tu programa puede usar ... después el usuario escribe su "script" en algún lugar que tu programa los encuentre; los interpreta/compila y los ejecuta. utilizás esas funciones que le habilitaste y tu programa cambia su comportamiento en base a lo que el usuario escribió.
Podés hacer algún enfoque híbrido o armar tu propio formato de plugin basado total o parcialmente en alguna de las dos ... queda en qué se ajuste más a lo que necesitás y gustos personales
Saludos.