single function with multiple names

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:single function with multiple names

Post by Pype.Clicker »

... or using a text transductor that would discover that you're calling XYZ("fmt", 1 , 2 , 3 , 4 ) and therefore replaces XYZ_MACROsiii ...

If you look at OpenGL, for instance, function names always carry the type of their arguments...
Dreamsmith

Re:single function with multiple names

Post by Dreamsmith »

Candy wrote:I was considering making the ugliest hack I've ever... making either a recursive define or about 60 or so defines so all functions can be used with it... That'd work...
I don't think you can define a recursive macro.

Was the problem that you have different syscalls that take different numbers of arguments, or that you have syscalls that take a variable number of arguments (ala printf)?

If it's the former, you really ought to have a different define for each syscall in any case, and it ought to be defined it such a way that its arguments are type-checked (assign each parameter to a local variable of the correct type inside the curly braces, if you're allergic to inline functions). Trying to use a single syscall macro for every syscall is a much bigger hack than actually doing the work of properly defining the interface for each syscall. The only non-hackish solution to this problem is to use inline functions, everything else subverts or bypasses (modern) C's standard way of declaring these things, type-checking, etc. As of C99, you really ought not need defines at all. That's what const and inline are for. #define has always been a hack.

If the problem is you have syscalls using varargs, I believe you're going to be forced to use a trampoline in that case.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:single function with multiple names

Post by Candy »

Dreamsmith wrote:
Candy wrote:I was considering making the ugliest hack I've ever... making either a recursive define or about 60 or so defines so all functions can be used with it... That'd work...
I don't think you can define a recursive macro.

Was the problem that you have different syscalls that take different numbers of arguments, or that you have syscalls that take a variable number of arguments (ala printf)?

If it's the former, you really ought to have a different define for each syscall in any case, and it ought to be defined it such a way that its arguments are type-checked (assign each parameter to a local variable of the correct type inside the curly braces, if you're allergic to inline functions). Trying to use a single syscall macro for every syscall is a much bigger hack than actually doing the work of properly defining the interface for each syscall. The only non-hackish solution to this problem is to use inline functions, everything else subverts or bypasses (modern) C's standard way of declaring these things, type-checking, etc. As of C99, you really ought not need defines at all. That's what const and inline are for. #define has always been a hack.

If the problem is you have syscalls using varargs, I believe you're going to be forced to use a trampoline in that case.
Two of my syscalls (well... two very similar ones) have variable arguments that have to be pushed on the stack before the call. The syscall itself doesn't use them as varargs, but as a memory area for a thread creation (the function is tcall and is similar to calling a function, but in this case making a thread that calls the function and not waiting for it to complete). The point is, the C compiler only has to treat it like a normal function, the rest is done by assembly magic in the kernel.

there is no way I'm going to convince the compiler to instead of inserting a call ....... to insert an arbitrary sequence of equal length right?
Dreamsmith

Re:single function with multiple names

Post by Dreamsmith »

Candy wrote:there is no way I'm going to convince the compiler to instead of inserting a call ....... to insert an arbitrary sequence of equal length right?
I believe so. If you do find a way, please let us know, I for one would love to be able to get rid of my trampolines.

You could postprocess the output of GCC and replace the CALLs that way. Or, for a real dirty hack, make all the CALLs be to a function that modifies the caller to what you want at run time.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:single function with multiple names

Post by Candy »

