Bueno, no dices específicamente, pero por tu publicación, parece que estás usando gcc y su ASM en línea con sintaxis de restricciones (otros compiladores de C tienen una sintaxis en línea muy diferente). Dicho esto, probablemente necesite utilizar AT & sintaxis de ensamblador T en lugar de Intel, ya que eso es lo que se usa con gcc.
Así que con lo anterior, vamos a ver su función write2. En primer lugar, no desea crear un marco de pila, ya que gcc lo creará, por lo que si crea uno en el código de asm, terminará con dos marcos, y las cosas probablemente se confundan. En segundo lugar, dado que gcc está diseñando el marco de pila, no puede acceder a vars con el anuncio "[ebp + offset]", no sabe cómo se distribuye. Para eso están las restricciones: usted dice qué tipo de lugar desea que gcc ponga el valor (cualquier registro, memoria, registro específico) y el uso de "% X" en el código asm. Finalmente, si utiliza registros explícitos en el código asm, debe enumerarlos en la 3ª sección (después de las restricciones de entrada) para que gcc sepa que los está utilizando. De lo contrario, podría poner un valor importante en uno de esos registros, y tú reducirías ese valor.
Así que con todo eso, su función parece write2:
void write2(char *str, int len) {
__asm__ volatile (
"movl $4, %%eax;"
"movl $1, %%ebx;"
"movl %0, %%ecx;"
"movl %1, %%edx;"
"int $0x80"
:: "g" (str), "g" (len)
: "eax", "ebx", "ecx", "edx");
}
Nota la sintaxis AT & T - src, en lugar de dest dest, src y %
antes del nombre de registro.
Ahora esto funcionará, pero es ineficiente ya que contendrá muchos movs adicionales. En general, NUNCA deberías usar instrucciones mov o registros explícitos en el código asm, ya que es mucho mejor utilizar restricciones para decir dónde quieres que las cosas y que el compilador se asegure de que estén allí. De esta manera, el optimizador probablemente puede deshacerse de la mayoría de los movs, particularmente si se enlista la función (lo que hará si especifica -O3).Convenientemente, el modelo de máquina i386 tiene limitaciones para registros específicos, por lo que en su lugar puede hacer:
void write2(char *str, int len) {
__asm__ volatile (
"movl $4, %%eax;"
"movl $1, %%ebx;"
"int $0x80"
:: "c" (str), /* c constraint tells the compiler to put str in ecx */
"d" (len) /* d constraint tells the compiler to put len in edx */
: "eax", "ebx");
}
o incluso mejor
void write2(char *str, int len) {
__asm__ volatile ("int $0x80"
:: "a" (4), "b" (1), "c" (str), "d" (len));
}
Tenga en cuenta también el uso de volatile
que se necesita para decirle al compilador que esta no se puede eliminar como muerto aunque sus salidas (de las cuales no hay) no se utilicen.
edición
Una nota final - esta función está haciendo una llamada al sistema de escritura, lo que devuelve un valor en eax - ya sea el número de bytes escritos o un código de error. Así que usted puede conseguir que con una restricción de salida:
int write2(char *str, int len) {
__asm__ ("int $0x80" : "=a" (len) : "a" (4), "b" (1), "c" (str), "d" (len));
return len;
}
Con una producción real, que puede o no quiere que el volátil - no tener que permitirá que el compilador de código muerto eliminar la escritura si el valor de retorno no se usa Pero siempre revisas el valor de retorno de los errores, ¿verdad?
¿Desea pasar un parámetro de salida, junto con str, len? O ¿quiere decir que desea enviar un descriptor de archivo al que desea escribir el str? – Zimbabao
Solo quiero pasar mi puntero de cadena y mi longitud de cadena ... exactamente como se ve en el código de ensamblaje ... De modo que, utilizando solo syscall, puedo imprimir mi cadena a la salida estándar. – RodrigoCR