c - GCC/x86 inline asm: How do you tell gcc that inline assembly section will modify %esp? -


while trying make old code work again (https://github.com/chaos4ever/chaos/blob/master/libraries/system/system_calls.h#l387, fwiw) discovered of semantics of gcc seem have changed in quite subtle still dangerous way during latest 10-15 years... :p

the code used work older versions of gcc, 2.95. anyway, here code:

static inline return_type system_call_service_get(const char *protocol_name, service_parameter_type *service_parameter,     tag_type *identification) {     return_type return_value;      asm volatile("pushl %2\n"                  "pushl %3\n"                  "pushl %4\n"                  "lcall %5, $0"                  : "=a" (return_value),                    "=g" (*service_parameter)                  : "g" (identification),                    "g" (service_parameter),                    "g" (protocol_name),                    "n" (system_call_service_get << 3));      return return_value; } 

the problem code above gcc (4.7 in case) compile following asm code (at&t syntax):

# 392 "../system/system_calls.h" 1 pushl 68(%esp)  # pointer (%esp + 0x68) valid when inline asm entered. pushl %eax pushl 48(%esp)  # ...but 1 not (%esp + 0x48), since 2 dwords have been pushed onto stack, %esp not compiler expects lcall $456, $0  # restoration of %esp @ point done in called method (i.e. lret $12) 

the problem: variables (identification , protocol_name) on stack in calling context. gcc (with optimizations turned out, unsure if matters) values there , hand on inline asm section. but since i'm pushing stuff on stack, offsets gcc calculate off 8 in third call (pushl 48(%esp)). :)

this took me long time figure out, wasn't obvious me @ first.

the easiest way around of course use r input constraint, ensure value in register instead. there another, better way? 1 obvious way of course rewrite whole system call interface not push stuff on stack in first place (and use registers instead, e.g. linux), that's not refactoring feel doing tonight...

is there way tell gcc inline asm "the stack volatile"? how have guys been handling stuff in past?


update later same evening: did found relevant gcc ml thread (https://gcc.gnu.org/ml/gcc-help/2011-06/msg00206.html) didn't seem help. seems specifying %esp in clobber list should make offsets %ebp instead, doesn't work , suspect -o2 -fomit-frame-pointer has effect here. have both of these flags enabled.

what works , doesn't:

  1. i tried omitting -fomit-frame-pointer. no effect whatsoever. included %esp, esp , sp in list of clobbers.

  2. i tried omitting -fomit-frame-pointer , -o3. produces code works, since relies on %ebp rather %esp.

    pushl 16(%ebp) pushl 12(%ebp) pushl 8(%ebp) lcall $456, $0 
  3. i tried having -o3 , not -fomit-frame-pointer specified in command line. creates bad, broken code (relies on %esp being constant within whole assembly block, i.e. no stack frame).

  4. i tried skipping -fomit-frame-pointer , using -o2. broken code, no stack frame.

  5. i tried using `-o1. broken code, no stack frame.

  6. i tried adding cc clobber. no can do, doesn't make difference whatsoever.

  7. i tried changing input constraints ri, giving input & output code below. of course works less elegant had hoped. again, perfect enemy of good maybe have live now.

input c code:

static inline return_type system_call_service_get(const char *protocol_name, service_parameter_type *service_parameter,     tag_type *identification) {     return_type return_value;      asm volatile("pushl %2\n"                  "pushl %3\n"                  "pushl %4\n"                  "lcall %5, $0"                  : "=a" (return_value),                    "=g" (*service_parameter)                  : "ri" (identification),                    "ri" (service_parameter),                    "ri" (protocol_name),                    "n" (system_call_service_get << 3));      return return_value; } 

output asm code. can seen, using registers instead should safe (but maybe less performant since compiler has move stuff around):

#app # 392 "../system/system_calls.h" 1 pushl %esi pushl %eax pushl %ebx lcall $456, $0 

Comments

Popular posts from this blog

node.js - Mongoose: Cast to ObjectId failed for value on newly created object after setting the value -

gradle error "Cannot convert the provided notation to a File or URI" -

python - NameError: name 'subprocess' is not defined -