我使用的是linux,只是在试验nasm和gas。我可以使用wprintf和c++打印出unicode字符
#include <wchar.h>
#include <locale.h>
#include <stdio.h>
int main()
{
//printf("helloworld"); // can't do this AND wprintf in same program
setlocale(LC_ALL, "");
wprintf(L"%lc",0x307E); //prints out japanese hiragana ma ま
}
然而,我对尝试在汇编(intel和gas语法)中进行这项操作感到非常困惑。我的主要困惑是.data部分。我甚至给gcc设置了-S开关,看看他们是如何做到这一点的。他们用13个.string语句来格式化字符串,其中许多是空白字符串,每个字符都在一个单独的.string上。我读到,在nasm中,通过将字符串放在dw而不是db中,基本上可以将常规字符串变成宽字符串。所以我当然试过用.int表示气体,但效果不太好。我的意思是它会打印出额外的灰色问号。这是我当前的代码
.section .data
locale:
.string ""
printformat:
.int '%','l','c'
printwide:
.int 0x307E,0
.section .text
.global _start
_start:
movq $locale,%rsi
movq $6,%rdi
call setlocale
movq $printformat,%rdi
movq $printwide,%rsi
movq $0,%rax
call wprintf
movq $2,%rdi
call exit
这导致5个灰色的问号,然后是平假名ま(ma)。你可能会认为在"%"、"l"、"c"之后应该有一个,0,但这不起作用——这样做之后只会输出问号。我能够打印出平假名ma而不打问号的唯一方法是跳过格式字符串,将printwide加载到rdi中。
同样,目前这是出于教育目的。所以基本上,如何在&t语法和intel?在c++中,你只需在它前面加一个L。(是的,我想你可以把%lc改成十六进制,但我不想那样做)
EDIT这是有效的(我把$printwide改成了printwide,把printformat:改成了.strings,就像gcc-S清单一样。)但是为什么它有效呢?除了使用这么多.string语句之外,还有更好的方法来写格式吗?在intel语法中,你会怎么做?
.section .data
locale:
.string ""
printformat:
.string "%"
.string ""
.string ""
.string "l"
.string ""
.string ""
.string "c"
.string ""
.string ""
.string ""
.string ""
.string ""
.string ""
printwide:
.word 0x307E
.section .text
.global _start
_start:
movq $locale,%rsi
movq $6,%rdi
call setlocale
movq $printformat,%rdi
movq printwide,%rsi
movq $0,%rax
call wprintf
movq $2,%rdi
call exit
我对这个答案感到惊讶。我猜64位宽的字符是32位的。我是通过阅读nasm发现这一点的。您可以通过以下在intel语法中生成字符串utf-16
printformat dw __utf16__("%lc"),0
然而,它只有在我做时才起作用
printformat dd __utf32__("%lc"),0
因此at&t语法为
.long '%','l','c',0
我想gcc-S的列表使用了这么多字符串,使其成为32位宽的
.string"%"=16位(%和自动零),然后用空字符串再加8位,然后用另一个空字符串再加8位。