Dreamsmith wrote:
Candy wrote:there is no way I'm going to convince the compiler to instead of inserting a call ....... to insert an arbitrary sequence of equal length right?
I believe so. If you do find a way, please let us know, I for one would love to be able to get rid of my trampolines...
all I can think of atm is a special hack to my dynamic linker/loader so it patches up the entire entry instead of just the relocation portion, but this is VERY unportable and VERY hackish. I'd make it replace each time that function occured with an E8 prefix to a normal syscall with a nop at the end, each time the prefix was E9 it'd be replaced with the syscall with a ret at the end and each other time (also all times when it's in the data section) it'd be replaced with the trampoline version. I think this'd kill a LOT of unnecessary calls.

Of course this could also be put in a preprocessor, to accelerate load times.. might be put in a loader section so it links them once and stores a prelinked binary, might be dynamic linking so it only replaces it upon actual call... but I think the best one is just on load.

How am I going to get the C compiler to just leave those references open? OK, back to the drawing board...
Dreamsmith

Re:single function with multiple names

Post by Dreamsmith »

Candy wrote:all I can think of atm is a special hack to my dynamic linker/loader so it patches up the entire entry instead of just the relocation portion, but this is VERY unportable and VERY hackish.
Ah, I suggested in an edit of my last post something similar, but if you have a dynamic linker, that'd probably be less hackish than my suggestion of a runtime function that modifies the caller. Actually, I don't think it's be very hackish doing it in the dynamic linker. It's the dynamic linker's job to modify code to connect it to the proper destination. If that destination is a syscall, it should be able to modify it appropriately. I'd consider that less of a hack than using a trampoline function, which is what I do now.

As far as portability goes, anything that has to modify processor specific object code is unportable. Anything that has to deal with hardware is unportable. Anything that has to deal with CPU state is unportable. The precise job of an operating system is to deal with the nitty-gritty unportable hardware-specific details of a system so that applications don't have to. Being overly concerned about the portability of operating system code is just going to drive you nuts. There's no such thing as a portable syscall interface, for example. So no matter which way you solve this problem, it's not going to be portable.

I don't mean to suggest portability should never be a concern in OS design. Just that it should be trumped by pretty much any other practical concern.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:single function with multiple names

Post by Candy »

Dreamsmith wrote:
Candy wrote:all I can think of atm is a special hack to my dynamic linker/loader so it patches up the entire entry instead of just the relocation portion, but this is VERY unportable and VERY hackish.
Ah, I suggested in an edit of my last post something similar, but if you have a dynamic linker, that'd probably be less hackish than my suggestion of a runtime function that modifies the caller. Actually, I don't think it's be very hackish doing it in the dynamic linker. It's the dynamic linker's job to modify code to connect it to the proper destination. If that destination is a syscall, it should be able to modify it appropriately. I'd consider that less of a hack than using a trampoline function, which is what I do now.

As far as portability goes, anything that has to modify processor specific object code is unportable. Anything that has to deal with hardware is unportable. Anything that has to deal with CPU state is unportable. The precise job of an operating system is to deal with the nitty-gritty unportable hardware-specific details of a system so that applications don't have to. Being overly concerned about the portability of operating system code is just going to drive you nuts. There's no such thing as a portable syscall interface, for example. So no matter which way you solve this problem, it's not going to be portable.

I don't mean to suggest portability should never be a concern in OS design. Just that it should be trumped by pretty much any other practical concern.
That's true, but the entire concept is not portable to any CPU with constant length ops, since the jump-op is replaced by at least 2 and sometimes 3 ops. Because I can stuff the syscall number in AL it only takes a 1-byte immediate, 1-byte opcode, syscall is 2-byte and that leaves for a 1-byte ret at the end. I might convert the mov/syscall/nop to mov in special encoding with syscall only, where the mov would be a mov(zx) eax, byte 1 in bytecode, since I recall the non-fitting form being a 2-byte opcode. Saves a byte on P4's and similar thingy's, since they only store microcoded instructions.

I think this is going to be the final way I'm going to do it. Functions that are normally inlined, if not inlined dynamically linked to a shared library, and upon load replaced with the alternate code or left as the call. Of course, the first version is only going to call the trampoline, no matter what.
Dreamsmith

Re:single function with multiple names

Post by Dreamsmith »

Candy wrote:That's true, but the entire concept is not portable to any CPU with constant length ops, since the jump-op is replaced by at least 2 and sometimes 3 ops.
On a CPU with constant length ops, you're almost certainly not going to need to replace the CALL op with multiple ops, rather, you'll have wide enough instructions to be able to encode each syscall with it own, unique opcode. The syscall number will be encoded into the syscall operation rather than loaded into EAX. Processors of this type generally have available trap opcodes by the thousands.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:single function with multiple names

Post by Candy »

Dreamsmith wrote:
Candy wrote:That's true, but the entire concept is not portable to any CPU with constant length ops, since the jump-op is replaced by at least 2 and sometimes 3 ops.
On a CPU with constant length ops, you're almost certainly not going to need to replace the CALL op with multiple ops, rather, you'll have wide enough instructions to be able to encode each syscall with it own, unique opcode. The syscall number will be encoded into the syscall operation rather than loaded into EAX. Processors of this type generally have available trap opcodes by the thousands.
That doesn't account for jumps instead of calls (E9 is jump), where you have to ret after the syscall, because the syscall doesn't ret but sysret (incompatible stack configuration).
User avatar
Pype.Clicker
Member
Member
Posts: 5964
Joined: Wed Oct 18, 2006 2:31 am
Location: In a galaxy, far, far away
Contact:

Re:single function with multiple names

Post by Pype.Clicker »

just throwing my 2 cents here: it is indeed possible to have the linker/compiler leave the system_call links "pending" by forcing 'iterative' linking (-r or -i flag for LD) ... After this, you simply crawl the symbol table, looking for patterns you expect (like MyOS_SysCall_<syscall_name>) and patches calls to that function with the wished code (like mov eax, byte svc_id; syscall), provided that your calling code is lower than 5 bytes ...

Toying with the following "add esp, <cleanup_value>" is discouradged since i've seen many optimizer trying to clean several calls in a row rather than cleaning after each call ...

In clicker, such patch of "open symbols" is performed for creating the 'module' format (instead of keeping an ELF/COFF format), and i rather advocate for having it done by a compiling tool than by the kernel-shipped loader for efficiency of loading.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:single function with multiple names

Post by Candy »

Pype.Clicker wrote: just throwing my 2 cents here: it is indeed possible to have the linker/compiler leave the system_call links "pending" by forcing 'iterative' linking (-r or -i flag for LD) ... After this, you simply crawl the symbol table, looking for patterns you expect (like MyOS_SysCall_<syscall_name>) and patches calls to that function with the wished code (like mov eax, byte svc_id; syscall), provided that your calling code is lower than 5 bytes ...
Which is exactly not what I want. I want it to leave the link open (such as with dynamic linking) when finished linking the file, plus I want all the other linker errors brought by the final link. This is code meant for users, not a specific clique. It should conform to the default wherever possible.
Toying with the following "add esp, <cleanup_value>" is discouradged since i've seen many optimizer trying to clean several calls in a row rather than cleaning after each call ...
The caller pushed the values, the caller must also clear them. This isn't pascal. Anyway, the C programs generated do this for all normal calls so it's useable in this way.
In clicker, such patch of "open symbols" is performed for creating the 'module' format (instead of keeping an ELF/COFF format), and i rather advocate for having it done by a compiling tool than by the kernel-shipped loader for efficiency of loading.
Loading efficiency was hoping to be achieved using prelinking to a certain location and storing a cached executable. This makes the actual binary portable across upgrades etc. but keeps the speed of prelinked stuff, even for things that may be dynamically relocated. It also allows me to change the program virtual base any time I damn well please :)
Dreamsmith

