linux - significa - stray 302 in program arduino español
Función "Hello World" sin usar C printf (3)
ACTUALIZADO
Es mi segundo día trabajando con NASM
. Después de entender esto a fondo
section .programFlow
global _start
_start:
mov edx,len
mov ecx,msg
mov ebx,0x1 ;select STDOUT stream
mov eax,0x4 ;select SYS_WRITE call
int 0x80 ;invoke SYS_WRITE
mov ebx,0x0 ;select EXIT_CODE_0
mov eax,0x1 ;select SYS_EXIT call
int 0x80 ;invoke SYS_EXIT
section .programData
msg: db "Hello World!",0xa
len: equ $ - msg
Quería envolver todo esto dentro de una función de ensamblaje. Todos (o la mayoría de) los ejemplos en la web están usando extern
y llamando a la función printf
de C
(ver el código a continuación), y no quiero eso. Quiero aprender a crear una función "Hello World" en el ensamblaje sin usar C
printf
(o incluso otras llamadas a funciones externas).
global _main
extern _printf
section .text
_main:
push message
call _printf
add esp, 4
ret
section .data
message: db "Hello, World", 10, 0
Actualizar
Estoy practicando ensamblar para Linux, pero como no poseo una caja Linux, estoy ejecutando mi código ensamblador aquí compile_assembly_online .
Suponiendo que quiere decir en un entorno de símbolo del sistema de Windows, escribiendo a salida estándar:
Como estos proporcionan una versión virtualizada del antiguo entorno de DOS, creo que puede usar las antiguas interrupciones de DOS para ello:
int 21, la función 9 puede dar salida a una cadena: Establezca AH en 9, DS: DX en una cadena terminada en $
y desencadenar la interrupción.
int 21, la función 2 puede generar un único carácter, por lo que puede usarlo repetidamente si necesita generar $
(o no quiere Ctrl + C y tal control). AH a 2, DL al código de carácter ASCII (I expect) y desencadenar la interrupción.
int 0x80
no funcionará en Windows o DOS simplemente porque es algo de Linux. Entonces eso es lo primero que tiene que cambiar.
En términos de hacerlo en Windows, en algún momento necesitará llamar a una función API de Windows, como (en este caso) WriteConsole()
. Eso es pasar por alto la biblioteca C como se desee.
Utiliza el sistema operativo para hacer el trabajo pesado para obtener resultados en la "pantalla", pero es lo mismo que int 0x80
y probablemente sea necesario ya sea Linux, Windows o DOS.
Si es un DOS original, su mejor lugar para comenzar es la excelente lista de interrupciones de Ralf Brown , específicamente Int21 / Fn9 .
Quiero señalar que Nasm "sabe" ciertos nombres de sección - ".text", ".data" y ".bss" (un par de otros que aún no necesita). El líder ''.'' es obligatorio, y los nombres son sensibles a mayúsculas y minúsculas. Usar otros nombres, como lo ha hecho en su primer ejemplo, puede "funcionar", pero puede que no le brinde los "atributos" que desea. Por ejemplo, la sección .programData is going to be read-only. Since you don''t try to write to it this isn''t going to do any harm... but
is going to be read-only. Since you don''t try to write to it this isn''t going to do any harm... but
se supone que la sección .data` puede escribirse.
Intentar aprender asm para Linux sin poder probarlo debe ser difícil. Tal vez ese sitio en línea es suficiente para ti. Hay una cosa llamada "andlinux" (creo) que te permitirá ejecutar programas de Linux en Windows. O podría ejecutar Linux en una "máquina virtual". O puede crear una partición en una de sus muchas unidades de repuesto e instalar Linux.
Para DOS, hay DosBox ... o puede instalar "DOS real" en una de esas particiones adicionales. Desde allí, puede escribir "directo a la pantalla" en B800h: xxxx. (un byte para "personaje" y el siguiente para "color"). Si desea hacer esto "sin ayuda del SO", puede ser lo que desee. En un SO de modo protegido, olvídalo. ¡Están protegidos de los Estados Unidos!
Tal vez solo quiera saber cómo escribir una subrutina, en general. Podríamos escribir una subrutina con "msg" y "len" codificados en ella, no muy flexibles. O podríamos escribir una subrutina que tome dos parámetros, ya sea en los registros o en la pila. O podríamos escribir una subrutina que espera una cadena terminada en cero (printf hace, sys_write no) y calcular la longitud para poner en edx
. Si eso es lo que necesita ayuda, nos hemos distraído hablando de int 80h
vs int 21h
vs WriteFile
. Es posible que deba preguntar de nuevo ...
EDITAR: Bien, una subrutina. La parte no obvia de esto es que call
pone la dirección de retorno (la dirección de la instrucción justo después de la llamada) en la pila, y ret
obtiene la dirección para regresar a la pila, por lo que no queremos modificar dónde ss:sp
puntos ss:sp
en el medio. Podemos cambiarlo, pero tenemos que volver a colocarlo donde estaba antes de llegar al ret
.
; purpose: to demonstrate a subroutine
; assemble with: nasm -f bin -o myfile.com myfile.asm
; (for DOS)
; Nasm defaults to 16-bit code in "-f bin" mode
; but it won''t hurt to make it clear
bits 16
; this does not "cause" our code to be loaded
; at 100h (256 decimal), but informs Nasm that
; this is where DOS will load a .com file
; (needed to calculate the address of "msg", etc.)
org 100h
; we can put our data after the code
; or we can jump over it
; we do not want to execute it!
; this will cause Nasm to move it after the code
section .data
msg db "Hello, World!", 13, 10, "$"
msg2 db "Goodbye cruel world!", 13, 10, "$"
section .text
; execution starts here
mov dx, msg ; address/offset of msg
call myprint
; "ret" comes back here
; no point in a subroutine if we''re only going to do it once
mov dx, msg2
call myprint
; when we get back, do something intelligent
exit:
mov ah. 4Ch ; DOS''s exit subfunction
int 21h
; ---------------------------------------
; subroutines go here, after the exit
; we don''t want to "fall through" into ''em!
myprint:
; expects: address of a $-terminated string in dx
; returns: nothing
push ax ; don''t really need to do this
mov ah, 9 ; DOS''s print subfunction
int 21h ; do it
pop ax ; restore caller''s ax - and our stack!
ret
; end of subroutine
Eso no se ha probado, pero está sujeto a errores tipográficos y lógicos estúpidos, "debería" funcionar. Podemos hacerlo más complicado: pasar el parámetro en la pila en lugar de simplemente en dx
. Podemos proporcionar un ejemplo para Linux (la misma idea general). Sugiero tomarlo en pequeños pasos ...