A a=csinalj(ezzel,0); rész az egy jmp + néhany nop-pal lefedhető, így lett egy ilyen rész:
#define really 0
if ( feltetel )
{ if ( really )
{ a=csinalj(ezzel,0);
}
else
{ asm volatile ("jmp itt_a_vege \r\n");
asm volatile ("nop \r\n");
/* ... */
asm volatile ("nop \r\n");
}
b=meg_ezzel();
valamit(a);
es_megvalamit(b);
itt_a_vege:
(void)0;
}
Ugy hogy annyi nop legyen hogy tényleg ne csússzon szét az image. A paraméterek (ezzel, 0) ABI-szerinti átadása, függvényhívás, return value lementése tényelg jóval összetettem mint egy jmp, így kell az a néhány nop. Ez a fenti így persze nem fordult le, és a C <-> assembly <-> inline assembly <-> C interfacing, ha nem használjuk napi szinten akkor tud fekete mágiának kinézni, finom részletekre nem mindig emlékszem kapásból plusz ilyet még eleve sosem csináltam, úgyhogy... úgyhogy gondoltam miért ne kérdezzük meg az információtól AI-tól hogy mi a teendő. How can we jump to a label from inline assembly using GCC. Egyenes kérdés, a válasz is egyenes. Próbának jó lesz.
A ChatGPT ezt mondta:
main() {
void *label_ptr;
// Take address of the label
label_ptr = &&my_label;
// Inline assembly jumps to label_ptr
asm volatile (
"jmp *%0"
:
: "r" (label_ptr)
);
// This won't be reached due to jump
printf("This will be skipped.\n");
my_label:
printf("Jumped to label!\n");
return 0;
Mindezt tökéletes magabiztonsággal ("Correct Way (Using labels as values + inline assembly)").
A valóság azzal szemben az hogy ezt vagy úgy lehet megcsinálni, hogy a label-t nem C szerint hanem inline assembly szerint kell definiálni:
asm volatile ("itt_a_vege: \r\n");
vagy asm goto-val, jmp %l[label], stb. Mindkettő okés. Itt most az egyszerűbb de kevésbé ajánlott ment élesben, egyszeri hekkelésre - főleg a disassembly/binary image átnézése után - jó ez.
Tanulságok: pro:
- Felhívta a figyelmemet arra hogy ez veszélyes, nonstandard, architektúra-függő, stb.
- Ezt a label_ptr = &&my_label szintaxist nem ismertem, lásd még: TIL. Később még jól jöhet ha az ember redukálni akarja az (inline) assembly-t erősen low level kódokban (low latency interrupt handlerek, context switching, bármi hasonló).
- A kód legalább le sem fordul, mintsemhogy elkezdene hülyeségeket csinálni.
Kontra:
- Magabiztosan nem működő kód, pedig ez egy klasszik minimal working example.
- Nyelvkeverés magas szinten: "jmp *%0", ez eléggé wtf.
- Nyelvi elemek rossz használata: a label az nem void * hanem void(*)(void) tipusú, bár ez a legkevesebb (és hát valljuk be, néha előfordul hogy kellhet ilyet csinálni).
Meg persze ha lenne idő(m), megkérdeznék mást is, opcionálisan előfizetésest... hátha valamelyik megmondja a jó választ.
- apal blogja
- A hozzászóláshoz be kell jelentkezni
- 117 megtekintés