Re:single function with multiple names

Post by Dreamsmith »

Candy wrote:That doesn't account for jumps instead of calls (E9 is jump), where you have to ret after the syscall, because the syscall doesn't ret but sysret (incompatible stack configuration).
Why not? It's no easier or more difficult to deal with either case, just keep it straight which case you're dealing with. Note: There are no routines on an Intel processor that must be returned from using an iret, or retf, or any other particular construction -- all that is required is that you return to the right place with the stack in order. The same is true on any other processor. All the various different forms of return instructions are their because it's conveninent. Absolutely none of them are there because they are necessary in some circumstance or other.

If you understand that, you can see why your concern above is a non-issue. All your routines can sysret at the end, regardless of how they were called -- you just need to make sure that everything is setup to go to the right place when that happens. That changes how you enter the function, not how you exit it, and since you're patching the entry opcode(s) into the code, that's a trivially easy thing to arrange.
User avatar
Candy
Member
Member
Posts: 3882
Joined: Tue Oct 17, 2006 11:33 pm
Location: Eindhoven

Re:single function with multiple names

Post by Candy »

Dreamsmith wrote: Why not? It's no easier or more difficult to deal with either case, just keep it straight which case you're dealing with. Note: There are no routines on an Intel processor that must be returned from using an iret, or retf, or any other particular construction -- all that is required is that you return to the right place with the stack in order. The same is true on any other processor. All the various different forms of return instructions are their because it's conveninent. Absolutely none of them are there because they are necessary in some circumstance or other.

If you understand that, you can see why your concern above is a non-issue. All your routines can sysret at the end, regardless of how they were called -- you just need to make sure that everything is setup to go to the right place when that happens. That changes how you enter the function, not how you exit it, and since you're patching the entry opcode(s) into the code, that's a trivially easy thing to arrange.
SYSCALL defines one (1) entry point systemwide. There is no second alternative route for any other calling interface. There is no space for loading a 16-bit register where I might abuse a bit (they all need a 2-byte opcode + 2-byte immediate, plus the 2-byte syscall > 5byte). The idea of keeping this manageable is to keep it as simple as possible. Only substitute the call / jump things, leave the rest. Anyway, I'm only aiming for X86 stuff, so it's not that important. Yet, it's a consideration.
Dreamsmith

Re:single function with multiple names

Post by Dreamsmith »

Candy wrote:Anyway, I'm only aiming for X86 stuff, so it's not that important. Yet, it's a consideration.
Not really. It's not a consideration on x86 because it doesn't have constant length operations, and it's not a problem on processors with constant length operations because you generally have a ridiculous number of opcodes to use for traps, and thus would not need to worry about encoding it as multiple operations as you're doing on the x86. This solution would only be not portable to machines with constant length operations but only a single opcode available for syscall trapping. To the best of my knowledge, there is no such processor, at least in the 32-bit or greater era...
B1FF

Re:single function with multiple names

Post by B1FF »

>Is it possible in C/C++ to create a function with more than one function name?

Code: Select all

typedef unsigned pid_t;
int kill(pid_t pid) { return pid; }
int killp(pid_t pid) __attribute__((weak, alias("kill")));
Post Reply