-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathmain.cpp
More file actions
5486 lines (5273 loc) · 277 KB
/
Copy pathmain.cpp
File metadata and controls
5486 lines (5273 loc) · 277 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
* VestaVM - Máquina Virtual Distribuida
*
* Copyright © 2026 David López.T (DesmonHak) (Castilla y León, ES)
* Licencia VMProject
*
* USO LIBRE NO COMERCIAL con atribución obligatoria.
* PROHIBIDO lucro sin permiso escrito.
*
* Descargo: Autor no responsable por modificaciones.
*/
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <cstring>
#include <fstream>
#include <sstream>
#include <thread>
#include <atomic>
#include <csignal>
#include <openssl/sha.h>
#include "cxxopts.hpp"
#include "cli/cli.h"
#include "cli/vsh.h"
#include "cli/version_info.h" // Banner de `vesta --version` / `-v`
#include "analyze/bigo.h" // Subsistema de coste: modo --analyze (Big-O)
#include "ir/ir_emitter.h"
#include "ir/ssa_ir_serialize.h" // Phase AOT: parse_ir_section (round-trip del @ir)
#include "aot/aot_analyze.h" // Phase AOT.1: analisis de compatibilidad nativa
#include "aot/aot_lower.h" // Phase AOT.2: re-bajada RAW_ALLOC/FREE/PANIC -> CALL
#include "aot/object_writer.h" // Phase AOT.4: emisor PE/ELF (ObjectWriter)
#include "aot/aot_native.h" // Phase AOT.3 Paso 2: _start arch-portable
#include "aot/linker.h" // Phase AOT.5: linker propio (enlaza .o)
#include "jit/vreg_pipeline.h" // Phase AOT.3 Paso 2: vreg_compile_native (HOST_LEAF)
#include "jit/vec_isa.h" // ancho SIMD del target (--float-isa)
#include "jit/auto_jit.h"
#include "jit/keystone_asm_backend.h" // Phase AS inc.4b: registrar backend asm
#include "jit/inline_asm_trampoline.h" // Phase AS inc.6: helper runner inline-asm
#include "jit/naked_native.h" // Bug 198: dispatcher naked (asm con simbolos propios)
#include "runtime/profile.h" // Sprint D.6 (2026-06-03)
#include "pkg/cli.h"
#include "runtime/proceso_runtime.h"
#include "cli/runtime_api_commands.h"
#include "util/assembler_multiprocess.h"
#include "vx/compiler.h"
#include "vx/lexer.h"
#include "vx/parser.h"
#include "vx/semantic_index.h"
// Forward-decl (evita incluir vx/parser.h, que arrastra cabeceras Windows que
// desbalancean el push/pop_macro(VOID) de ssa_ir.h). @Target target-aware AOT.
namespace vx {
void set_aot_condcomp_target(const std::string &os,
const std::string &arch) noexcept;
}
#include "vx/comptime_vm.h" /* Phase MC.4 probe del ComptimeRuntime */
#include "vx/project_cache.h" /* Phase M5.B project-level cache */
#include "vx/velb_signature.h" /* Phase M.L28: firmas digitales */
#include "util/sqlite_singleton.h"
#include "util/fs_utils.h"
#include "runtime/manager_runtime.h"
#include "gc/gc_heap.h"
#include "loader/loader.h"
#include "profiler/timer.h"
#include "distrib/dist_runtime.h"
#include "distrib/dist_debug.h"
#include "distrib/node_registry.h"
#include "debug/debugger.h"
#include "debug/auth.h"
#include "install/install.h"
#include <filesystem>
#include <map> // Phase MC.16: per-macro manifest map
#include <unordered_map> // Phase AOT.3 2b-ii: layout name->offset
#include <set> // Phase MC.16: manifest diff seen-set
#include <cctype> // Phase MC.16: isalnum en find_macro_ranges_with_names
#include <openssl/rand.h>
#ifdef VESTA_HAS_PREPROCESSOR
#include "preprocessor/preprocessor.h"
#endif
// flag global para el modo --dist-server; SIGINT lo pone a false
static std::atomic<bool> g_server_running{true};
static void on_dist_sigint(int) {
g_server_running.store(false);
}
/**
* @brief Construye la NodeAuthConfig a partir de los flags de autenticacion.
*
* Calcula SHA-256 del token en texto plano si se proporciono --dist-token.
* Copia las rutas TLS si se activo --dist-tls.
*
* @param token Token en texto plano (puede estar vacio).
* @param use_tls true si se activo --dist-tls.
* @param cert Ruta al certificado PEM del cliente.
* @param key Ruta a la clave privada PEM del cliente.
* @param ca Ruta al CA bundle PEM para verificar pares.
* @return NodeAuthConfig relleno.
*/
static distrib::NodeAuthConfig
build_node_auth(const std::string &token, bool use_tls, const std::string &cert,
const std::string &key, const std::string &ca) {
distrib::NodeAuthConfig auth{};
if (!token.empty()) {
auth.use_token = true;
SHA256(reinterpret_cast<const unsigned char *>(token.c_str()),
token.size(), auth.token_hash);
}
if (use_tls) {
auth.use_tls = true;
std::snprintf(auth.cert_path, sizeof(auth.cert_path), "%s",
cert.c_str());
std::snprintf(auth.key_path, sizeof(auth.key_path), "%s", key.c_str());
std::snprintf(auth.ca_path, sizeof(auth.ca_path), "%s", ca.c_str());
}
return auth;
}
/**
* @brief Aplica la configuracion distribuida a una instancia VM.
*
* Reemplaza el dist_runtime minimo creado en VM::VM() por uno completamente
* configurado segun los flags --dist-* de la linea de comandos.
* Si --dist-port > 0 o --dist-discover esta activo, llama a start() para
* abrir el servidor VDP y/o el hilo de descubrimiento UDP.
* Registra cualquier nodo estatico indicado con --dist-add-node (formato
* IP:PUERTO).
*
* @param vm Instancia VM sobre la que se aplica la configuracion.
* @param result Resultado del parseo de cxxopts con todos los flags.
*/
static void apply_dist_config(runtime::VM *vm,
const cxxopts::ParseResult &result) {
const std::string token = result["dist-token"].as<std::string>();
const bool use_tls = result.count("dist-tls") > 0;
const std::string cert = result["dist-cert"].as<std::string>();
const std::string key = result["dist-key"].as<std::string>();
const std::string ca = result["dist-ca"].as<std::string>();
// construir configuracion del DistRuntime
distrib::DistRuntimeConfig cfg{};
cfg.local_node_id = result["dist-node-id"].as<uint64_t>();
cfg.vdp_listen_port = result["dist-port"].as<uint16_t>();
cfg.discover_port = result["dist-discover-port"].as<uint16_t>();
cfg.enable_discovery = result.count("dist-discover") > 0;
std::string name = result["dist-name"].as<std::string>();
if (!name.empty())
std::snprintf(cfg.local_node_name, sizeof(cfg.local_node_name), "%s",
name.c_str());
else
std::snprintf(cfg.local_node_name, sizeof(cfg.local_node_name),
"vm-%llu", static_cast<unsigned long long>(vm->id));
cfg.server_auth = build_node_auth(token, use_tls, cert, key, ca);
// reemplazar el dist_runtime minimal por uno completamente configurado
vm->dist_runtime = std::make_unique<distrib::DistRuntime>(*vm, cfg);
// arrancar el servidor VDP y/o el descubrimiento si alguno esta habilitado
if (cfg.vdp_listen_port > 0 || cfg.enable_discovery) {
if (vm->dist_runtime->start()) {
std::string msg = "[dist] Servidor VDP iniciado";
if (cfg.vdp_listen_port)
msg += " en puerto " + std::to_string(cfg.vdp_listen_port);
if (cfg.enable_discovery)
msg += " con descubrimiento UDP (puerto " +
std::to_string(cfg.discover_port) + ")";
vesta::scout() << msg << "\n";
} else {
std::cerr << "[dist] Error al iniciar el servidor VDP\n";
}
}
// registrar nodos estaticos proporcionados con --dist-add-node IP:PUERTO
if (result.count("dist-add-node")) {
distrib::NodeAuthConfig node_auth =
build_node_auth(token, use_tls, cert, key, ca);
for (auto &spec :
result["dist-add-node"].as<std::vector<std::string>>()) {
auto colon = spec.rfind(':');
if (colon == std::string::npos) {
std::cerr << "[dist] Formato invalido (esperado IP:PUERTO): "
<< spec << "\n";
continue;
}
std::string node_ip = spec.substr(0, colon);
uint16_t node_port = 0;
try {
node_port =
static_cast<uint16_t>(std::stoul(spec.substr(colon + 1)));
} catch (...) {
std::cerr << "[dist] Puerto invalido en: " << spec << "\n";
continue;
}
uint32_t idx = vm->dist_runtime->add_node(
node_ip.c_str(), node_port, node_auth, node_ip.c_str());
vesta::scout() << "[dist] Nodo registrado: " << node_ip << ":"
<< node_port << " (idx=" << idx << ")\n";
}
}
}
/* forzar registro de virtual fns runtime (callbacks Vesta->C). */
extern "C" void runtime_ensure_vx_callback_registered(void);
int main(int argc, char *argv[]) {
#if defined(WIN32) || defined(_WIN32) || \
defined(__WIN32) && !defined(__CYGWIN__)
asm_multi_process::run_and_capture("chcp 65001");
#endif
runtime_ensure_vx_callback_registered();
// Phase AS inc.4b: registrar el backend de ensamblado Keystone para que el
// frontend Vesta valide la sintaxis del inline asm en compile-time.
jit::register_keystone_asm_backend();
// Phase AS inc.6: registrar el helper nativo vrt:inline_asm_exec que el
// interprete (modo -m vm, sin JIT) invoca por cada bloque inline-asm.
jit::register_inline_asm_runner();
// Bug/feature 198: registrar el dispatcher vrt:naked_dispatch que
// compila+invoca funciones @Naked (asm con simbolos propios) al vuelo
// desde interp/JIT, + vrt:naked_fnaddr (direccion nativa de una funcion
// para punteros a funcion que fluyen a codigo nativo).
jit::register_naked_dispatch_runner();
jit::register_naked_fnaddr_runner();
// FN.3: registrar vrt:jit_active (modo interp vs JIT) y vrt:getproc
// (ProcessVM* actual), que `fiber_init` usa para elegir el modelo de
// fibra en JIT (pila/ctx host + trampolin + proc).
jit::register_fiber_runtime_runner();
// ------------------------------------------------------------------
// Subcomando especial: @c vm pkg <subcmd> ...
// Despachamos ANTES del parser cxxopts porque el package manager
// tiene su propio sistema de flags y subcomandos.
// ------------------------------------------------------------------
if (argc >= 2 && std::string(argv[1]) == "pkg") {
// Pasamos argv shifted: argv[0]="vm", argv[1]="pkg",
// queremos que pkg::cli reciba argv[1]=primer subcomando.
// Construimos un argc/argv nuevo skipeando el "pkg" literal.
std::vector<char *> sub;
sub.push_back(argv[0]);
for (int i = 2; i < argc; ++i)
sub.push_back(argv[i]);
return pkg::cli::run(static_cast<int>(sub.size()), sub.data());
}
/* registrar el hook auto-JIT en el runtime.
* El runtime (vesta_rt) tiene un function pointer nulo por defecto;
* el main aqui lo apunta al JIT trigger. Si el env var
* VESTA_JIT_THRESHOLD esta presente, el trigger compila funciones
* hot a codigo nativo. Sin env var, el
* threshold queda en UINT32_MAX y el hook es no-op aunque se llame. */
runtime::g_callvirt_post_hook = &jit::maybe_compile_method;
cxxopts::Options options("VMProject", "Virtual Machine Example");
options.add_options()("h,help", "Mostrar ayuda")(
"o,output", "Archivo de salida (sin extensión o completo)",
cxxopts::value<std::string>())(
"driver", "Compilar un directorio completo en paralelo",
cxxopts::value<std::string>())(
"worker", "Compilar un único archivo (modo interno)",
cxxopts::value<std::string>())(
"j,threads", "Número de hilos para el driver",
cxxopts::value<int>()->default_value("0"))("v,version",
"Mostrar versión")(
"m,mode",
"Modo de ejecucion/compilacion: vm (interprete) | jit (JIT en "
"caliente) | aot (compilacion nativa standalone, requiere --vx)",
cxxopts::value<std::string>()->default_value("vm"))(
"list-arch", "Imprimir arquitecturas soportadas")(
"asm-file", "Archivo ASM a ensamblar", cxxopts::value<std::string>())(
"disasm-file", "Archivo binario a desensamblar",
cxxopts::value<std::string>())(
"arch", "Arquitectura para ensamblar/desensamblar",
cxxopts::value<std::string>())(
"save-output", "Guardar código ensamblado/desensamblado en archivo")(
"output-prefix", "Prefijo/nombre base para archivos de salida",
cxxopts::value<std::string>()->default_value("out"))(
"run", "Ejecutar un archivo .velb en la VM",
cxxopts::value<std::string>())("build",
"Compilar un archivo .vel a .velb",
cxxopts::value<std::string>())(
"schedulers", "Número de schedulers para el comando run",
cxxopts::value<size_t>()->default_value("1"))(
"install",
"Ejecutar el instalador interactivo (o con flags adicionales)")(
"uninstall", "Desinstalar Vesta usando el manifest")(
"repair", "Reparar la instalacion existente")(
"silent", "Modo silencioso para install/uninstall")(
"per-user", "Forzar instalacion per-user")(
"system-wide", "Forzar instalacion system-wide")(
"prefix", "Directorio destino", cxxopts::value<std::string>())(
"manifest", "Ruta a install_manifest.json",
cxxopts::value<std::string>())(
"stats",
"Mostrar estadísticas de ejecución al finalizar (tiempo, MIPS)")
// ---- opciones de JIT ----
("jit-threshold",
"Umbral de invocaciones de un metodo para disparar JIT (default: "
"UINT32_MAX = JIT off; sugerido para test: 1)",
cxxopts::value<uint32_t>())(
"jit-warn", "Imprimir warnings cada vez que el Selector encuentra "
"una IR op no soportada (dedup por op+linea)")(
"jit-stats", "Imprimir snapshot final de counters del JIT: "
"compiled/unsupported/no_ir + threshold")(
"jit-disasm", "Volcar hex bytes + disasm (Capstone) de cada "
"funcion JIT-compilada a stderr")
// ---- opciones de profiling (D.6 PGO) ----
("profile",
"Generar @c .vprof con branch/type/alloc counters al exit (PGO para "
"C2). Path opcional; default: 'program.vprof'.",
cxxopts::value<std::string>()->implicit_value("program.vprof"))
// ---- opciones de runtime distribuido ----
("dist-port",
"Puerto VDP del servidor distribuido (0 = sin servidor TCP)",
cxxopts::value<uint16_t>()->default_value("0"))(
"dist-discover", "Activar descubrimiento UDP de nodos en la LAN")(
"dist-discover-port", "Puerto UDP para descubrimiento de nodos",
cxxopts::value<uint16_t>()->default_value("7790"))(
"dist-name", "Nombre del nodo local (cadena identificativa)",
cxxopts::value<std::string>()->default_value(""))(
"dist-node-id",
"ID de 64 bits del nodo (0 = generar automaticamente)",
cxxopts::value<uint64_t>()->default_value("0"))(
"dist-add-node",
"Nodo estatico a registrar y conectar (formato IP:PUERTO, "
"repetible)",
cxxopts::value<std::vector<std::string>>())(
"dist-token",
"Token de autenticacion en texto plano (se almacena como SHA-256)",
cxxopts::value<std::string>()->default_value(""))(
"dist-tls", "Usar TLS en las conexiones VDP salientes y entrantes")(
"dist-cert", "Ruta al certificado TLS del nodo local (PEM)",
cxxopts::value<std::string>()->default_value(""))(
"dist-key", "Ruta a la clave privada TLS del nodo local (PEM)",
cxxopts::value<std::string>()->default_value(""))(
"dist-ca", "Ruta al CA bundle TLS para verificar pares (PEM)",
cxxopts::value<std::string>()->default_value(""))(
"dist-server", "Modo servidor distribuido puro: espera conexiones "
"VDP sin ejecutar bytecode")(
"dist-debug", "Activar trazas de depuracion del subsistema "
"distribuido (RSPAWN, HALT, FUTURE_FULFILL)")(
"script", "Ejecutar un fichero VestaShell (.vsh) y salir",
cxxopts::value<std::string>())(
"interprete",
"Abrir el interprete interactivo VestaShell (REPL .vsh)")(
"ir-file",
"Compilar archivo .ir (SSA IR) a .vel y opcionalmente a .velb",
cxxopts::value<std::string>())(
"ir-opt",
"Nivel de optimizacion IR: 0=O0, 1=O1, 2=O2, 3=O3 (defecto: 1)",
cxxopts::value<int>()->default_value("1"))(
"ir-emit-only", "Solo emitir el texto .vel; no compilar a .velb")(
"vesta", "Compilar archivo .vx (lenguaje Vesta) a .velb",
cxxopts::value<std::string>())(
"vx", "Alias de --vesta (compilar archivo .vx a .velb)",
cxxopts::value<std::string>())(
"vx-emit-only",
"Solo emitir el .vel intermedio del .vx; no compilar a .velb")(
"vx-emit-ir",
"Emitir el SSA IR del .vx (pre y post optimizacion) en "
"<output>.ir; util para debug del frontend")(
"dump-semantic-index",
"Volcar el indice semantico por-declaracion (hash de contenido + "
"grafo de deps) de un .vx como JSON; sustrato de la compilacion "
"incremental granular",
cxxopts::value<std::string>())(
"analyze",
"Subsistema de coste: analiza la complejidad algoritmica (Big-O) "
"estatica de cada funcion de un .vx y la imprime; valida el "
"contrato @complexity si esta presente. Cero impacto en codegen.",
cxxopts::value<std::string>())(
"analyze-json",
"Con --analyze: emite el coste por funcion como JSON (para "
"consumir desde un renderer de diagramas) en vez de texto legible.")
// Phase AOT: con -m aot, target de compilacion nativa.
("target",
"Tier de compilacion nativa AOT (-m aot): bare|embed|full (default "
"bare).",
cxxopts::value<std::string>()->default_value("bare"))(
"freestanding",
"AOT bare sin libc (kernels/bootloaders): RAW_ALLOC/FREE/PANIC "
"requieren hooks @AllocatorOverride/@PanicHandler.")(
"no-exceptions",
"AOT (-m aot): DESACTIVA el mecanismo de excepciones nativo "
"(setjmp/longjmp). Un try/catch/throw da error. Para "
"kernels/freestanding sin runtime de excepciones.")(
"no-io",
"AOT (-m aot): NO auto-incluye el runtime de I/O "
"(stdlib/vx/vx_io.vx). El usuario aporta __vx_write y los "
"__vx_print_* (p.ej. enlazar vesta_io_bare.o, o freestanding).")(
"no-mem",
"AOT (-m aot): NO auto-incluye el slab allocator "
"(stdlib/vx/vx_mem.vx). El allocator usa libc malloc/free (o el "
"@AllocatorOverride del usuario).")(
"format",
"Formato del ejecutable AOT (-m aot): pe|elf (default: PE en "
"Windows, ELF en el resto).",
cxxopts::value<std::string>())(
"no-pie", "AOT: refs a datos absolutas (mov reg,imm64; requiere "
"base de imagen fija) en vez de RIP-relativas (default, "
"position-independent), analogo a gcc/clang -no-pie.")(
"emit",
"AOT: tipo de artefacto: exe (ejecutable standalone, default) | "
"obj (objeto relocatable linkable: ELF .o o COFF .obj segun "
"--format) | shared (libreria compartida ELF .so que exporta sus "
"funciones; dlopen/dlsym) | bin (binario plano sin cabecera: "
"bootloader/ROM/firmware, entry en offset 0).",
cxxopts::value<std::string>())(
"bin-base",
"AOT --emit bin: base de carga del binario plano (hex, e.g. "
"0x7C00); afecta solo a refs absolutas (--no-pie). Default 0.",
cxxopts::value<std::string>())(
"aot-arch",
"AOT: arquitectura objetivo: x86-64 (default) | x86-32 (modo "
"protegido, kernels: 8 GP eax-edi, regparm(3), subset entero de "
"32-bit).",
cxxopts::value<std::string>()->default_value("x86-64"))(
"float-isa",
"AOT: backend de punto flotante / ancho SIMD del vectorizador: "
"sse2 (default, 128b, corre en CUALQUIER x86-64) | x87 (legacy) | "
"avx (AVX2 256b, requiere AVX2 en la CPU) | avx512f (512b, requiere "
"AVX-512) | auto (multiversion: emite las 3 variantes y elige la "
"optima en runtime por CPUID; lo mejor para distribuir un solo "
"binario). Nota: un binario avx/avx512f FIJO da SIGILL en una CPU "
"sin ese soporte; usa auto para portabilidad.",
cxxopts::value<std::string>()->default_value("sse2"))(
"vx-base",
"VA base address para el modulo (hex, e.g. 0x10000000). Usado para "
"plugins cargados via loadmodule, evita solapamiento con el caller "
"(default 0x0).",
cxxopts::value<std::string>()->default_value("0x0"))
// Phase M.sandbox: restringe las capabilities del modulo
// principal al subset listado. Default vacio = ALL granted
// (zero overhead, backward compat). Sintaxis: 'fs:read,net,
// ffi:call=kernel32.dll;user32.dll' etc. Ver include/loader/
// sandbox.h para tabla completa de caps + sintaxis.
("vx-caps",
"Phase M.sandbox: restringe caps del modulo principal. Sintaxis: "
"'fs:read,net,ffi:call=kernel32.dll;user32.dll'. Vacio = ALL granted "
"(default). 'none' = sandbox total.",
cxxopts::value<std::string>()->default_value(""))
// Diagramas para debug y traceo del pipeline Vesta. Tres formatos
// seleccionables via --diagram-format:
// mermaid (default): escribe .mmd con bloque ```mermaid```;
// listo para VS Code / GitHub / mermaid.live.
// graphviz: escribe .dot con `digraph G { ... }`;
// listo para `dot -Tsvg foo.dot -o foo.svg`.
// html: escribe .html interactivo AUTOCONTENIDO
// (CSS+JS embebidos, sin CDN): pan/zoom, panel
// de detalle por nodo, busqueda, filtros de
// aristas. Se abre directo en el navegador.
// both: mermaid + graphviz. all: los tres.
// El contenido es paralelo entre formatos: misma topologia, misma
// info por nodo (Graphviz/HTML llevan extra via tooltips/detalle).
// --diagram-all genera las 4 vistas (AST, IR pre, IR post, VEL)
// en el formato escogido.
("diagram-vx",
"Generar diagrama del AST Vesta post type-check (.ast.<ext>)")(
"diagram-ir",
"Generar diagrama del SSA IR pre-optimizacion (.ir.pre.<ext>)")(
"diagram-ir-opt",
"Generar diagrama del SSA IR post-optimizacion (.ir.post.<ext>)")(
"diagram-vel",
"Generar diagrama del bytecode .vel final (.vel.<ext>)")(
"diagram-all", "Generar las 4 vistas (vx, ir pre, ir post, vel) "
"con sufijos correspondientes")(
"diagram-format",
"Formato: mermaid | graphviz | html | both | all (default: "
"mermaid). html produce paginas interactivas autocontenidas "
"(.html); both=mermaid+graphviz; all=los tres.",
cxxopts::value<std::string>()->default_value("mermaid"))(
"diagram-cost",
"Anotar cada nodo-funcion de los diagramas IR (pre y post) con su "
"coste Big-O (parcial + total) calculado por analyze::bigo. Aplica "
"a --diagram-ir / --diagram-ir-opt / --diagram-all.")(
"gc-debug",
"Activar trazas de debug del Garbage Collector a stderr (minor_gc, "
"major_gc, sweep, release_handle, evacuate). Util para "
"diagnosticar use-after-free o objetos colectados prematuramente. "
"Alt: env VESTA_GC_DEBUG=1.")(
"gc-debug-buffered",
"Activar modo BUFFERED del GC debug: ~100x mas rapido (buffer "
"thread-local de 64KB) pero pierde las ultimas trazas en crash. "
"Implica --gc-debug. Alt: env VESTA_GC_DEBUG_BUFFERED=1.")(
"debug-port",
"Activar el servidor de depuracion TCP en el puerto N (default "
"9229 si N=0). Soporta multiples clientes simultaneos y JSON via "
"length-prefix framing. El servidor permanece disponible mientras "
"la VM ejecuta; los clientes (e.g. tools/dbg_client.vsh) se "
"conectan via tcp_connect, envian comandos JSON y reciben eventos "
"asincronos (break/exit/exception/spawned). Sin este flag, el "
"debugger NO se instancia y el coste runtime es exactamente cero. "
"Cuando esta presente, el proceso main arranca PAUSADO en su "
"primera instruccion para dar tiempo al cliente a conectarse y "
"poner breakpoints; el cliente debe enviar 'continue 0' para "
"arrancar la ejecucion.",
cxxopts::value<uint16_t>()->default_value("0"))(
"server-mode",
"Iniciar la VM como un servidor persistente de depuracion. Implica "
"--debug-port (default 9229). No requiere --run: la VM se queda "
"viva esperando comandos del debugger para cargar/ejecutar/matar "
"procesos remotamente. Compatible con --schedulers, --dist-port, "
"etc. Termina con SIGINT (Ctrl+C) o con el comando "
"'server_shutdown' del cliente. Comandos disponibles: load_velb, "
"load_velb_bytes, kill_proc, server_info, server_shutdown, "
"auth_login/logout/whoami, "
"auth_create_user/delete_user/list_users/change_pass, "
"fs_read/write/list/stat/delete/mkdir/rename.")(
"server-port",
"Puerto del servidor persistente (sinonimo de --debug-port en modo "
"--server-mode). Default 9229.",
cxxopts::value<uint16_t>()->default_value("0"))(
"server-root",
"Directorio raiz del sandbox de filesystem en modo --server-mode. "
"Todas las rutas usadas por fs_* y load_velb se resuelven contra "
"este directorio; cualquier intento de salir (con '..' o rutas "
"absolutas) se rechaza. Sin este flag NO hay sandbox (modo "
"back-compat: cualquier ruta absoluta del servidor es accesible). "
"Recomendado en despliegues compartidos.",
cxxopts::value<std::string>()->default_value(""))(
"auth-db",
"Ruta al fichero SQLite con la tabla vm_users (usuarios, hashes "
"PBKDF2 y roles) en modo --server-mode. Sin este flag la "
"autenticacion esta desactivada y cualquier cliente puede invocar "
"cualquier comando (modo desarrollo).",
cxxopts::value<std::string>()->default_value(""))(
"admin-user",
"Nombre del usuario admin a crear automaticamente cuando la base "
"de datos --auth-db esta vacia. Default 'admin'.",
cxxopts::value<std::string>()->default_value("admin"))(
"admin-password",
"Contrasenya del usuario admin a crear automaticamente. Si se "
"omite y --auth-db apunta a una BD vacia, se genera una "
"contrasenya aleatoria de 24 caracteres y se imprime en stdout UNA "
"UNICA VEZ.",
cxxopts::value<std::string>()->default_value(""))(
"no-repl",
"Desactivar el REPL interactivo local en modo --server-mode (modo "
"headless). Sin este flag, el operador local mantiene un prompt "
"vesta> que comparte el mismo runtime con los clientes remotos; "
"con el, el proceso solo escucha el socket TCP.")(
"vx-debug",
"Emitir comentarios `// @line N` en el .vel intermedio del "
"compilador Vesta y, cuando se integre la pipeline completa de debug "
"section (Phase 2), embeber la tabla bytecode_offset -> (file, "
"line) en el .velb final. Sin este flag, el .vel/.velb no "
"contienen info de debug -> el ejecutable es mas pequeno y el "
"frontend NO genera datos extra. Con el flag, el cliente del "
"debugger puede setear breakpoints por linea Vesta (`b file.vx:42`) "
"en lugar de solo por addr.")(
"port",
"Transpilar el IR a codigo fuente del lenguaje destino y escribir "
"a <output>.<ext> (e.g. .c). Valores actuales: 'c'. Futuro: "
"'java', 'js', 'rust'. Con --port=c se genera codigo C99 portable "
"listo para compilar con gcc/clang -O3 -std=c11 SIN dependencias "
"de VestaVM (a menos que --port-gc=vesta). Implica --vx (se "
"aplica al pipeline Vesta post-optimizacion).",
cxxopts::value<std::string>())(
"emit-header",
"Generar el header C publico del modulo (<output>.h): typedefs de "
"los structs C-compatibles + prototipos de las funciones con firma "
"C-representable + punteros a funcion cfn. Pensado junto a --port "
"c: el .c lleva las definiciones y el .h las declaraciones, listo "
"para que un programa C incluya el .h y enlace el .c.")(
"port-gc",
"Modelo de memoria del codigo portado: none|vesta|boehm. none "
"(default): malloc/free + sin GC. Las IR ops de objetos GC "
"(NEWOBJ/strings) emiten stub. vesta: enlazar contra "
"vesta_rt.lib. boehm: enlazar contra libgc (placeholder).",
cxxopts::value<std::string>()->default_value("none"))(
"port-exc",
"Manejo de excepciones del codigo portado: none|setjmp|returncode. "
" none: throw -> abort. setjmp (default): longjmp portable. "
"returncode: codigo de retorno + propagacion explicita (no impl "
"v1).",
cxxopts::value<std::string>()->default_value("setjmp"))(
"port-types",
"Estilo de tipos del codigo portado: stdint (default) usa "
"int8_t/uint64_t/etc de stdint.h. builtin usa char/int/long del C "
"clasico (menos portable).",
cxxopts::value<std::string>()->default_value("stdint"))(
"port-strings",
"Modelo de strings: raw (const char* solo literales) | managed "
"(default: VxString con tracking per-thread).",
cxxopts::value<std::string>()->default_value("managed"))(
"port-freestanding",
"Generar C freestanding (sin includes automaticos de "
"stdio/stdlib/math). El usuario debe proveer vx_throw + "
"vx_panic_with_str. Para bootloaders, kernels, firmware.")(
"port-stdlib-dir",
"Path al directorio stdlib/port/c con los snippets .v.c "
"(autodetect si vacio).",
cxxopts::value<std::string>()->default_value(""))(
"port-arch",
"Target CPU: '' (portable, default) | native | x86-64-v2 | "
"x86-64-v3 | x86-64-v4. Emite #pragma GCC target con flags "
"agresivas (AVX2/FMA/BMI2 segun nivel).",
cxxopts::value<std::string>()->default_value(""))(
"port-no-aggressive",
"Desactivar atributos agresivos (const/cold/restrict/always_inline "
"+ __builtin_expect/unreachable). Default: activado.")(
"instrument",
"Instrumentacion en el IR Vesta (heredada por bytecode VM, JIT, port "
"C, port futuros): none (default) | trace (calls a "
"vx_trace:enter/exit por funcion) | profile (timing per-funcion).",
cxxopts::value<std::string>()->default_value("none"))
#ifdef VESTA_HAS_PREPROCESSOR
("preprocess-only",
"Solo preprocesar un .vel y mostrar/guardar el resultado (debug)",
cxxopts::value<std::string>())
#endif
("keep-labels",
"Mantener los nombres de label en el .velb (por defecto se "
"eliminan: el loader no los usa y reducen ~9% el tamano)")(
"emit-map", "Generar archivo .velb-map con info de "
"simbolos y secciones (debug). Off por "
"defecto: cuesta ~60% del tiempo del linker")
// Phase M.L28: firmas digitales del .velb.
("sign-velb",
"Firmar un .velb con clave privada PEM. Uso: --sign-velb input.velb "
"--sign-key priv.pem -o output.signed.velb",
cxxopts::value<std::string>())(
"sign-key", "Path al PEM con la clave privada para --sign-velb",
cxxopts::value<std::string>())(
"verify-velb",
"Verificar la firma digital de un .velb. Uso: --verify-velb "
"file.velb --verify-key pub.pem",
cxxopts::value<std::string>())(
"verify-key", "Path al PEM con la clave publica para --verify-velb",
cxxopts::value<std::string>())
// Phase AOT.5: linker propio (enlaza .o sin ld/gcc).
("link",
"Phase AOT.5: enlaza objetos relocatables (ELF64 o COFF AMD64, "
"auto-detectados; los de --emit obj o de gcc/MSVC) en un ejecutable "
"nativo SIN ld/gcc. Uso: vm --link a.o b.o [lib.a] [lib.dll] -o prog "
"[--format elf|pe] [--entry sym] [--link-base 0xADDR]. Con --entry usa "
"ese simbolo como entrada SIN stub (kernel/bootloader); sin el, "
"sintetiza _start->main (ejecutable hosted).")
// Phase AOT.5: archivador propio (crea .a sin el ar del sistema).
("ar",
"Phase AOT.5: crea una libreria estatica .a (formato ar GNU, con "
"indice de simbolos) a partir de objetos, SIN el ar del sistema. Uso: "
"vm --ar libfoo.a a.o b.o ... El .a lo consume nuestro linker (--link) "
"y tambien ar/ld/gcc.")(
"entry",
"Con --link: simbolo de entrada del ejecutable (e.g. _kstart). "
"Vacio => _start sintetico que llama a main.",
cxxopts::value<std::string>()->default_value(""))(
"link-base",
"Con --link: base de carga del ejecutable (hex, e.g. 0x100000 para "
"un kernel). Default segun el formato.",
cxxopts::value<std::string>()->default_value(""))(
"link-script",
"Con --link: script de enlace ESCRITO EN VESTA (un .vx con 'fn "
"link()' que llama a builtins base/entry/stack/section/"
"section_size/align_up/debug_build). El linker lo compila y ejecuta "
"para leer la configuracion. Los CLI --link-base/--entry tienen "
"prioridad sobre el script.",
cxxopts::value<std::string>()->default_value(""))(
"link-debug",
"Con --link --link-script: hace que el builtin debug_build() del "
"script devuelva true.",
cxxopts::value<bool>()->default_value("false"))(
"sysroot",
"Con --link / --emit exe (ELF): raiz donde buscar las librerias del "
"sistema (libc.so.6) al cross-compilar ELF desde otro SO. En Linux "
"nativo no hace falta.",
cxxopts::value<std::string>()->default_value(""));
// BUG FIX: Args posicionales y allow_unrecognised DEBEN configurarse
// ANTES de @c options.parse(...). El bug anterior registraba el
// option `positional` y @c parse_positional DESPUES del parse, asi
// que cualquier `vm --script foo.vsh arg1 arg2` perdia arg1/arg2 y
// ARGV del script quedaba con solo el path del script. Se mueve
// toda la configuracion arriba; esto es prerequisito de @c parse.
options.add_options()("positional", "Argumentos posicionales",
cxxopts::value<std::vector<std::string>>());
options.parse_positional({"positional"});
options.positional_help("[args...]");
options
.allow_unrecognised_options(); // para flags sin que aun hay que parsear
auto result = options.parse(argc, argv);
// activar trazas de depuracion del subsistema distribuido si se paso
// --dist-debug
if (result.count("dist-debug")) distrib::set_dist_debug(true);
// activar trazas del GC si se paso --gc-debug. Tambien respeta env
// VESTA_GC_DEBUG=1 (la inicializacion estatica corre antes de main,
// no se pierde si el flag CLI esta o no).
if (result.count("gc-debug")) gc::set_gc_debug(true);
// --gc-debug-buffered implica --gc-debug ademas de buffered mode.
if (result.count("gc-debug-buffered")) {
gc::set_gc_debug(true);
gc::set_gc_debug_buffered(true);
}
// ---- Configuracion del JIT ----
//
// Orden de prioridad (mayor primero):
// 1. --jit-threshold N (CLI explicito)
// 2. -m jit (preset = threshold 1, util para tests)
// 3. VESTA_JIT_THRESHOLD env var (default ya lazy-leida en auto_jit)
//
// --jit-warn activa el output detallado de IR ops no soportadas.
// --jit-stats imprime el snapshot final al RET de main (independiente).
/* Prioridad: --jit-threshold > -m jit/-m interp explicito > env var
* VESTA_JIT_THRESHOLD > default (UINT32_MAX = JIT off).
*
* cxxopts retorna count("mode") == 0 cuando no se paso `-m` aunque
* la opcion tenga default_value("vm"). Usamos eso para distinguir
* "el usuario eligio -m algo" vs "default; mirar env var".
*
* Importante: leer el env var ANTES del Loader para que la
* eager-compile pass se dispare con el threshold correcto. Sin esto
* el threshold se inicializa lazy en el primer maybe_compile_*, ya
* tarde para eager compile. */
// Phase AOT: modo de compilacion nativa standalone (-m aot). Se resuelve
// aqui (junto al resto de modos) y se consume en el bloque --vx mas abajo.
bool aot_mode = false;
aot::Tier aot_tier = aot::Tier::BARE;
bool aot_freestanding = result.count("freestanding") > 0;
bool aot_no_exceptions = result.count("no-exceptions") > 0;
bool aot_no_io = result.count("no-io") > 0;
bool aot_no_mem = result.count("no-mem") > 0;
{
const std::string &tname = result["target"].as<std::string>();
if (tname == "bare")
aot_tier = aot::Tier::BARE;
else if (tname == "embed")
aot_tier = aot::Tier::EMBED;
else if (tname == "full")
aot_tier = aot::Tier::FULL;
else {
std::cerr << "[aot] --target invalido: '" << tname
<< "' (usa bare|embed|full)\n";
return EXIT_FAILURE;
}
}
if (result.count("jit-threshold")) {
jit::set_jit_threshold(result["jit-threshold"].as<uint32_t>());
} else if (result.count("mode")) {
const std::string m = result["mode"].as<std::string>();
if (m == "jit") {
jit::set_jit_threshold(1);
} else if (m == "vm" || m == "interp") {
jit::set_jit_threshold(UINT32_MAX);
} else if (m == "aot") {
// Modo AOT: no se ejecuta nada en la VM; el JIT runtime queda off.
aot_mode = true;
jit::set_jit_threshold(UINT32_MAX);
// @Target target-aware: los atomos os:/arch: de @Target se evaluan
// contra el TARGET del binario AOT (cross-compile), no el host de
// build, para que las variantes por plataforma del runtime/usuario
// se seleccionen segun --format / --aot-arch.
std::string fmt_s;
if (result.count("format"))
fmt_s = result["format"].as<std::string>();
else
#if defined(_WIN32)
fmt_s = "pe";
#else
fmt_s = "elf";
#endif
const std::string arch_s =
result.count("aot-arch")
? result["aot-arch"].as<std::string>()
: std::string("x86-64");
const bool is32 = (arch_s == "x86-32" || arch_s == "x86_32" ||
arch_s == "i386");
vx::set_aot_condcomp_target(fmt_s == "pe" ? "windows" : "linux",
is32 ? "x86" : "x86_64");
}
} else {
/* Sin flags CLI explicitos -> consultar env var ahora. Lo
* hacemos via la API publica que delega en el mismo
* std::call_once que el path lazy interno, asi futuras
* inicializaciones lazy son no-op (idempotente). */
jit::init_threshold_from_env_now();
}
if (result.count("jit-warn")) {
jit::g_jit_warn_unsupported = true;
}
if (result.count("jit-disasm")) {
jit::g_jit_disasm = true;
}
/* Sprint D.6 (2026-06-03): activar profile counters runtime. El
* --profile [path] inicializa el collector y registra el atexit
* handler para dump automatico al finalizar el proceso. Tambien
* se respeta la env var VESTA_PROFILE_DUMP cuando el flag no esta. */
{
std::string profile_path;
if (result.count("profile")) {
profile_path = result["profile"].as<std::string>();
} else if (const char *env = std::getenv("VESTA_PROFILE_DUMP")) {
profile_path = env;
}
if (!profile_path.empty()) {
runtime::profile::profile_init(profile_path);
}
}
const bool jit_stats_requested = result.count("jit-stats") > 0;
/* Sprint string-perf-6: --stats o --jit-stats activan el counter MIPS
* per-block en JIT. Sin estos flags el JIT corre sin overhead de
* instrumentacion (35-50% mas rapido en hot loops con muchos bloques). */
if (result.count("stats") || jit_stats_requested) {
jit::g_jit_emit_instr_counter = true;
}
if (result.count("help")) {
vesta::scout() << options.help() << std::endl;
return 0;
}
std::string out_prefix;
if (result.count("output")) {
out_prefix = result["output"].as<std::string>();
} else {
out_prefix = result["output-prefix"].as<std::string>();
}
if (result.count("version")) {
cli::print_version_banner(std::cout);
return 0;
}
if (result.count("list-arch")) {
const ArchSupport &archs = get_available_architectures();
vesta::scout() << "Capstone supported architectures:\n";
for (auto &a : archs.capstone)
vesta::scout() << " " << a << "\n";
vesta::scout() << "Keystone supported architectures:\n";
for (auto &a : archs.keystone)
vesta::scout() << " " << a << "\n";
return 0;
}
// === Validacion temprana de combinaciones de flags ===
// Sin esto, flags incompatibles o mal escritas se ignoraban en silencio
// por el orden de dispatch. Ejemplos reales detectados:
// - `--run x.velb -m aot --emit exe --format exe`: el dispatch de --run
// ganaba y ejecutaba el .velb, ignorando -m aot/--emit/--format.
// - `--vx x.vx --emit exe` (sin -m aot): --emit se ignoraba en silencio.
// Falla cerrado con mensaje claro en vez de hacer algo distinto a lo pedido.
{
// (1) Acciones primarias mutuamente excluyentes: solo una a la vez.
static const char *const kPrimaryActions[] = {
"run", "worker", "driver", "build",
"vesta", "vx", "asm-file", "disasm-file", "script"};
std::vector<std::string> present;
for (const char *a : kPrimaryActions)
if (result.count(a)) present.emplace_back(std::string("--") + a);
if (present.size() > 1) {
std::cerr << "[cli] acciones incompatibles: ";
for (size_t i = 0; i < present.size(); ++i)
std::cerr << (i ? ", " : "") << present[i];
std::cerr << " -- elige solo una.\n";
return EXIT_FAILURE;
}
// (2) -m aot solo tiene sentido compilando un .vx a binario nativo.
if (aot_mode && !result.count("vesta") && !result.count("vx")) {
std::cerr << "[cli] -m aot requiere --vesta <archivo.vx> "
"(compilacion nativa desde fuente Vesta).\n";
if (result.count("run"))
std::cerr << "[cli] nota: --run ejecuta un .velb en la VM; "
"es incompatible con -m aot.\n";
return EXIT_FAILURE;
}
// (3) --emit / --format solo aplican a la compilacion AOT (-m aot) o,
// en el caso de --format, al linker propio (--link). Fuera de esos
// contextos se ignoraban sin avisar.
const bool link_mode = result.count("link") > 0;
if (result.count("emit") && !aot_mode) {
std::cerr << "[cli] --emit solo aplica con -m aot "
"(compilacion nativa standalone).\n";
return EXIT_FAILURE;
}
if (result.count("format") && !aot_mode && !link_mode) {
std::cerr << "[cli] --format solo aplica con -m aot o --link.\n";
return EXIT_FAILURE;
}
}
// Phase M.L28: firmas digitales del .velb (independientes del flujo
// de compile / run / etc.). Ambos comandos retornan al usuario al
// terminar; no continuan al resto del flow.
if (result.count("sign-velb")) {
const std::string in_path = result["sign-velb"].as<std::string>();
if (!result.count("sign-key")) {
std::cerr << "error: --sign-velb requiere --sign-key <priv.pem>\n";
return EXIT_FAILURE;
}
const std::string key_path = result["sign-key"].as<std::string>();
const std::string out_path = result.count("output")
? result["output"].as<std::string>()
: (in_path + ".signed");
std::ifstream f(in_path, std::ios::binary | std::ios::ate);
if (!f) {
std::cerr << "error: no se puede abrir " << in_path << "\n";
return EXIT_FAILURE;
}
const std::streamsize sz = f.tellg();
f.seekg(0, std::ios::beg);
std::vector<uint8_t> bytes(static_cast<size_t>(sz < 0 ? 0 : sz));
if (sz > 0) f.read(reinterpret_cast<char *>(bytes.data()), sz);
f.close();
std::vector<uint8_t> signed_bytes;
std::string err;
if (!vx::velb_sign(bytes, key_path, vx::VsigAlgo::RSA_SHA256,
signed_bytes, err)) {
std::cerr << "error: " << err << "\n";
return EXIT_FAILURE;
}
std::ofstream of(out_path, std::ios::binary);
if (!of) {
std::cerr << "error: no se puede escribir " << out_path << "\n";
return EXIT_FAILURE;
}
of.write(reinterpret_cast<const char *>(signed_bytes.data()),
static_cast<std::streamsize>(signed_bytes.size()));
std::cerr << "[sign] " << in_path << " (" << bytes.size() << " B) -> "
<< out_path << " (" << signed_bytes.size() << " B, +"
<< (signed_bytes.size() - bytes.size())
<< " B footer VSIG)\n";
return EXIT_SUCCESS;
}
if (result.count("verify-velb")) {
const std::string in_path = result["verify-velb"].as<std::string>();
if (!result.count("verify-key")) {
std::cerr
<< "error: --verify-velb requiere --verify-key <pub.pem>\n";
return EXIT_FAILURE;
}
const std::string key_path = result["verify-key"].as<std::string>();
std::ifstream f(in_path, std::ios::binary | std::ios::ate);
if (!f) {
std::cerr << "error: no se puede abrir " << in_path << "\n";
return EXIT_FAILURE;
}
const std::streamsize sz = f.tellg();
f.seekg(0, std::ios::beg);
std::vector<uint8_t> bytes(static_cast<size_t>(sz < 0 ? 0 : sz));
if (sz > 0) f.read(reinterpret_cast<char *>(bytes.data()), sz);
f.close();
auto vr = vx::velb_verify_signature(bytes, key_path);
if (vr.ok) {
std::cerr << "[verify] " << in_path << ": firma VALIDA\n";
return EXIT_SUCCESS;
}
std::cerr << "[verify] " << in_path << ": " << vr.error << "\n";
return EXIT_FAILURE;
}
// Phase AOT.5: linker propio -- enlaza objetos .o en un ejecutable nativo
// sin depender de ld/gcc. Uso: vm --link a.o b.o -o prog [--format elf]
// [--entry sym] [--link-base 0xADDR].
if (result.count("ar")) {
// Archivador propio: vm --ar libfoo.a a.o b.o ... (primer posicional =
// .a de salida; resto = objetos), o -o libfoo.a + posicionales objetos.
std::vector<std::string> pos;
if (result.count("positional"))
pos = result["positional"].as<std::vector<std::string>>();
std::string ar_out =
result.count("output") ? result["output"].as<std::string>() : "";
std::vector<std::string> ar_objs;
if (!ar_out.empty()) {
ar_objs = pos; // -o fijo la salida; los posicionales son objetos
} else if (!pos.empty()) {
ar_out = pos.front(); // primer posicional = salida
ar_objs.assign(pos.begin() + 1, pos.end());
}
if (ar_out.empty() || ar_objs.empty()) {
std::cerr << "error: --ar requiere la libreria de salida y al menos "
"un objeto (vm --ar libfoo.a a.o [b.o ...])\n";
return EXIT_FAILURE;
}
std::string aerr;
if (!aot::aot_ar_create(ar_out, ar_objs, aerr)) {
std::cerr << "[ar] error: " << aerr << "\n";
return EXIT_FAILURE;
}
std::cerr << "[ar] '" << ar_out << "' creado (" << ar_objs.size()
<< " objeto(s)).\n";
return EXIT_SUCCESS;
}
if (result.count("link")) {
std::vector<std::string> inputs;
if (result.count("positional"))