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
- 636 megtekintés
Hozzászólások
Nekem van előfizetésem. Megkérdezem neked ha akarod.
Még nincs aláírásom.
- A hozzászóláshoz be kell jelentkezni
Köszi! Kiváncsi vagyok.
- A hozzászóláshoz be kell jelentkezni
How can we jump to a label from inline assembly using GCC.
De valamelyik stackoverflow cime is jó lehet.
- A hozzászóláshoz be kell jelentkezni
Itt jön a válasz...
🕙 2025-08-23 16:04
Two portable-ish GNU C ways:
1) asm goto
(best if your GCC supports it)
asm goto
lets inline assembly branch to C labels directly.
#include <stdio.h>
void demo(int x) {
asm goto(
"test %0, %0\n\t"
"jz %l[is_zero]\n\t"
:
: "r"(x) // inputs
: // clobbers (add "memory" if needed)
: is_zero // C label(s) you may jump to
);
puts("non-zero");
return;
is_zero:
puts("zero");
}
Notes:
-
Use
%l[labelname]
(or%l0
etc.) in the asm template to reference a C label from the final: ... : labels
list. -
Add
"memory"
to clobbers if the asm influences memory-observable state. -
Supported by GCC 4.5+; Clang supports it only in newer versions (and not on all targets).
2) “Labels as values” + indirect jump (fallback)
If you can’t use asm goto
, take the address of a C label (GNU C extension) and jump to it indirectly:
#include <stdio.h>
void demo(int x) {
void *target = &&nonzero;
if (x == 0) target = &&zero;
// Jump via register operand
__asm__ volatile ("jmp *%0" :: "r"(target));
zero:
puts("zero");
return;
nonzero:
puts("non-zero");
}
Notes:
-
This uses GNU C’s computed goto (
&&label
) plus an indirectjmp *reg
. -
Works in C (GNU C); not standard C/C++.
-
The inline asm sees the label address as a normal pointer operand.
Which should I use?
-
Prefer
asm goto
when available: it’s designed for exactly this use case and integrates with the optimizer/control flow. -
Use the computed-goto + indirect jmp trick if
asm goto
isn’t available on your compiler/target.
If you share your exact target (arch/OS) and GCC/Clang versions, I can tailor the snippet (e.g., different jump mnemonics, clobbers, or constraints).
Még nincs aláírásom.
- A hozzászóláshoz be kell jelentkezni
A válasz elején szerepelt egy ilyen szöveg "Thought for 14s", ami kinyitható (chatGPT5 modell):
Kibontva ez van benne:
When jumping to C labels from inline assembly in GCC, you can use asm goto
or computed gotos. The correct syntax for asm goto
is:
asm goto ("jmp %l0" ::: : target);
You'll also need to specify inputs, clobbers, and the target labels. For example, you could use:
asm goto ("test %0, %0\n\t jz %l[iszero]" : : "r"(x) : : iszero);
In contrast, x86 doesn't allow direct jumps from inline asm to C labels without asm goto
.
In GCC, you can't use a direct jump like jmp some_c_label
unless you use local labels with &&label
. This technique allows indirect jumps via registers:
register void *p = &&label; asm volatile("jmp *%0"::"r"(p));
This works in GNU C, but not C++. Inline assembly can't directly refer to C labels unless using asm goto
or computed gotos. Clang doesn't support asm goto
until GCC 4.5.
The user initially asked for timestamps and had a system that remembered this through updates, but they've reset their context a few times since then. They haven't asked for a timestamp recently, but to be safe, I’ll continue including it unless they explicitly tell me otherwise.
Még nincs aláírásom.
- A hozzászóláshoz be kell jelentkezni
Koszi!
Kozben vegigcsamcsogtam az architekturakat es ugy nezem hogy ez a *%0 megoldas csak x86-oson megy. Az osszes tobbin amit neztem, nem, pedig ugye direkt megfeleloje, ha ugy vesszuk van (ARM-ben, RISC-V-ban es MSP430(X)-ben biztos, minden regiszterrel, AVR-nel limitaltan, csak Z-re). A labeles pelda az szepen megy mindenhol (persze a test/jz-ket megfeleloen at kell irni, de ugye az nem gond). Akkor a fizetos valtozat tobbmindent megtalal.
Clang doesn't support asm goto
until GCC 4.5.
Hm... ez is egy erdekesen sikeredett mondat lett...
- A hozzászóláshoz be kell jelentkezni
Szívesen. Kérdezz nyugodtan mást is, máskor is. Segítek. Nem csak neked szól.
Még nincs aláírásom.
- A hozzászóláshoz be kell jelentkezni
Koszi!
De igen, erdekesek a tanulsagok: az ingyenes megtalalta az egyik, de sajna (valami miatt) x86-specifikus megoldast. A fizetos megtalalta az altalanos masik megoldast, az mukodik mindenhol tok jol mint minimal working example. Az altalanos harmadikat meg a fizetos sem talalta meg.
- A hozzászóláshoz be kell jelentkezni
Esetleg, ha unszoltam volna, azzal is előhozakodik.
Még nincs aláírásom.
- A hozzászóláshoz be kell jelentkezni
> Sajnos a "feltetel" nem volt azonosan 0-ra írható sehogy
Valamit csinálsz a feltételben? Úgy értem, hogy
if (somefunction())
ahol a somefunction csinál valamit, aminek mindenképp meg kell történnie, és a visszatérési érték alapján történik a döntés? Vagy én se kapok fagyit? :))
Debian - The "What?!" starts not!
http://nyizsa.blogspot.com
- A hozzászóláshoz be kell jelentkezni
Jó kérdés. Ez már minimum egy gombóc vanília. Csokoládé elfogyott, pisztácia nem is volt. Hogy klasszikust idézzek.
Még nincs aláírásom.
- A hozzászóláshoz be kell jelentkezni
Sajna #define feloldasbol jon, azonosan igaz. Mondom, aki hulye nem kap fagyit. Nem is kaptam :)
Egyebkent ez egy RTOS kernelhez periferia + halozati linterface inicializalas lenne (igy max routing szinten tiltom le ha nem akarom hasznalni, a #define csak az hogy a kernelhez ne forditsa hozza az aux libeket meg a KEEP-esen linkelt handlert felejtse el hogy kisebb legyen a forras). Az engineering modelben amin dolgoztam be volt forrasztva az illeszto csipp, az eles hardverben meg nem. Es keson szolta a cimbora hogy bocsi, rosszul emlekezett, nem forrasztotta be. Na, erre nem voltam felkeszulve...
- A hozzászóláshoz be kell jelentkezni
Akkor mondd meg a cimborádnak, hogy egy életre felejtse el a fagyit! :))
Debian - The "What?!" starts not!
http://nyizsa.blogspot.com
- A hozzászóláshoz be kell jelentkezni
Kicsit favágó, de az if utáni egész blokkot végigírhatod nop-pal. Akkor nem kell ugrálni.
Debian - The "What?!" starts not!
http://nyizsa.blogspot.com
- A hozzászóláshoz be kell jelentkezni
Jo otlet lehet de igy egyreszt kicsit sok adatot kell feltolteni a joszagra a valtoztatas jellegehez kepest.
Masreszt, a nagyobbik gond, hogy ugy nem teljesen egyertelmu hogy meddig kell tolteni nop-okkal fel. Ezt ugyan a disasm tanulmanyozasaval megtehetjuk, de ugy is roppantul erteni kell a disasm alapjan hogy mi tortenik. Ennel a modszernel megvan az az elony hogy ugyanugy forditott C kod a peccselt valtozat es egyszeruen a hexdumpok diffjet toltlom fel. Igy ha barmi optimalizacio miatt elkezd keveredni a kod (ilyen out of order jelleggel, csak ugye pipeline stallokra optimalizalva) akkor az a diff-nel ez is kibukik. Igy legrosszabb esetben nemcsak az atugro utasitas videket kell megpeccselni hanem a label kornyeken is keletkezhet difi (nehany instruction-nyi), es igy az is megy fel.
- A hozzászóláshoz be kell jelentkezni
Nekem itt az a feltetel nem stimmel, hogy miert akarsz mindent a helyen hagyni? Ha utana olyan valtoztatasra lesz igeny valahol, ami nem fer el a jelenlegi helyen, fogod, es jumpolsz a vegere, aztan vissza?
Azt meg megertem, ha valami fix dolgot a jelenlegi helyen szeretnel tartani, de ahhoz inkabb linkeres trukkozes kell.
Tipikusan a mikrokontroller egetese par masodperc - eleg hamar felmegy a teljes kod, es a flash mondjuk 10000* ujrairhato, ebbol meg fejlesztes kozben is nehez kifutni, hat meg production kutyuknel. Persze ha csak szakmai kivancsisag hajt, akkor hajra!
A strange game. The only winning move is not to play. How about a nice game of chess?
- A hozzászóláshoz be kell jelentkezni
Itt most csak egy gyors hotfix volt hogy egy joliranyzott jmp ugorja at a kritikus reszt (konkretan az MCU ~tucatnyi hw inicializalasbol kellet az egyiket kiiktatni). Csak azert csinaltam igy hogy tenyleg csak a joliranyzott jmp-t injektalja bele a fordito a jo helyre, hogy pont oda ugorjon ahova kell (es ne nekem kelljen offset-et meg pc-alignmentet szamolni) es hogy biztos hogy atugorhato legyen (es/vagy kideruljon ha nem atugorhato, pl egy pipeline stall optimization miatt) ez az if ( ... ) blokk. Ezutobbiaknak volt az ara ez a ~feltucat nop... ez van :)
Persze, komolyabb fejlesztesnel rendes ujraforditas + ujrafeltoltes van, csak itt ennel az esetnel a savszelesseg meg a feltoltesi lehetoseg az nem eppen a legoptimalisabb. Igy ez a kis praktika/sporolas plusz a szakmai kivancsisag volt itt a fo cel.
- A hozzászóláshoz be kell jelentkezni